commit
be60973a30
495
api/next.pb.txt
495
api/next.pb.txt
@ -928,6 +928,13 @@ file {
|
||||
}
|
||||
json_name: "extensions"
|
||||
}
|
||||
field {
|
||||
name: "sandbox"
|
||||
number: 11
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandbox"
|
||||
}
|
||||
nested_type {
|
||||
name: "LabelsEntry"
|
||||
field {
|
||||
@ -2929,6 +2936,494 @@ file {
|
||||
}
|
||||
syntax: "proto3"
|
||||
}
|
||||
file {
|
||||
name: "github.com/containerd/containerd/api/types/sandbox.proto"
|
||||
package: "containerd.types"
|
||||
dependency: "gogoproto/gogo.proto"
|
||||
dependency: "google/protobuf/any.proto"
|
||||
dependency: "google/protobuf/timestamp.proto"
|
||||
message_type {
|
||||
name: "Sandbox"
|
||||
field {
|
||||
name: "sandbox_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandboxId"
|
||||
}
|
||||
field {
|
||||
name: "runtime"
|
||||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox.Runtime"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "runtime"
|
||||
}
|
||||
field {
|
||||
name: "spec"
|
||||
number: 3
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".google.protobuf.Any"
|
||||
json_name: "spec"
|
||||
}
|
||||
field {
|
||||
name: "labels"
|
||||
number: 4
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox.LabelsEntry"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "labels"
|
||||
}
|
||||
field {
|
||||
name: "created_at"
|
||||
number: 5
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".google.protobuf.Timestamp"
|
||||
options {
|
||||
65010: 1
|
||||
65001: 0
|
||||
}
|
||||
json_name: "createdAt"
|
||||
}
|
||||
field {
|
||||
name: "updated_at"
|
||||
number: 6
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".google.protobuf.Timestamp"
|
||||
options {
|
||||
65010: 1
|
||||
65001: 0
|
||||
}
|
||||
json_name: "updatedAt"
|
||||
}
|
||||
field {
|
||||
name: "extensions"
|
||||
number: 7
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox.ExtensionsEntry"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "extensions"
|
||||
}
|
||||
nested_type {
|
||||
name: "Runtime"
|
||||
field {
|
||||
name: "name"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "name"
|
||||
}
|
||||
field {
|
||||
name: "options"
|
||||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".google.protobuf.Any"
|
||||
json_name: "options"
|
||||
}
|
||||
}
|
||||
nested_type {
|
||||
name: "LabelsEntry"
|
||||
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
|
||||
}
|
||||
}
|
||||
nested_type {
|
||||
name: "ExtensionsEntry"
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
options {
|
||||
go_package: "github.com/containerd/containerd/api/types;types"
|
||||
}
|
||||
weak_dependency: 0
|
||||
syntax: "proto3"
|
||||
}
|
||||
file {
|
||||
name: "github.com/containerd/containerd/api/services/sandbox/v1/sandbox.proto"
|
||||
package: "containerd.services.sandbox.v1"
|
||||
dependency: "google/protobuf/any.proto"
|
||||
dependency: "google/protobuf/timestamp.proto"
|
||||
dependency: "gogoproto/gogo.proto"
|
||||
dependency: "github.com/containerd/containerd/api/types/sandbox.proto"
|
||||
dependency: "github.com/containerd/containerd/api/types/mount.proto"
|
||||
message_type {
|
||||
name: "StoreCreateRequest"
|
||||
field {
|
||||
name: "sandbox"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "sandbox"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "StoreCreateResponse"
|
||||
field {
|
||||
name: "sandbox"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "sandbox"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "StoreUpdateRequest"
|
||||
field {
|
||||
name: "sandbox"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "sandbox"
|
||||
}
|
||||
field {
|
||||
name: "fields"
|
||||
number: 2
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_STRING
|
||||
json_name: "fields"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "StoreUpdateResponse"
|
||||
field {
|
||||
name: "sandbox"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "sandbox"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "StoreDeleteRequest"
|
||||
field {
|
||||
name: "sandbox_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandboxId"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "StoreDeleteResponse"
|
||||
}
|
||||
message_type {
|
||||
name: "StoreListRequest"
|
||||
field {
|
||||
name: "filters"
|
||||
number: 1
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_STRING
|
||||
json_name: "filters"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "StoreListResponse"
|
||||
field {
|
||||
name: "list"
|
||||
number: 1
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "list"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "StoreGetRequest"
|
||||
field {
|
||||
name: "sandbox_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandboxId"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "StoreGetResponse"
|
||||
field {
|
||||
name: "sandbox"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Sandbox"
|
||||
json_name: "sandbox"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ControllerStartRequest"
|
||||
field {
|
||||
name: "sandbox_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandboxId"
|
||||
}
|
||||
field {
|
||||
name: "rootfs"
|
||||
number: 2
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".containerd.types.Mount"
|
||||
json_name: "rootfs"
|
||||
}
|
||||
field {
|
||||
name: "options"
|
||||
number: 3
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".google.protobuf.Any"
|
||||
json_name: "options"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ControllerStartResponse"
|
||||
field {
|
||||
name: "sandbox_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandboxId"
|
||||
}
|
||||
field {
|
||||
name: "pid"
|
||||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT32
|
||||
json_name: "pid"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ControllerShutdownRequest"
|
||||
field {
|
||||
name: "sandbox_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandboxId"
|
||||
}
|
||||
field {
|
||||
name: "timeout_secs"
|
||||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT32
|
||||
json_name: "timeoutSecs"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ControllerShutdownResponse"
|
||||
}
|
||||
message_type {
|
||||
name: "ControllerWaitRequest"
|
||||
field {
|
||||
name: "sandbox_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandboxId"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ControllerWaitResponse"
|
||||
field {
|
||||
name: "exit_status"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT32
|
||||
json_name: "exitStatus"
|
||||
}
|
||||
field {
|
||||
name: "exited_at"
|
||||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".google.protobuf.Timestamp"
|
||||
options {
|
||||
65010: 1
|
||||
65001: 0
|
||||
}
|
||||
json_name: "exitedAt"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ControllerStatusRequest"
|
||||
field {
|
||||
name: "sandbox_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "sandboxId"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ControllerStatusResponse"
|
||||
field {
|
||||
name: "id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "id"
|
||||
}
|
||||
field {
|
||||
name: "pid"
|
||||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT32
|
||||
json_name: "pid"
|
||||
}
|
||||
field {
|
||||
name: "state"
|
||||
number: 3
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "state"
|
||||
}
|
||||
field {
|
||||
name: "exit_status"
|
||||
number: 4
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT32
|
||||
json_name: "exitStatus"
|
||||
}
|
||||
field {
|
||||
name: "exited_at"
|
||||
number: 5
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".google.protobuf.Timestamp"
|
||||
options {
|
||||
65010: 1
|
||||
65001: 0
|
||||
}
|
||||
json_name: "exitedAt"
|
||||
}
|
||||
field {
|
||||
name: "extra"
|
||||
number: 6
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".google.protobuf.Any"
|
||||
json_name: "extra"
|
||||
}
|
||||
}
|
||||
service {
|
||||
name: "Store"
|
||||
method {
|
||||
name: "Create"
|
||||
input_type: ".containerd.services.sandbox.v1.StoreCreateRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.StoreCreateResponse"
|
||||
}
|
||||
method {
|
||||
name: "Update"
|
||||
input_type: ".containerd.services.sandbox.v1.StoreUpdateRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.StoreUpdateResponse"
|
||||
}
|
||||
method {
|
||||
name: "Delete"
|
||||
input_type: ".containerd.services.sandbox.v1.StoreDeleteRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.StoreDeleteResponse"
|
||||
}
|
||||
method {
|
||||
name: "List"
|
||||
input_type: ".containerd.services.sandbox.v1.StoreListRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.StoreListResponse"
|
||||
}
|
||||
method {
|
||||
name: "Get"
|
||||
input_type: ".containerd.services.sandbox.v1.StoreGetRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.StoreGetResponse"
|
||||
}
|
||||
}
|
||||
service {
|
||||
name: "Controller"
|
||||
method {
|
||||
name: "Start"
|
||||
input_type: ".containerd.services.sandbox.v1.ControllerStartRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.ControllerStartResponse"
|
||||
}
|
||||
method {
|
||||
name: "Shutdown"
|
||||
input_type: ".containerd.services.sandbox.v1.ControllerShutdownRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.ControllerShutdownResponse"
|
||||
}
|
||||
method {
|
||||
name: "Wait"
|
||||
input_type: ".containerd.services.sandbox.v1.ControllerWaitRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.ControllerWaitResponse"
|
||||
}
|
||||
method {
|
||||
name: "Status"
|
||||
input_type: ".containerd.services.sandbox.v1.ControllerStatusRequest"
|
||||
output_type: ".containerd.services.sandbox.v1.ControllerStatusResponse"
|
||||
}
|
||||
}
|
||||
options {
|
||||
go_package: "github.com/containerd/containerd/api/services/sandbox/v1;sandbox"
|
||||
}
|
||||
weak_dependency: 2
|
||||
syntax: "proto3"
|
||||
}
|
||||
file {
|
||||
name: "github.com/containerd/containerd/api/services/snapshots/v1/snapshots.proto"
|
||||
package: "containerd.services.snapshots.v1"
|
||||
|
@ -81,10 +81,12 @@ type Container struct {
|
||||
// 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]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:"-"`
|
||||
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"`
|
||||
// Sandbox ID this container belongs to.
|
||||
Sandbox string `protobuf:"bytes,11,opt,name=sandbox,proto3" json:"sandbox,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Container) Reset() { *m = Container{} }
|
||||
@ -594,58 +596,59 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_311afb8e15951042 = []byte{
|
||||
// 815 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x72, 0x12, 0x4d,
|
||||
0x14, 0xce, 0x00, 0x19, 0xc2, 0xe1, 0xaf, 0xfa, 0xff, 0xea, 0x1f, 0x71, 0x1c, 0xab, 0x80, 0xb0,
|
||||
0xa2, 0x2c, 0x1d, 0x12, 0xb4, 0xcc, 0xcd, 0x4d, 0xc8, 0xad, 0xd4, 0xc4, 0x4a, 0x4d, 0x74, 0xa3,
|
||||
0x8b, 0x38, 0x40, 0x87, 0x8c, 0xcc, 0xcd, 0xe9, 0x86, 0x92, 0x72, 0x11, 0x7d, 0x03, 0x77, 0x3e,
|
||||
0x82, 0xaf, 0x92, 0xa5, 0x4b, 0x57, 0xd1, 0x50, 0x3e, 0x88, 0x35, 0x3d, 0x3d, 0xcc, 0x84, 0x8b,
|
||||
0x42, 0x62, 0x76, 0x7d, 0xe8, 0xf3, 0x9d, 0xf3, 0xf5, 0x77, 0xfa, 0x6b, 0x06, 0x76, 0x9b, 0x3a,
|
||||
0x3d, 0x6e, 0xd7, 0x94, 0xba, 0x6d, 0x96, 0xeb, 0xb6, 0x45, 0x35, 0xdd, 0xc2, 0x6e, 0x23, 0xba,
|
||||
0xd4, 0x1c, 0xbd, 0x4c, 0xb0, 0xdb, 0xd1, 0xeb, 0x98, 0x84, 0xbf, 0x93, 0x72, 0x67, 0x31, 0x12,
|
||||
0x29, 0x8e, 0x6b, 0x53, 0x1b, 0xcd, 0x87, 0x38, 0x25, 0xc0, 0x28, 0x91, 0xac, 0xce, 0xa2, 0x9c,
|
||||
0x69, 0xda, 0x4d, 0x9b, 0x65, 0x97, 0xbd, 0x95, 0x0f, 0x94, 0x6f, 0x35, 0x6d, 0xbb, 0x69, 0xe0,
|
||||
0x32, 0x8b, 0x6a, 0xed, 0xa3, 0xb2, 0x66, 0x75, 0xf9, 0xd6, 0xed, 0xc1, 0x2d, 0x6c, 0x3a, 0x34,
|
||||
0xd8, 0x2c, 0x0c, 0x6e, 0x1e, 0xe9, 0xd8, 0x68, 0x1c, 0x9a, 0x1a, 0x69, 0xf1, 0x8c, 0xfc, 0x60,
|
||||
0x06, 0xd5, 0x4d, 0x4c, 0xa8, 0x66, 0x3a, 0x7e, 0x42, 0xf1, 0xb3, 0x08, 0xa9, 0x8d, 0x80, 0x22,
|
||||
0xca, 0x42, 0x4c, 0x6f, 0x48, 0x42, 0x41, 0x28, 0xa5, 0xaa, 0x62, 0xef, 0x2c, 0x1f, 0x7b, 0xbc,
|
||||
0xa9, 0xc6, 0xf4, 0x06, 0xda, 0x07, 0xd1, 0xd0, 0x6a, 0xd8, 0x20, 0x52, 0xac, 0x10, 0x2f, 0xa5,
|
||||
0x2b, 0xcb, 0xca, 0x1f, 0x8f, 0xaa, 0xf4, 0xab, 0x2a, 0xbb, 0x0c, 0xba, 0x65, 0x51, 0xb7, 0xab,
|
||||
0xf2, 0x3a, 0x28, 0x03, 0xb3, 0xba, 0xa9, 0x35, 0xb1, 0x14, 0xf7, 0x9a, 0xa9, 0x7e, 0x80, 0x9e,
|
||||
0x41, 0xd2, 0x6d, 0x5b, 0x1e, 0x47, 0x29, 0x51, 0x10, 0x4a, 0xe9, 0xca, 0x83, 0xa9, 0x1a, 0xa9,
|
||||
0x3e, 0x56, 0x0d, 0x8a, 0xa0, 0x12, 0x24, 0x88, 0x83, 0xeb, 0xd2, 0x2c, 0x2b, 0x96, 0x51, 0x7c,
|
||||
0x35, 0x94, 0x40, 0x0d, 0x65, 0xdd, 0xea, 0xaa, 0x2c, 0x03, 0x15, 0x20, 0x4d, 0x2c, 0xcd, 0x21,
|
||||
0xc7, 0x36, 0xa5, 0xd8, 0x95, 0x44, 0xc6, 0x2a, 0xfa, 0x13, 0x9a, 0x87, 0x7f, 0x82, 0xf0, 0xb0,
|
||||
0x85, 0xbb, 0x52, 0xf2, 0x62, 0xca, 0x53, 0xdc, 0x45, 0x1b, 0x00, 0x75, 0x17, 0x6b, 0x14, 0x37,
|
||||
0x0e, 0x35, 0x2a, 0xcd, 0xb1, 0xa6, 0xf2, 0x50, 0xd3, 0xe7, 0xc1, 0x08, 0xaa, 0x73, 0xa7, 0x67,
|
||||
0xf9, 0x99, 0x4f, 0xdf, 0xf3, 0x82, 0x9a, 0xe2, 0xb8, 0x75, 0xea, 0x15, 0x69, 0x3b, 0x8d, 0xa0,
|
||||
0x48, 0x6a, 0x9a, 0x22, 0x1c, 0xb7, 0x4e, 0x51, 0x0d, 0x00, 0xbf, 0xa3, 0xd8, 0x22, 0xba, 0x6d,
|
||||
0x11, 0x09, 0xd8, 0xd0, 0x1e, 0x4d, 0xa5, 0xe5, 0x56, 0x1f, 0xce, 0x06, 0x57, 0x4d, 0x78, 0x6d,
|
||||
0xd4, 0x48, 0x55, 0x79, 0x05, 0xd2, 0x91, 0xc9, 0xa2, 0xff, 0x20, 0xee, 0xc9, 0xc2, 0x2e, 0x8f,
|
||||
0xea, 0x2d, 0xbd, 0x19, 0x77, 0x34, 0xa3, 0x8d, 0xa5, 0x98, 0x3f, 0x63, 0x16, 0xac, 0xc6, 0x96,
|
||||
0x05, 0x79, 0x0f, 0x92, 0x7c, 0x56, 0x08, 0x41, 0xc2, 0xd2, 0x4c, 0xcc, 0x71, 0x6c, 0x8d, 0x14,
|
||||
0x48, 0xda, 0x0e, 0x65, 0xd4, 0x63, 0xbf, 0x99, 0x5c, 0x90, 0x24, 0x1f, 0xc0, 0xbf, 0x03, 0x74,
|
||||
0x47, 0xb0, 0xb9, 0x13, 0x65, 0x33, 0xae, 0x64, 0xc8, 0xb1, 0x78, 0x0f, 0xfe, 0xdf, 0xc1, 0xb4,
|
||||
0x2f, 0x88, 0x8a, 0xdf, 0xb6, 0x31, 0xa1, 0xe3, 0x2c, 0x52, 0x3c, 0x86, 0xcc, 0xc5, 0x74, 0xe2,
|
||||
0xd8, 0x16, 0xc1, 0x68, 0x1f, 0x52, 0x7d, 0x89, 0x19, 0x2c, 0x5d, 0xb9, 0x3b, 0xcd, 0x20, 0xb8,
|
||||
0xf0, 0x61, 0x91, 0xe2, 0x22, 0xdc, 0xd8, 0xd5, 0x49, 0xd8, 0x8a, 0x04, 0xd4, 0x24, 0x48, 0x1e,
|
||||
0xe9, 0x06, 0xc5, 0x2e, 0x91, 0x84, 0x42, 0xbc, 0x94, 0x52, 0x83, 0xb0, 0x68, 0x40, 0x76, 0x10,
|
||||
0xc2, 0xe9, 0xa9, 0x00, 0x61, 0x63, 0x06, 0xbb, 0x1c, 0xbf, 0x48, 0x95, 0xe2, 0x1b, 0xc8, 0x6e,
|
||||
0xb0, 0xeb, 0x3c, 0x24, 0xde, 0xdf, 0x17, 0xa3, 0x05, 0x37, 0x87, 0x7a, 0x5d, 0x9b, 0xf2, 0x5f,
|
||||
0x04, 0xc8, 0xbe, 0x60, 0x1e, 0xbb, 0xfe, 0x93, 0xa1, 0x35, 0x48, 0xfb, 0x7e, 0x66, 0xef, 0x39,
|
||||
0xbf, 0xb5, 0xc3, 0x0f, 0xc1, 0xb6, 0xf7, 0xe4, 0xef, 0x69, 0xa4, 0xa5, 0xf2, 0x67, 0xc3, 0x5b,
|
||||
0x7b, 0xb2, 0x0c, 0x11, 0xbd, 0x36, 0x59, 0x16, 0x20, 0xbb, 0x89, 0x0d, 0x3c, 0x42, 0x95, 0x71,
|
||||
0x66, 0xa9, 0x41, 0xe6, 0xc2, 0x7d, 0xdc, 0xc3, 0x84, 0x78, 0xef, 0xff, 0x93, 0x2b, 0x72, 0x8b,
|
||||
0xb0, 0xaa, 0xfc, 0x9c, 0x05, 0x08, 0x2f, 0x3c, 0xea, 0x40, 0x7c, 0x07, 0x53, 0xf4, 0x70, 0x82,
|
||||
0x72, 0x23, 0x6c, 0x2f, 0x2f, 0x4d, 0x8d, 0xe3, 0x72, 0xbf, 0x87, 0x84, 0x77, 0x54, 0x34, 0xc9,
|
||||
0x5f, 0xe6, 0x48, 0x5b, 0xcb, 0x2b, 0x97, 0x40, 0xf2, 0xe6, 0x1f, 0x05, 0x00, 0x6f, 0xeb, 0x80,
|
||||
0xba, 0x58, 0x33, 0xaf, 0xc0, 0x61, 0x69, 0x5a, 0x24, 0x9f, 0xe8, 0x82, 0x80, 0x4e, 0x40, 0xf4,
|
||||
0x1d, 0x8a, 0x26, 0x39, 0xc8, 0xe8, 0x87, 0x43, 0x5e, 0xbd, 0x0c, 0x94, 0x8b, 0x70, 0x02, 0xa2,
|
||||
0xef, 0x85, 0x89, 0x08, 0x8c, 0xf6, 0xf7, 0x44, 0x04, 0xc6, 0x39, 0xee, 0x15, 0x88, 0xbe, 0x3f,
|
||||
0x26, 0x22, 0x30, 0xda, 0x4a, 0x72, 0x76, 0xc8, 0xf9, 0x5b, 0xde, 0x97, 0x60, 0xf5, 0xf5, 0xe9,
|
||||
0x79, 0x6e, 0xe6, 0xdb, 0x79, 0x6e, 0xe6, 0x43, 0x2f, 0x27, 0x9c, 0xf6, 0x72, 0xc2, 0xd7, 0x5e,
|
||||
0x4e, 0xf8, 0xd1, 0xcb, 0x09, 0x2f, 0xb7, 0xaf, 0xf0, 0x71, 0xbb, 0x16, 0x46, 0x35, 0x91, 0x75,
|
||||
0xbc, 0xff, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x77, 0xc8, 0x5c, 0x78, 0x2d, 0x0b, 0x00, 0x00,
|
||||
// 832 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x72, 0x1a, 0x47,
|
||||
0x14, 0xd5, 0x00, 0x1a, 0xc4, 0x25, 0x55, 0x49, 0x75, 0x08, 0x99, 0x4c, 0xaa, 0x00, 0xb1, 0xa2,
|
||||
0x52, 0xc9, 0x20, 0x91, 0x54, 0xf4, 0xca, 0x46, 0xe8, 0x55, 0x49, 0xa4, 0x94, 0x6a, 0x94, 0x6c,
|
||||
0xe2, 0x85, 0x3c, 0x40, 0x0b, 0x8d, 0x99, 0x97, 0xa7, 0x1b, 0x4a, 0x94, 0x17, 0xb2, 0xff, 0xc0,
|
||||
0x7f, 0xe1, 0xb5, 0xff, 0x42, 0x4b, 0x2f, 0xbd, 0x92, 0x2d, 0xca, 0x1f, 0xe2, 0xea, 0x9e, 0x1e,
|
||||
0x66, 0xc4, 0xc3, 0x06, 0xc9, 0xda, 0xf5, 0xa5, 0xef, 0xb9, 0xf7, 0xf4, 0xb9, 0x7d, 0x7a, 0x80,
|
||||
0xc3, 0xb6, 0x49, 0xcf, 0xbb, 0x0d, 0xad, 0xe9, 0xda, 0xd5, 0xa6, 0xeb, 0x50, 0xc3, 0x74, 0xb0,
|
||||
0xdf, 0x8a, 0x2f, 0x0d, 0xcf, 0xac, 0x12, 0xec, 0xf7, 0xcc, 0x26, 0x26, 0xd1, 0xef, 0xa4, 0xda,
|
||||
0x5b, 0x8d, 0x45, 0x9a, 0xe7, 0xbb, 0xd4, 0x45, 0xcb, 0x11, 0x4e, 0x0b, 0x31, 0x5a, 0x2c, 0xab,
|
||||
0xb7, 0xaa, 0xe6, 0xda, 0x6e, 0xdb, 0xe5, 0xd9, 0x55, 0xb6, 0x0a, 0x80, 0xea, 0x0f, 0x6d, 0xd7,
|
||||
0x6d, 0x5b, 0xb8, 0xca, 0xa3, 0x46, 0xf7, 0xac, 0x6a, 0x38, 0x7d, 0xb1, 0xf5, 0xe3, 0xe8, 0x16,
|
||||
0xb6, 0x3d, 0x1a, 0x6e, 0x96, 0x46, 0x37, 0xcf, 0x4c, 0x6c, 0xb5, 0x4e, 0x6d, 0x83, 0x74, 0x44,
|
||||
0x46, 0x71, 0x34, 0x83, 0x9a, 0x36, 0x26, 0xd4, 0xb0, 0xbd, 0x20, 0xa1, 0xfc, 0x5a, 0x86, 0xcc,
|
||||
0x4e, 0x48, 0x11, 0xe5, 0x21, 0x61, 0xb6, 0x14, 0xa9, 0x24, 0x55, 0x32, 0x75, 0x79, 0x70, 0x5d,
|
||||
0x4c, 0xfc, 0xb9, 0xab, 0x27, 0xcc, 0x16, 0x3a, 0x06, 0xd9, 0x32, 0x1a, 0xd8, 0x22, 0x4a, 0xa2,
|
||||
0x94, 0xac, 0x64, 0x6b, 0xeb, 0xda, 0x67, 0x8f, 0xaa, 0x0d, 0xab, 0x6a, 0x87, 0x1c, 0xba, 0xe7,
|
||||
0x50, 0xbf, 0xaf, 0x8b, 0x3a, 0x28, 0x07, 0x8b, 0xa6, 0x6d, 0xb4, 0xb1, 0x92, 0x64, 0xcd, 0xf4,
|
||||
0x20, 0x40, 0xff, 0x40, 0xda, 0xef, 0x3a, 0x8c, 0xa3, 0x92, 0x2a, 0x49, 0x95, 0x6c, 0xed, 0xb7,
|
||||
0xb9, 0x1a, 0xe9, 0x01, 0x56, 0x0f, 0x8b, 0xa0, 0x0a, 0xa4, 0x88, 0x87, 0x9b, 0xca, 0x22, 0x2f,
|
||||
0x96, 0xd3, 0x02, 0x35, 0xb4, 0x50, 0x0d, 0x6d, 0xdb, 0xe9, 0xeb, 0x3c, 0x03, 0x95, 0x20, 0x4b,
|
||||
0x1c, 0xc3, 0x23, 0xe7, 0x2e, 0xa5, 0xd8, 0x57, 0x64, 0xce, 0x2a, 0xfe, 0x13, 0x5a, 0x86, 0xaf,
|
||||
0xc2, 0xf0, 0xb4, 0x83, 0xfb, 0x4a, 0xfa, 0x76, 0xca, 0xdf, 0xb8, 0x8f, 0x76, 0x00, 0x9a, 0x3e,
|
||||
0x36, 0x28, 0x6e, 0x9d, 0x1a, 0x54, 0x59, 0xe2, 0x4d, 0xd5, 0xb1, 0xa6, 0xff, 0x86, 0x23, 0xa8,
|
||||
0x2f, 0x5d, 0x5d, 0x17, 0x17, 0x5e, 0xbe, 0x2b, 0x4a, 0x7a, 0x46, 0xe0, 0xb6, 0x29, 0x2b, 0xd2,
|
||||
0xf5, 0x5a, 0x61, 0x91, 0xcc, 0x3c, 0x45, 0x04, 0x6e, 0x9b, 0xa2, 0x06, 0x00, 0xbe, 0xa0, 0xd8,
|
||||
0x21, 0xa6, 0xeb, 0x10, 0x05, 0xf8, 0xd0, 0xfe, 0x98, 0x4b, 0xcb, 0xbd, 0x21, 0x9c, 0x0f, 0xae,
|
||||
0x9e, 0x62, 0x6d, 0xf4, 0x58, 0x55, 0xa4, 0x40, 0x9a, 0x18, 0x4e, 0xab, 0xe1, 0x5e, 0x28, 0x59,
|
||||
0xae, 0x45, 0x18, 0xaa, 0x1b, 0x90, 0x8d, 0xcd, 0x1c, 0x7d, 0x03, 0x49, 0x26, 0x18, 0xbf, 0x56,
|
||||
0x3a, 0x5b, 0xb2, 0xe9, 0xf7, 0x0c, 0xab, 0x8b, 0x95, 0x44, 0x30, 0x7d, 0x1e, 0x6c, 0x26, 0xd6,
|
||||
0x25, 0xf5, 0x08, 0xd2, 0x62, 0x8a, 0x08, 0x41, 0xca, 0x31, 0x6c, 0x2c, 0x70, 0x7c, 0x8d, 0x34,
|
||||
0x48, 0xbb, 0x1e, 0xe5, 0x87, 0x4a, 0x7c, 0x62, 0xa6, 0x61, 0x92, 0x7a, 0x02, 0x5f, 0x8f, 0x1c,
|
||||
0x64, 0x02, 0x9b, 0x9f, 0xe2, 0x6c, 0xa6, 0x95, 0x8c, 0x38, 0x96, 0x7f, 0x81, 0x6f, 0x0f, 0x30,
|
||||
0x1d, 0x4a, 0xa5, 0xe3, 0xa7, 0x5d, 0x4c, 0xe8, 0x34, 0xf3, 0x94, 0xcf, 0x21, 0x77, 0x3b, 0x9d,
|
||||
0x78, 0xae, 0x43, 0x30, 0x3a, 0x86, 0xcc, 0x50, 0x7c, 0x0e, 0xcb, 0xd6, 0x7e, 0x9e, 0x67, 0x44,
|
||||
0x62, 0x24, 0x51, 0x91, 0xf2, 0x2a, 0x7c, 0x77, 0x68, 0x92, 0xa8, 0x15, 0x09, 0xa9, 0x29, 0x90,
|
||||
0x3e, 0x33, 0x2d, 0x8a, 0x7d, 0xa2, 0x48, 0xa5, 0x24, 0x1b, 0x95, 0x08, 0xcb, 0x16, 0xe4, 0x47,
|
||||
0x21, 0x82, 0x9e, 0x0e, 0x10, 0x35, 0xe6, 0xb0, 0xbb, 0xf1, 0x8b, 0x55, 0x29, 0x3f, 0x81, 0xfc,
|
||||
0x0e, 0xbf, 0xe8, 0x63, 0xe2, 0x7d, 0x79, 0x31, 0x3a, 0xf0, 0xfd, 0x58, 0xaf, 0x07, 0x53, 0xfe,
|
||||
0x95, 0x04, 0xf9, 0xff, 0xb8, 0xfb, 0x1e, 0xfe, 0x64, 0x68, 0x0b, 0xb2, 0x81, 0xd3, 0xf9, 0x4b,
|
||||
0x2f, 0x6e, 0xed, 0xf8, 0x13, 0xb1, 0xcf, 0x3e, 0x06, 0x47, 0x06, 0xe9, 0xe8, 0xe2, 0x41, 0x61,
|
||||
0x6b, 0x26, 0xcb, 0x18, 0xd1, 0x07, 0x93, 0x65, 0x05, 0xf2, 0xbb, 0xd8, 0xc2, 0x13, 0x54, 0x99,
|
||||
0x66, 0x96, 0x06, 0xe4, 0x6e, 0xdd, 0xc7, 0x23, 0x4c, 0x08, 0xfb, 0x32, 0xfc, 0x75, 0x4f, 0x6e,
|
||||
0x31, 0x56, 0xb5, 0x0f, 0x8b, 0x00, 0xd1, 0x85, 0x47, 0x3d, 0x48, 0x1e, 0x60, 0x8a, 0x7e, 0x9f,
|
||||
0xa1, 0xdc, 0x04, 0xdb, 0xab, 0x6b, 0x73, 0xe3, 0x84, 0xdc, 0xcf, 0x20, 0xc5, 0x8e, 0x8a, 0x66,
|
||||
0xf9, 0x98, 0x4e, 0xb4, 0xb5, 0xba, 0x71, 0x07, 0xa4, 0x68, 0xfe, 0x42, 0x02, 0x60, 0x5b, 0x27,
|
||||
0xd4, 0xc7, 0x86, 0x7d, 0x0f, 0x0e, 0x6b, 0xf3, 0x22, 0xc5, 0x44, 0x57, 0x24, 0x74, 0x09, 0x72,
|
||||
0xe0, 0x50, 0x34, 0xcb, 0x41, 0x26, 0x3f, 0x1c, 0xea, 0xe6, 0x5d, 0xa0, 0x42, 0x84, 0x4b, 0x90,
|
||||
0x03, 0x2f, 0xcc, 0x44, 0x60, 0xb2, 0xbf, 0x67, 0x22, 0x30, 0xcd, 0x71, 0x8f, 0x40, 0x0e, 0xfc,
|
||||
0x31, 0x13, 0x81, 0xc9, 0x56, 0x52, 0xf3, 0x63, 0xce, 0xdf, 0x63, 0xff, 0x11, 0xeb, 0x8f, 0xaf,
|
||||
0x6e, 0x0a, 0x0b, 0x6f, 0x6f, 0x0a, 0x0b, 0xcf, 0x07, 0x05, 0xe9, 0x6a, 0x50, 0x90, 0xde, 0x0c,
|
||||
0x0a, 0xd2, 0xfb, 0x41, 0x41, 0xfa, 0x7f, 0xff, 0x1e, 0x7f, 0x7b, 0xb7, 0xa2, 0xa8, 0x21, 0xf3,
|
||||
0x8e, 0xbf, 0x7e, 0x0c, 0x00, 0x00, 0xff, 0xff, 0xef, 0xe7, 0xe1, 0xb7, 0x47, 0x0b, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@ -960,6 +963,13 @@ func (m *Container) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.Sandbox) > 0 {
|
||||
i -= len(m.Sandbox)
|
||||
copy(dAtA[i:], m.Sandbox)
|
||||
i = encodeVarintContainers(dAtA, i, uint64(len(m.Sandbox)))
|
||||
i--
|
||||
dAtA[i] = 0x5a
|
||||
}
|
||||
if len(m.Extensions) > 0 {
|
||||
for k := range m.Extensions {
|
||||
v := m.Extensions[k]
|
||||
@ -1563,6 +1573,10 @@ func (m *Container) Size() (n int) {
|
||||
n += mapEntrySize + 1 + sovContainers(uint64(mapEntrySize))
|
||||
}
|
||||
}
|
||||
l = len(m.Sandbox)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovContainers(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@ -1788,6 +1802,7 @@ func (this *Container) String() string {
|
||||
`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 + `,`,
|
||||
`Sandbox:` + fmt.Sprintf("%v", this.Sandbox) + `,`,
|
||||
`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
@ -2480,6 +2495,38 @@ func (m *Container) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
m.Extensions[mapkey] = *mapvalue
|
||||
iNdEx = postIndex
|
||||
case 11:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Sandbox", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContainers
|
||||
}
|
||||
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 ErrInvalidLengthContainers
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthContainers
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Sandbox = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipContainers(dAtA[iNdEx:])
|
||||
|
@ -114,6 +114,9 @@ message Container {
|
||||
// data, one should only update the specified extension using field paths
|
||||
// to select a specific map key.
|
||||
map<string, google.protobuf.Any> extensions = 10 [(gogoproto.nullable) = false];
|
||||
|
||||
// Sandbox ID this container belongs to.
|
||||
string sandbox = 11;
|
||||
}
|
||||
|
||||
message GetContainerRequest {
|
||||
|
17
api/services/sandbox/v1/doc.go
Normal file
17
api/services/sandbox/v1/doc.go
Normal file
@ -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 sandbox
|
4333
api/services/sandbox/v1/sandbox.pb.go
Normal file
4333
api/services/sandbox/v1/sandbox.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
133
api/services/sandbox/v1/sandbox.proto
Normal file
133
api/services/sandbox/v1/sandbox.proto
Normal file
@ -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.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
// Sandbox is a v2 runtime extension that allows more complex execution environments for containers.
|
||||
// This adds a notion of groups of containers that share same lifecycle and/or resources.
|
||||
// A few good fits for sandbox can be:
|
||||
// - A "pause" container in k8s, that acts as a parent process for child containers to hold network namespace.
|
||||
// - (micro)VMs that launch a VM process and executes containers inside guest OS.
|
||||
// containerd in this case remains implementation agnostic and delegates sandbox handling to runtimes.
|
||||
// See proposal and discussion here: https://github.com/containerd/containerd/issues/4131
|
||||
package containerd.services.sandbox.v1;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import weak "gogoproto/gogo.proto";
|
||||
|
||||
import "github.com/containerd/containerd/api/types/sandbox.proto";
|
||||
import "github.com/containerd/containerd/api/types/mount.proto";
|
||||
|
||||
option go_package = "github.com/containerd/containerd/api/services/sandbox/v1;sandbox";
|
||||
|
||||
// Store provides a metadata storage interface for sandboxes. Similarly to `Containers`,
|
||||
// sandbox object includes info required to start a new instance, but no runtime state.
|
||||
// When running a new sandbox instance, store objects are used as base type to create from.
|
||||
service Store {
|
||||
rpc Create(StoreCreateRequest) returns (StoreCreateResponse);
|
||||
rpc Update(StoreUpdateRequest) returns (StoreUpdateResponse);
|
||||
rpc Delete(StoreDeleteRequest) returns (StoreDeleteResponse);
|
||||
rpc List(StoreListRequest) returns (StoreListResponse);
|
||||
rpc Get(StoreGetRequest) returns (StoreGetResponse);
|
||||
}
|
||||
|
||||
message StoreCreateRequest {
|
||||
containerd.types.Sandbox sandbox = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message StoreCreateResponse {
|
||||
containerd.types.Sandbox sandbox = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message StoreUpdateRequest {
|
||||
containerd.types.Sandbox sandbox = 1 [(gogoproto.nullable) = false];
|
||||
repeated string fields = 2;
|
||||
}
|
||||
|
||||
message StoreUpdateResponse {
|
||||
containerd.types.Sandbox sandbox = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message StoreDeleteRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message StoreDeleteResponse {}
|
||||
|
||||
message StoreListRequest {
|
||||
repeated string filters = 1;
|
||||
}
|
||||
|
||||
message StoreListResponse {
|
||||
repeated containerd.types.Sandbox list = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message StoreGetRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message StoreGetResponse {
|
||||
containerd.types.Sandbox sandbox = 1;
|
||||
}
|
||||
|
||||
// Controller is an interface to manage runtime sandbox instances.
|
||||
service Controller {
|
||||
rpc Start(ControllerStartRequest) returns (ControllerStartResponse);
|
||||
rpc Shutdown(ControllerShutdownRequest) returns (ControllerShutdownResponse);
|
||||
rpc Wait(ControllerWaitRequest) returns (ControllerWaitResponse);
|
||||
rpc Status(ControllerStatusRequest) returns (ControllerStatusResponse);
|
||||
}
|
||||
|
||||
message ControllerStartRequest {
|
||||
string sandbox_id = 1;
|
||||
repeated containerd.types.Mount rootfs = 2;
|
||||
google.protobuf.Any options = 3;
|
||||
}
|
||||
|
||||
message ControllerStartResponse {
|
||||
string sandbox_id = 1;
|
||||
uint32 pid = 2;
|
||||
}
|
||||
|
||||
message ControllerShutdownRequest {
|
||||
string sandbox_id = 1;
|
||||
uint32 timeout_secs = 2;
|
||||
}
|
||||
|
||||
message ControllerShutdownResponse {}
|
||||
|
||||
message ControllerWaitRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message ControllerWaitResponse {
|
||||
uint32 exit_status = 1;
|
||||
google.protobuf.Timestamp exited_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message ControllerStatusRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message ControllerStatusResponse {
|
||||
string id = 1;
|
||||
uint32 pid = 2;
|
||||
string state = 3;
|
||||
uint32 exit_status = 4;
|
||||
google.protobuf.Timestamp exited_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
google.protobuf.Any extra = 6;
|
||||
}
|
1148
api/types/sandbox.pb.go
Normal file
1148
api/types/sandbox.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
52
api/types/sandbox.proto
Normal file
52
api/types/sandbox.proto
Normal file
@ -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.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package containerd.types;
|
||||
|
||||
import weak "gogoproto/gogo.proto";
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
option go_package = "github.com/containerd/containerd/api/types;types";
|
||||
|
||||
// Sandbox represents a sandbox metadata object that keeps all info required by controller to
|
||||
// work with a particular instance.
|
||||
message Sandbox {
|
||||
// SandboxID is a unique instance identifier within namespace
|
||||
string sandbox_id = 1;
|
||||
message Runtime {
|
||||
// Name is the name of the runtime.
|
||||
string name = 1;
|
||||
// Options specify additional runtime initialization options for the shim (this data will be available in StartShim).
|
||||
// Typically this data expected to be runtime shim implementation specific.
|
||||
google.protobuf.Any options = 2;
|
||||
}
|
||||
// Runtime specifies which runtime to use for executing this container.
|
||||
Runtime runtime = 2 [(gogoproto.nullable) = false];
|
||||
// Spec is sandbox configuration (kin of OCI runtime spec), spec's data will be written to a config.json file in the
|
||||
// bundle directory (similary to OCI spec).
|
||||
google.protobuf.Any spec = 3;
|
||||
// Labels provides an area to include arbitrary data on containers.
|
||||
map<string, string> labels = 4 [(gogoproto.nullable) = false];
|
||||
// CreatedAt is the time the container was first created.
|
||||
google.protobuf.Timestamp created_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
// UpdatedAt is the last time the container was mutated.
|
||||
google.protobuf.Timestamp updated_at = 6 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
// Extensions allow clients to provide optional blobs that can be handled by runtime.
|
||||
map<string, google.protobuf.Any> extensions = 7 [(gogoproto.nullable) = false];
|
||||
}
|
24
client.go
24
client.go
@ -35,6 +35,7 @@ import (
|
||||
introspectionapi "github.com/containerd/containerd/api/services/introspection/v1"
|
||||
leasesapi "github.com/containerd/containerd/api/services/leases/v1"
|
||||
namespacesapi "github.com/containerd/containerd/api/services/namespaces/v1"
|
||||
sandboxsapi "github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
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"
|
||||
@ -54,13 +55,14 @@ import (
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/containerd/containerd/sandbox"
|
||||
"github.com/containerd/containerd/services/introspection"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
snproxy "github.com/containerd/containerd/snapshots/proxy"
|
||||
"github.com/containerd/typeurl"
|
||||
ptypes "github.com/gogo/protobuf/types"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/backoff"
|
||||
@ -688,6 +690,26 @@ func (c *Client) EventService() EventService {
|
||||
return NewEventServiceFromClient(eventsapi.NewEventsClient(c.conn))
|
||||
}
|
||||
|
||||
// SandboxStore returns the underlying sandbox store client
|
||||
func (c *Client) SandboxStore() sandbox.Store {
|
||||
if c.sandboxStore != nil {
|
||||
return c.sandboxStore
|
||||
}
|
||||
c.connMu.Lock()
|
||||
defer c.connMu.Unlock()
|
||||
return NewRemoteSandboxStore(sandboxsapi.NewStoreClient(c.conn))
|
||||
}
|
||||
|
||||
// SandboxController returns the underlying sandbox controller client
|
||||
func (c *Client) SandboxController() sandbox.Controller {
|
||||
if c.sandboxController != nil {
|
||||
return c.sandboxController
|
||||
}
|
||||
c.connMu.Lock()
|
||||
defer c.connMu.Unlock()
|
||||
return NewSandboxRemoteController(sandboxsapi.NewControllerClient(c.conn))
|
||||
}
|
||||
|
||||
// VersionService returns the underlying VersionClient
|
||||
func (c *Client) VersionService() versionservice.VersionClient {
|
||||
c.connMu.Lock()
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/runtime/v2/runc/manager"
|
||||
_ "github.com/containerd/containerd/runtime/v2/runc/pause"
|
||||
_ "github.com/containerd/containerd/runtime/v2/runc/task/plugin"
|
||||
"github.com/containerd/containerd/runtime/v2/shim"
|
||||
)
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
_ "github.com/containerd/containerd/services/leases"
|
||||
_ "github.com/containerd/containerd/services/namespaces"
|
||||
_ "github.com/containerd/containerd/services/opt"
|
||||
_ "github.com/containerd/containerd/services/sandbox"
|
||||
_ "github.com/containerd/containerd/services/snapshots"
|
||||
_ "github.com/containerd/containerd/services/tasks"
|
||||
_ "github.com/containerd/containerd/services/version"
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/plugins"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/pprof"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/run"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/sandboxes"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/snapshots"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/tasks"
|
||||
versionCmd "github.com/containerd/containerd/cmd/ctr/commands/version"
|
||||
@ -114,6 +115,7 @@ containerd CLI
|
||||
tasks.Command,
|
||||
install.Command,
|
||||
ociCmd.Command,
|
||||
sandboxes.Command,
|
||||
}, extraCmds...)
|
||||
app.Before = func(context *cli.Context) error {
|
||||
if context.GlobalBool("debug") {
|
||||
|
178
cmd/ctr/commands/sandboxes/sandboxes.go
Normal file
178
cmd/ctr/commands/sandboxes/sandboxes.go
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sandboxes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/defaults"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Command is a set of subcommands to manage runtimes with sandbox support
|
||||
var Command = cli.Command{
|
||||
Name: "sandboxes",
|
||||
Aliases: []string{"sandbox", "sb", "s"},
|
||||
Usage: "manage sandboxes",
|
||||
Subcommands: cli.Commands{
|
||||
runCommand,
|
||||
listCommand,
|
||||
removeCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var runCommand = cli.Command{
|
||||
Name: "run",
|
||||
Aliases: []string{"create", "c", "r"},
|
||||
Usage: "run a new sandbox",
|
||||
ArgsUsage: "[flags] <pod-config.json> <sandbox-id>",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "runtime name",
|
||||
Value: defaults.DefaultRuntime,
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
id = context.Args().Get(0)
|
||||
runtime = context.String("runtime")
|
||||
)
|
||||
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
sandbox, err := client.NewSandbox(ctx, id,
|
||||
containerd.WithSandboxRuntime(runtime, nil),
|
||||
containerd.WithSandboxSpec(&oci.Spec{}),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new sandbox: %w", err)
|
||||
}
|
||||
|
||||
err = sandbox.Start(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println(sandbox.ID())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "list sandboxes",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringSliceFlag{
|
||||
Name: "filters",
|
||||
Usage: "the list of filters to apply when querying sandboxes from the store",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
var (
|
||||
writer = tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
|
||||
filters = context.StringSlice("filters")
|
||||
)
|
||||
|
||||
defer func() {
|
||||
_ = writer.Flush()
|
||||
}()
|
||||
|
||||
list, err := client.SandboxStore().List(ctx, filters...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list sandboxes: %w", err)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintln(writer, "ID\tCREATED\tRUNTIME\t"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, sandbox := range list {
|
||||
_, err := fmt.Fprintf(writer, "%s\t%s\t%s\t\n", sandbox.ID, sandbox.CreatedAt, sandbox.Runtime.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var removeCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
ArgsUsage: "<id> [<id>, ...]",
|
||||
Usage: "remove sandboxes",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "force, f",
|
||||
Usage: "ignore shutdown errors when removing sandbox",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
force := context.Bool("force")
|
||||
|
||||
for _, id := range context.Args() {
|
||||
sandbox, err := client.LoadSandbox(ctx, id)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("failed to load sandbox %s", id)
|
||||
continue
|
||||
}
|
||||
|
||||
err = sandbox.Stop(ctx)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("failed to stop sandbox %s", id)
|
||||
if !force {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
err = sandbox.Delete(ctx)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("failed to shutdown sandbox %s", id)
|
||||
continue
|
||||
}
|
||||
|
||||
log.G(ctx).Infof("deleted: %s", id)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
@ -74,6 +74,15 @@ func WithRuntime(name string, options interface{}) NewContainerOpts {
|
||||
}
|
||||
}
|
||||
|
||||
// WithSandbox joins the container to a container group (aka sandbox) from the given ID
|
||||
// Note: shim runtime must support sandboxes environments.
|
||||
func WithSandbox(sandboxID string) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
c.SandboxID = sandboxID
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithImage sets the provided image as the base for the container
|
||||
func WithImage(i Image) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
|
@ -76,6 +76,11 @@ type Container struct {
|
||||
|
||||
// Extensions stores client-specified metadata
|
||||
Extensions map[string]typeurl.Any
|
||||
|
||||
// SandboxID is an identifier of sandbox this container belongs to.
|
||||
//
|
||||
// This property is optional, but can't be changed after creation.
|
||||
SandboxID string
|
||||
}
|
||||
|
||||
// RuntimeInfo holds runtime specific information
|
||||
|
@ -166,6 +166,7 @@ func containerToProto(container *containers.Container) containersapi.Container {
|
||||
Snapshotter: container.Snapshotter,
|
||||
SnapshotKey: container.SnapshotKey,
|
||||
Extensions: extensions,
|
||||
Sandbox: container.SandboxID,
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,6 +194,7 @@ func containerFromProto(containerpb *containersapi.Container) containers.Contain
|
||||
CreatedAt: containerpb.CreatedAt,
|
||||
UpdatedAt: containerpb.UpdatedAt,
|
||||
Extensions: extensions,
|
||||
SandboxID: containerpb.Sandbox,
|
||||
}
|
||||
}
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -48,6 +48,7 @@ require (
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
|
||||
github.com/opencontainers/selinux v1.10.0
|
||||
github.com/pelletier/go-toml v1.9.3
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.11.1
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
@ -103,7 +104,6 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.30.0 // indirect
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/containerd/containerd/filters"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/sandbox"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
)
|
||||
|
||||
@ -149,6 +150,23 @@ func adaptSnapshot(info snapshots.Info) filters.Adaptor {
|
||||
})
|
||||
}
|
||||
|
||||
func adaptSandbox(instance *sandbox.Sandbox) filters.Adaptor {
|
||||
return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
|
||||
if len(fieldpath) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
switch fieldpath[0] {
|
||||
case "id":
|
||||
return instance.ID, true
|
||||
case "labels":
|
||||
return checkMap(fieldpath[1:], instance.Labels)
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func checkMap(fieldpath []string, m map[string]string) (string, bool) {
|
||||
if len(m) == 0 {
|
||||
return "", false
|
||||
|
@ -213,11 +213,11 @@ func WriteAny(bkt *bolt.Bucket, name []byte, any typeurl.Any) error {
|
||||
|
||||
data, err := proto.Marshal(pbany)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to marshal: %w", err)
|
||||
}
|
||||
|
||||
if err := bkt.Put(name, data); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("put failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -130,6 +130,7 @@ var (
|
||||
bucketKeyObjectBlob = []byte("blob") // stores content links
|
||||
bucketKeyObjectIngests = []byte("ingests") // stores ingest objects
|
||||
bucketKeyObjectLeases = []byte("leases") // stores leases
|
||||
bucketKeyObjectSandboxes = []byte("sandboxes") // stores sandboxes
|
||||
|
||||
bucketKeyDigest = []byte("digest")
|
||||
bucketKeyMediaType = []byte("mediatype")
|
||||
@ -149,6 +150,7 @@ var (
|
||||
bucketKeyExpected = []byte("expected")
|
||||
bucketKeyRef = []byte("ref")
|
||||
bucketKeyExpireAt = []byte("expireat")
|
||||
bucketKeySandboxID = []byte("sandboxid")
|
||||
|
||||
deprecatedBucketKeyObjectIngest = []byte("ingest") // stores ingest links, deprecated in v1.2
|
||||
)
|
||||
@ -270,3 +272,19 @@ func createIngestBucket(tx *bolt.Tx, namespace, ref string) (*bolt.Bucket, error
|
||||
func getIngestBucket(tx *bolt.Tx, namespace, ref string) *bolt.Bucket {
|
||||
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(ref))
|
||||
}
|
||||
|
||||
func createSandboxBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
|
||||
return createBucketIfNotExists(
|
||||
tx,
|
||||
[]byte(namespace),
|
||||
bucketKeyObjectSandboxes,
|
||||
)
|
||||
}
|
||||
|
||||
func getSandboxBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
|
||||
return getBucket(
|
||||
tx,
|
||||
[]byte(namespace),
|
||||
bucketKeyObjectSandboxes,
|
||||
)
|
||||
}
|
||||
|
@ -359,6 +359,8 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
|
||||
}
|
||||
|
||||
container.Extensions = extensions
|
||||
case string(bucketKeySandboxID):
|
||||
container.SandboxID = string(v)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -407,5 +409,9 @@ func writeContainer(bkt *bolt.Bucket, container *containers.Container) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bkt.Put(bucketKeySandboxID, []byte(container.SandboxID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return boltutil.WriteLabels(bkt, container.Labels)
|
||||
}
|
||||
|
377
metadata/sandbox.go
Normal file
377
metadata/sandbox.go
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES 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"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/filters"
|
||||
"github.com/containerd/containerd/identifiers"
|
||||
"github.com/containerd/containerd/metadata/boltutil"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
api "github.com/containerd/containerd/sandbox"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/pkg/errors"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
type sandboxStore struct {
|
||||
db *DB
|
||||
}
|
||||
|
||||
var _ api.Store = (*sandboxStore)(nil)
|
||||
|
||||
// NewSandboxStore creates a datababase client for sandboxes
|
||||
func NewSandboxStore(db *DB) api.Store {
|
||||
return &sandboxStore{db: db}
|
||||
}
|
||||
|
||||
// Create a sandbox record in the store
|
||||
func (s *sandboxStore) Create(ctx context.Context, sandbox api.Sandbox) (api.Sandbox, error) {
|
||||
ns, err := namespaces.NamespaceRequired(ctx)
|
||||
if err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
sandbox.CreatedAt = time.Now().UTC()
|
||||
sandbox.UpdatedAt = sandbox.CreatedAt
|
||||
|
||||
if err := s.validate(&sandbox); err != nil {
|
||||
return api.Sandbox{}, errors.Wrap(err, "failed to validate sandbox")
|
||||
}
|
||||
|
||||
if err := s.db.Update(func(tx *bbolt.Tx) error {
|
||||
parent, err := createSandboxBucket(tx, ns)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create error: %w", err)
|
||||
}
|
||||
|
||||
if err := s.write(parent, &sandbox, false); err != nil {
|
||||
return fmt.Errorf("write error: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
return sandbox, nil
|
||||
}
|
||||
|
||||
// Update the sandbox with the provided sandbox object and fields
|
||||
func (s *sandboxStore) Update(ctx context.Context, sandbox api.Sandbox, fieldpaths ...string) (api.Sandbox, error) {
|
||||
ns, err := namespaces.NamespaceRequired(ctx)
|
||||
if err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
ret := api.Sandbox{}
|
||||
if err := update(ctx, s.db, func(tx *bbolt.Tx) error {
|
||||
parent := getSandboxBucket(tx, ns)
|
||||
if parent == nil {
|
||||
return errors.Wrap(errdefs.ErrNotFound, "no sandbox buckets")
|
||||
}
|
||||
|
||||
updated, err := s.read(parent, []byte(sandbox.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(fieldpaths) == 0 {
|
||||
fieldpaths = []string{"labels", "extensions", "spec", "runtime"}
|
||||
|
||||
if updated.Runtime.Name != sandbox.Runtime.Name {
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "sandbox.Runtime.Name field is immutable")
|
||||
}
|
||||
}
|
||||
|
||||
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] = sandbox.Labels[key]
|
||||
continue
|
||||
} else if strings.HasPrefix(path, "extensions.") {
|
||||
if updated.Extensions == nil {
|
||||
updated.Extensions = map[string]typeurl.Any{}
|
||||
}
|
||||
|
||||
key := strings.TrimPrefix(path, "extensions.")
|
||||
updated.Extensions[key] = sandbox.Extensions[key]
|
||||
continue
|
||||
}
|
||||
|
||||
switch path {
|
||||
case "labels":
|
||||
updated.Labels = sandbox.Labels
|
||||
case "extensions":
|
||||
updated.Extensions = sandbox.Extensions
|
||||
case "runtime":
|
||||
updated.Runtime = sandbox.Runtime
|
||||
case "spec":
|
||||
updated.Spec = sandbox.Spec
|
||||
default:
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on sandbox %q", path, sandbox.ID)
|
||||
}
|
||||
}
|
||||
|
||||
updated.UpdatedAt = time.Now().UTC()
|
||||
|
||||
if err := s.validate(&updated); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.write(parent, &updated, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret = updated
|
||||
return nil
|
||||
}); err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Get sandbox metadata using the id
|
||||
func (s *sandboxStore) Get(ctx context.Context, id string) (api.Sandbox, error) {
|
||||
ns, err := namespaces.NamespaceRequired(ctx)
|
||||
if err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
ret := api.Sandbox{}
|
||||
if err := view(ctx, s.db, func(tx *bbolt.Tx) error {
|
||||
bucket := getSandboxBucket(tx, ns)
|
||||
if bucket == nil {
|
||||
return errors.Wrap(errdefs.ErrNotFound, "no sandbox buckets")
|
||||
}
|
||||
|
||||
out, err := s.read(bucket, []byte(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret = out
|
||||
return nil
|
||||
}); err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// List returns sandboxes that match one or more of the provided filters
|
||||
func (s *sandboxStore) List(ctx context.Context, fields ...string) ([]api.Sandbox, error) {
|
||||
ns, err := namespaces.NamespaceRequired(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filter, err := filters.ParseAll(fields...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
var (
|
||||
list []api.Sandbox
|
||||
)
|
||||
|
||||
if err := view(ctx, s.db, func(tx *bbolt.Tx) error {
|
||||
bucket := getSandboxBucket(tx, ns)
|
||||
if bucket == nil {
|
||||
// We haven't created any sandboxes yet, just return empty list
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bucket.ForEach(func(k, v []byte) error {
|
||||
info, err := s.read(bucket, k)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to read bucket %q", string(k))
|
||||
}
|
||||
|
||||
if filter.Match(adaptSandbox(&info)) {
|
||||
list = append(list, info)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// Delete a sandbox from metadata store using the id
|
||||
func (s *sandboxStore) Delete(ctx context.Context, id string) error {
|
||||
ns, err := namespaces.NamespaceRequired(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := update(ctx, s.db, func(tx *bbolt.Tx) error {
|
||||
buckets := getSandboxBucket(tx, ns)
|
||||
if buckets == nil {
|
||||
return errors.Wrap(errdefs.ErrNotFound, "no sandbox buckets")
|
||||
}
|
||||
|
||||
if err := buckets.DeleteBucket([]byte(id)); err != nil {
|
||||
return errors.Wrapf(err, "failed to delete sandbox %q", id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sandboxStore) write(parent *bbolt.Bucket, instance *api.Sandbox, overwrite bool) error {
|
||||
var (
|
||||
bucket *bbolt.Bucket
|
||||
err error
|
||||
id = []byte(instance.ID)
|
||||
)
|
||||
|
||||
if overwrite {
|
||||
bucket, err = parent.CreateBucketIfNotExists(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
bucket = parent.Bucket(id)
|
||||
if bucket != nil {
|
||||
return errors.Wrapf(errdefs.ErrAlreadyExists, "sandbox bucket %q already exists", instance.ID)
|
||||
}
|
||||
|
||||
bucket, err = parent.CreateBucket(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := boltutil.WriteTimestamps(bucket, instance.CreatedAt, instance.UpdatedAt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := boltutil.WriteLabels(bucket, instance.Labels); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := boltutil.WriteExtensions(bucket, instance.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := boltutil.WriteAny(bucket, bucketKeySpec, instance.Spec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtimeBucket, err := bucket.CreateBucketIfNotExists(bucketKeyRuntime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := runtimeBucket.Put(bucketKeyName, []byte(instance.Runtime.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := boltutil.WriteAny(runtimeBucket, bucketKeyOptions, instance.Runtime.Options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sandboxStore) read(parent *bbolt.Bucket, id []byte) (api.Sandbox, error) {
|
||||
var (
|
||||
inst api.Sandbox
|
||||
err error
|
||||
)
|
||||
|
||||
bucket := parent.Bucket(id)
|
||||
if bucket == nil {
|
||||
return api.Sandbox{}, errors.Wrapf(errdefs.ErrNotFound, "bucket %q not found", id)
|
||||
}
|
||||
|
||||
inst.ID = string(id)
|
||||
|
||||
inst.Labels, err = boltutil.ReadLabels(bucket)
|
||||
if err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
if err := boltutil.ReadTimestamps(bucket, &inst.CreatedAt, &inst.UpdatedAt); err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
inst.Spec, err = boltutil.ReadAny(bucket, bucketKeySpec)
|
||||
if err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
runtimeBucket := bucket.Bucket(bucketKeyRuntime)
|
||||
if runtimeBucket == nil {
|
||||
return api.Sandbox{}, errors.New("no runtime bucket")
|
||||
}
|
||||
|
||||
inst.Runtime.Name = string(runtimeBucket.Get(bucketKeyName))
|
||||
inst.Runtime.Options, err = boltutil.ReadAny(runtimeBucket, bucketKeyOptions)
|
||||
if err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
inst.Extensions, err = boltutil.ReadExtensions(bucket)
|
||||
if err != nil {
|
||||
return api.Sandbox{}, err
|
||||
}
|
||||
|
||||
return inst, nil
|
||||
}
|
||||
|
||||
func (s *sandboxStore) validate(new *api.Sandbox) error {
|
||||
if err := identifiers.Validate(new.ID); err != nil {
|
||||
return errors.Wrap(err, "invalid sandbox ID")
|
||||
}
|
||||
|
||||
if new.CreatedAt.IsZero() {
|
||||
return errors.Wrap(errdefs.ErrInvalidArgument, "creation date must not be zero")
|
||||
}
|
||||
|
||||
if new.UpdatedAt.IsZero() {
|
||||
return errors.Wrap(errdefs.ErrInvalidArgument, "updated date must not be zero")
|
||||
}
|
||||
|
||||
if new.Runtime.Name == "" {
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "sandbox.Runtime.Name must be set")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
292
metadata/sandbox_test.go
Normal file
292
metadata/sandbox_test.go
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES 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 (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/protobuf"
|
||||
api "github.com/containerd/containerd/sandbox"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/gogo/protobuf/types"
|
||||
)
|
||||
|
||||
func TestSandboxCreate(t *testing.T) {
|
||||
ctx, db, done := testDB(t)
|
||||
defer done()
|
||||
|
||||
store := NewSandboxStore(db)
|
||||
|
||||
in := api.Sandbox{
|
||||
ID: "1",
|
||||
Labels: map[string]string{"a": "1", "b": "2"},
|
||||
Spec: &types.Any{TypeUrl: "1", Value: []byte{1, 2, 3}},
|
||||
Extensions: map[string]typeurl.Any{
|
||||
"ext1": &types.Any{TypeUrl: "url/1", Value: []byte{1, 2, 3}},
|
||||
"ext2": &types.Any{TypeUrl: "url/2", Value: []byte{3, 2, 1}},
|
||||
},
|
||||
Runtime: api.RuntimeOpts{
|
||||
Name: "test",
|
||||
Options: &types.Any{TypeUrl: "url/3", Value: []byte{4, 5, 6}},
|
||||
},
|
||||
}
|
||||
|
||||
_, err := store.Create(ctx, in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
out, err := store.Get(ctx, "1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertEqualInstances(t, in, out)
|
||||
}
|
||||
|
||||
func TestSandboxCreateDup(t *testing.T) {
|
||||
ctx, db, done := testDB(t)
|
||||
defer done()
|
||||
|
||||
store := NewSandboxStore(db)
|
||||
|
||||
in := api.Sandbox{
|
||||
ID: "1",
|
||||
Spec: &types.Any{TypeUrl: "1", Value: []byte{1, 2, 3}},
|
||||
Runtime: api.RuntimeOpts{Name: "test"},
|
||||
}
|
||||
|
||||
_, err := store.Create(ctx, in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = store.Create(ctx, in)
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
t.Fatalf("expected %+v, got %+v", errdefs.ErrAlreadyExists, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSandboxUpdate(t *testing.T) {
|
||||
ctx, db, done := testDB(t)
|
||||
defer done()
|
||||
|
||||
store := NewSandboxStore(db)
|
||||
|
||||
if _, err := store.Create(ctx, api.Sandbox{
|
||||
ID: "2",
|
||||
Labels: map[string]string{"lbl1": "existing"},
|
||||
Spec: &types.Any{TypeUrl: "1", Value: []byte{1}}, // will replace
|
||||
Extensions: map[string]typeurl.Any{
|
||||
"ext2": &types.Any{TypeUrl: "url2", Value: []byte{4, 5, 6}}, // will append `ext1`
|
||||
},
|
||||
Runtime: api.RuntimeOpts{Name: "test"}, // no change
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedSpec := types.Any{TypeUrl: "2", Value: []byte{3, 2, 1}}
|
||||
|
||||
out, err := store.Update(ctx, api.Sandbox{
|
||||
ID: "2",
|
||||
Labels: map[string]string{"lbl1": "new"},
|
||||
Spec: &expectedSpec,
|
||||
Extensions: map[string]typeurl.Any{
|
||||
"ext1": &types.Any{TypeUrl: "url1", Value: []byte{1, 2}},
|
||||
},
|
||||
}, "labels.lbl1", "extensions.ext1", "spec")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := api.Sandbox{
|
||||
ID: "2",
|
||||
Spec: &expectedSpec,
|
||||
Labels: map[string]string{
|
||||
"lbl1": "new",
|
||||
},
|
||||
Extensions: map[string]typeurl.Any{
|
||||
"ext1": &types.Any{TypeUrl: "url1", Value: []byte{1, 2}},
|
||||
"ext2": &types.Any{TypeUrl: "url2", Value: []byte{4, 5, 6}},
|
||||
},
|
||||
Runtime: api.RuntimeOpts{Name: "test"},
|
||||
}
|
||||
|
||||
assertEqualInstances(t, out, expected)
|
||||
}
|
||||
|
||||
func TestSandboxGetInvalid(t *testing.T) {
|
||||
ctx, db, done := testDB(t)
|
||||
defer done()
|
||||
|
||||
store := NewSandboxStore(db)
|
||||
|
||||
_, err := store.Get(ctx, "invalid_id")
|
||||
if err == nil {
|
||||
t.Fatalf("expected %+v error for invalid ID", errdefs.ErrNotFound)
|
||||
} else if !errdefs.IsNotFound(err) {
|
||||
t.Fatalf("unexpected error %T type", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSandboxList(t *testing.T) {
|
||||
ctx, db, done := testDB(t)
|
||||
defer done()
|
||||
|
||||
store := NewSandboxStore(db)
|
||||
|
||||
in := []api.Sandbox{
|
||||
{
|
||||
ID: "1",
|
||||
Labels: map[string]string{"test": "1"},
|
||||
Spec: &types.Any{TypeUrl: "1", Value: []byte{1, 2, 3}},
|
||||
Extensions: map[string]typeurl.Any{"ext": &types.Any{}},
|
||||
Runtime: api.RuntimeOpts{Name: "test"},
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Labels: map[string]string{"test": "2"},
|
||||
Spec: &types.Any{TypeUrl: "2", Value: []byte{3, 2, 1}},
|
||||
Extensions: map[string]typeurl.Any{"ext": &types.Any{
|
||||
TypeUrl: "test",
|
||||
Value: []byte{9},
|
||||
}},
|
||||
Runtime: api.RuntimeOpts{Name: "test"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, inst := range in {
|
||||
_, err := store.Create(ctx, inst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
out, err := store.List(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(in) != len(out) {
|
||||
t.Fatalf("expected list size: %d != %d", len(in), len(out))
|
||||
}
|
||||
|
||||
for i := range out {
|
||||
assertEqualInstances(t, out[i], in[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSandboxListWithFilter(t *testing.T) {
|
||||
ctx, db, done := testDB(t)
|
||||
defer done()
|
||||
|
||||
store := NewSandboxStore(db)
|
||||
|
||||
in := []api.Sandbox{
|
||||
{
|
||||
ID: "1",
|
||||
Labels: map[string]string{"test": "1"},
|
||||
Spec: &types.Any{TypeUrl: "1", Value: []byte{1, 2, 3}},
|
||||
Extensions: map[string]typeurl.Any{"ext": &types.Any{}},
|
||||
Runtime: api.RuntimeOpts{Name: "test"},
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Labels: map[string]string{"test": "2"},
|
||||
Spec: &types.Any{TypeUrl: "2", Value: []byte{3, 2, 1}},
|
||||
Extensions: map[string]typeurl.Any{"ext": &types.Any{
|
||||
TypeUrl: "test",
|
||||
Value: []byte{9},
|
||||
}},
|
||||
Runtime: api.RuntimeOpts{Name: "test"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, inst := range in {
|
||||
_, err := store.Create(ctx, inst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
out, err := store.List(ctx, "id==1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(out) != 1 {
|
||||
t.Fatalf("expected list to contain 1 element, got %d", len(out))
|
||||
}
|
||||
|
||||
assertEqualInstances(t, out[0], in[0])
|
||||
}
|
||||
|
||||
func TestSandboxDelete(t *testing.T) {
|
||||
ctx, db, done := testDB(t)
|
||||
defer done()
|
||||
|
||||
store := NewSandboxStore(db)
|
||||
|
||||
in := api.Sandbox{
|
||||
ID: "2",
|
||||
Spec: &types.Any{TypeUrl: "1", Value: []byte{1, 2, 3}},
|
||||
Runtime: api.RuntimeOpts{Name: "test"},
|
||||
}
|
||||
|
||||
_, err := store.Create(ctx, in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = store.Delete(ctx, "2")
|
||||
if err != nil {
|
||||
t.Fatalf("deleted failed %+v", err)
|
||||
}
|
||||
|
||||
_, err = store.Get(ctx, "2")
|
||||
if !errdefs.IsNotFound(err) {
|
||||
t.Fatalf("unexpected err result: %+v != %+v", err, errdefs.ErrNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func assertEqualInstances(t *testing.T, x, y api.Sandbox) {
|
||||
if x.ID != y.ID {
|
||||
t.Fatalf("ids are not equal: %q != %q", x.ID, y.ID)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(x.Labels, y.Labels) {
|
||||
t.Fatalf("labels are not equal: %+v != %+v", x.Labels, y.Labels)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(x.Spec, y.Spec) {
|
||||
t.Fatalf("specs are not equal: %+v != %+v", x.Spec, y.Spec)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(x.Extensions, y.Extensions) {
|
||||
t.Fatalf("extensions are not equal: %+v != %+v", x.Extensions, y.Extensions)
|
||||
}
|
||||
|
||||
if x.Runtime.Name != y.Runtime.Name {
|
||||
t.Fatalf("runtime names are not equal: %q != %q", x.Runtime.Name, y.Runtime.Name)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(protobuf.FromAny(x.Runtime.Options), protobuf.FromAny(y.Runtime.Options)) {
|
||||
t.Fatalf("runtime options are not equal: %+v != %+v", x.Runtime.Options, y.Runtime.Options)
|
||||
}
|
||||
}
|
@ -49,6 +49,8 @@ type CreateOpts struct {
|
||||
// Runtime name to use (e.g. `io.containerd.NAME.VERSION`).
|
||||
// As an alternative full abs path to binary may be specified instead.
|
||||
Runtime string
|
||||
// SandboxID is an optional ID of sandbox this container belongs to
|
||||
SandboxID string
|
||||
}
|
||||
|
||||
// Exit information for a process
|
||||
|
@ -25,6 +25,8 @@ import (
|
||||
"github.com/containerd/containerd/identifiers"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const configFilename = "config.json"
|
||||
@ -43,7 +45,7 @@ func LoadBundle(ctx context.Context, root, id string) (*Bundle, error) {
|
||||
}
|
||||
|
||||
// NewBundle returns a new bundle on disk
|
||||
func NewBundle(ctx context.Context, root, state, id string, spec []byte) (b *Bundle, err error) {
|
||||
func NewBundle(ctx context.Context, root, state, id string, spec typeurl.Any) (b *Bundle, err error) {
|
||||
if err := identifiers.Validate(id); err != nil {
|
||||
return nil, fmt.Errorf("invalid task id %s: %w", id, err)
|
||||
}
|
||||
@ -73,8 +75,10 @@ func NewBundle(ctx context.Context, root, state, id string, spec []byte) (b *Bun
|
||||
if err := os.Mkdir(b.Path, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := prepareBundleDirectoryPermissions(b.Path, spec); err != nil {
|
||||
return nil, err
|
||||
if typeurl.Is(spec, &specs.Spec{}) {
|
||||
if err := prepareBundleDirectoryPermissions(b.Path, spec.GetValue()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
paths = append(paths, b.Path)
|
||||
// create working directory for the bundle
|
||||
@ -100,9 +104,14 @@ func NewBundle(ctx context.Context, root, state, id string, spec []byte) (b *Bun
|
||||
if err := os.Symlink(work, filepath.Join(b.Path, "work")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// write the spec to the bundle
|
||||
err = os.WriteFile(filepath.Join(b.Path, configFilename), spec, 0666)
|
||||
return b, err
|
||||
if spec := spec.GetValue(); spec != nil {
|
||||
// write the spec to the bundle
|
||||
err = os.WriteFile(filepath.Join(b.Path, configFilename), spec, 0666)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to write %s", configFilename)
|
||||
}
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Bundle represents an OCI bundle
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/containerd/pkg/testutil"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -57,11 +58,11 @@ func TestNewBundle(t *testing.T) {
|
||||
GIDMappings: []specs.LinuxIDMapping{{ContainerID: 0, HostID: usernsGID}},
|
||||
}
|
||||
}
|
||||
specBytes, err := json.Marshal(&spec)
|
||||
specAny, err := typeurl.MarshalAny(&spec)
|
||||
require.NoError(t, err, "failed to marshal spec")
|
||||
|
||||
ctx := namespaces.WithNamespace(context.TODO(), namespaces.Default)
|
||||
b, err := NewBundle(ctx, work, state, id, specBytes)
|
||||
b, err := NewBundle(ctx, work, state, id, specAny)
|
||||
require.NoError(t, err, "NewBundle should succeed")
|
||||
require.NotNil(t, b, "bundle should not be nil")
|
||||
|
||||
|
@ -96,6 +96,24 @@ func init() {
|
||||
return NewTaskManager(shimManager), nil
|
||||
},
|
||||
})
|
||||
|
||||
// Task manager uses shim manager as a dependency to manage shim instances.
|
||||
// However, due to time limits and to avoid migration steps in 1.6 release,
|
||||
// use the following workaround.
|
||||
// This expected to be removed in 1.7.
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.RuntimePluginV2,
|
||||
ID: "shim",
|
||||
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
taskManagerI, err := ic.GetByID(plugin.RuntimePluginV2, "task")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
taskManager := taskManagerI.(*TaskManager)
|
||||
return taskManager.manager, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type ManagerConfig struct {
|
||||
@ -158,7 +176,7 @@ func (m *ShimManager) ID() string {
|
||||
|
||||
// Start launches a new shim instance
|
||||
func (m *ShimManager) Start(ctx context.Context, id string, opts runtime.CreateOpts) (_ ShimProcess, retErr error) {
|
||||
bundle, err := NewBundle(ctx, m.root, m.state, id, opts.Spec.GetValue())
|
||||
bundle, err := NewBundle(ctx, m.root, m.state, id, opts.Spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -168,6 +186,40 @@ func (m *ShimManager) Start(ctx context.Context, id string, opts runtime.CreateO
|
||||
}
|
||||
}()
|
||||
|
||||
// This container belongs to sandbox which supposed to be already started via sandbox API.
|
||||
if opts.SandboxID != "" {
|
||||
process, err := m.Get(ctx, opts.SandboxID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't find sandbox %s", opts.SandboxID)
|
||||
}
|
||||
|
||||
// Write sandbox ID this task belongs to.
|
||||
if err := os.WriteFile(filepath.Join(bundle.Path, "sandbox"), []byte(opts.SandboxID), 0600); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
address, err := shimbinary.ReadAddress(filepath.Join(m.state, process.Namespace(), opts.SandboxID, "address"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get socket address for sandbox %q: %w", opts.SandboxID, err)
|
||||
}
|
||||
|
||||
// Use sandbox's socket address to handle task requests for this container.
|
||||
if err := shimbinary.WriteAddress(filepath.Join(bundle.Path, "address"), address); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shim, err := loadShim(ctx, bundle, func() {})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load sandbox task %q: %w", opts.SandboxID, err)
|
||||
}
|
||||
|
||||
if err := m.shims.Add(ctx, shim); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return shim, nil
|
||||
}
|
||||
|
||||
shim, err := m.startShim(ctx, bundle, id, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -324,7 +376,8 @@ func (m *ShimManager) Get(ctx context.Context, id string) (ShimProcess, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return proc, nil
|
||||
shimTask := proc.(*shimTask)
|
||||
return shimTask, nil
|
||||
}
|
||||
|
||||
// Delete a runtime task
|
||||
@ -388,7 +441,8 @@ func (m *TaskManager) Create(ctx context.Context, taskID string, opts runtime.Cr
|
||||
dctx, cancel := timeout.WithContext(context.Background(), cleanupTimeout)
|
||||
defer cancel()
|
||||
|
||||
_, errShim := shim.delete(dctx, func(context.Context, string) {})
|
||||
sandboxed := opts.SandboxID != ""
|
||||
_, errShim := shim.delete(dctx, sandboxed, func(context.Context, string) {})
|
||||
if errShim != nil {
|
||||
if errdefs.IsDeadlineExceeded(errShim) {
|
||||
dctx, cancel = timeout.WithContext(context.Background(), cleanupTimeout)
|
||||
@ -422,8 +476,14 @@ func (m *TaskManager) Delete(ctx context.Context, taskID string) (*runtime.Exit,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
container, err := m.manager.containers.Get(ctx, taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sandboxed := container.SandboxID != ""
|
||||
shimTask := item.(*shimTask)
|
||||
exit, err := shimTask.delete(ctx, func(ctx context.Context, id string) {
|
||||
exit, err := shimTask.delete(ctx, sandboxed, func(ctx context.Context, id string) {
|
||||
m.manager.shims.Delete(ctx, id)
|
||||
})
|
||||
|
||||
|
104
runtime/v2/runc/pause/sandbox.go
Normal file
104
runtime/v2/runc/pause/sandbox.go
Normal file
@ -0,0 +1,104 @@
|
||||
//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 pause
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/pkg/shutdown"
|
||||
"github.com/containerd/ttrpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/containerd/containerd/plugin"
|
||||
api "github.com/containerd/containerd/runtime/v2/task"
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.TTRPCPlugin,
|
||||
ID: "pause",
|
||||
Requires: []plugin.Type{
|
||||
plugin.InternalPlugin,
|
||||
},
|
||||
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
ss, err := ic.GetByID(plugin.InternalPlugin, "shutdown")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pauseService{
|
||||
shutdown: ss.(shutdown.Service),
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// pauseService is an extension for task v2 runtime to support Pod "pause" containers via sandbox API.
|
||||
type pauseService struct {
|
||||
shutdown shutdown.Service
|
||||
}
|
||||
|
||||
var _ api.SandboxService = (*pauseService)(nil)
|
||||
|
||||
func (p *pauseService) RegisterTTRPC(server *ttrpc.Server) error {
|
||||
api.RegisterSandboxService(server, p)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pauseService) StartSandbox(ctx context.Context, req *api.StartSandboxRequest) (*api.StartSandboxResponse, error) {
|
||||
log.Debugf("start sandbox request: %+v", req)
|
||||
return &api.StartSandboxResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *pauseService) StopSandbox(ctx context.Context, req *api.StopSandboxRequest) (*api.StopSandboxResponse, error) {
|
||||
log.Debugf("stop sandbox request: %+v", req)
|
||||
p.shutdown.Shutdown()
|
||||
return &api.StopSandboxResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *pauseService) WaitSandbox(ctx context.Context, req *api.WaitSandboxRequest) (*api.WaitSandboxResponse, error) {
|
||||
return &api.WaitSandboxResponse{
|
||||
ExitStatus: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *pauseService) UpdateSandbox(ctx context.Context, req *api.UpdateSandboxRequest) (*api.UpdateSandboxResponse, error) {
|
||||
log.Debugf("update sandbox request: %+v", req)
|
||||
return &api.UpdateSandboxResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *pauseService) PauseSandbox(ctx context.Context, req *api.PauseSandboxRequest) (*api.PauseSandboxResponse, error) {
|
||||
log.Debugf("pause sandbox request: %+v", req)
|
||||
return &api.PauseSandboxResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *pauseService) ResumeSandbox(ctx context.Context, req *api.ResumeSandboxRequest) (*api.ResumeSandboxResponse, error) {
|
||||
log.Debugf("resume sandbox request: %+v", req)
|
||||
return &api.ResumeSandboxResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *pauseService) SandboxStatus(ctx context.Context, req *api.SandboxStatusRequest) (*api.SandboxStatusResponse, error) {
|
||||
log.Debugf("sandbox status request: %+v", req)
|
||||
return &api.SandboxStatusResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *pauseService) PingSandbox(ctx context.Context, req *api.PingRequest) (*api.PingResponse, error) {
|
||||
return &api.PingResponse{}, nil
|
||||
}
|
@ -194,6 +194,10 @@ type ShimProcess interface {
|
||||
ID() string
|
||||
// Namespace of this shim.
|
||||
Namespace() string
|
||||
// Bundle is a file system path to shim's bundle.
|
||||
Bundle() string
|
||||
// Client returns the underlying TTRPC client for this shim.
|
||||
Client() *ttrpc.Client
|
||||
}
|
||||
|
||||
type shim struct {
|
||||
@ -210,6 +214,10 @@ func (s *shim) Namespace() string {
|
||||
return s.bundle.Namespace
|
||||
}
|
||||
|
||||
func (s *shim) Bundle() string {
|
||||
return s.bundle.Path
|
||||
}
|
||||
|
||||
func (s *shim) Close() error {
|
||||
return s.client.Close()
|
||||
}
|
||||
@ -243,6 +251,10 @@ type shimTask struct {
|
||||
task task.TaskService
|
||||
}
|
||||
|
||||
func (s *shimTask) Client() *ttrpc.Client {
|
||||
return s.client
|
||||
}
|
||||
|
||||
func (s *shimTask) Shutdown(ctx context.Context) error {
|
||||
_, err := s.task.Shutdown(ctx, &task.ShutdownRequest{
|
||||
ID: s.ID(),
|
||||
@ -271,7 +283,7 @@ func (s *shimTask) PID(ctx context.Context) (uint32, error) {
|
||||
return response.TaskPid, nil
|
||||
}
|
||||
|
||||
func (s *shimTask) delete(ctx context.Context, removeTask func(ctx context.Context, id string)) (*runtime.Exit, error) {
|
||||
func (s *shimTask) delete(ctx context.Context, sandboxed bool, removeTask func(ctx context.Context, id string)) (*runtime.Exit, error) {
|
||||
response, shimErr := s.task.Delete(ctx, &task.DeleteRequest{
|
||||
ID: s.ID(),
|
||||
})
|
||||
@ -299,8 +311,12 @@ func (s *shimTask) delete(ctx context.Context, removeTask func(ctx context.Conte
|
||||
removeTask(ctx, s.ID())
|
||||
}
|
||||
|
||||
if err := s.waitShutdown(ctx); err != nil {
|
||||
log.G(ctx).WithField("id", s.ID()).WithError(err).Error("failed to shutdown shim task")
|
||||
// Don't shutdown sandbox as there may be other containers running.
|
||||
// Let controller decide when to shutdown.
|
||||
if !sandboxed {
|
||||
if err := s.waitShutdown(ctx); err != nil {
|
||||
log.G(ctx).WithField("id", s.ID()).WithError(err).Error("failed to shutdown shim task")
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.shim.delete(ctx); err != nil {
|
||||
|
3694
runtime/v2/task/sandbox.pb.go
Normal file
3694
runtime/v2/task/sandbox.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
121
runtime/v2/task/sandbox.proto
Normal file
121
runtime/v2/task/sandbox.proto
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT 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;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import weak "gogoproto/gogo.proto";
|
||||
|
||||
import "github.com/containerd/containerd/api/types/mount.proto";
|
||||
|
||||
// Sandbox is an optional interface that shim may implement to support sandboxes environments.
|
||||
// A typical example of sandbox is microVM or pause container - an entity that groups containers and/or
|
||||
// holds resources relevant for this group.
|
||||
service Sandbox {
|
||||
// StartSandbox will create/start a new sandbox instance
|
||||
rpc StartSandbox(StartSandboxRequest) returns (StartSandboxResponse);
|
||||
|
||||
// StopSandbox will stop existing sandbox instance
|
||||
rpc StopSandbox(StopSandboxRequest) returns (StopSandboxResponse);
|
||||
|
||||
// WaitSandbox blocks until sanbox exits.
|
||||
rpc WaitSandbox(WaitSandboxRequest) returns (WaitSandboxResponse);
|
||||
|
||||
// Update can be used to amend the state of currently running sandbox instance (depending on
|
||||
// implementation this can be used to resize/reacquire needed resources like RAM/CPU).
|
||||
rpc UpdateSandbox(UpdateSandboxRequest) returns (UpdateSandboxResponse);
|
||||
|
||||
// PauseSandbox will suspend currently running sandbox instance.
|
||||
rpc PauseSandbox(PauseSandboxRequest) returns (PauseSandboxResponse);
|
||||
|
||||
// ResumeSandbox will resuyme previously suspended sandbox instance.
|
||||
rpc ResumeSandbox(ResumeSandboxRequest) returns (ResumeSandboxResponse);
|
||||
|
||||
// SandboxStatus will return current status of the running sandbox instance
|
||||
rpc SandboxStatus(SandboxStatusRequest) returns (SandboxStatusResponse);
|
||||
|
||||
// PingSandbox is a lightweight API call to check whether sandbox alive.
|
||||
rpc PingSandbox(PingRequest) returns (PingResponse);
|
||||
}
|
||||
|
||||
message StartSandboxRequest {
|
||||
string sandbox_id = 1;
|
||||
string bundle_path = 2;
|
||||
repeated containerd.types.Mount rootfs = 3;
|
||||
google.protobuf.Any options = 4;
|
||||
}
|
||||
|
||||
message StartSandboxResponse {
|
||||
uint32 pid = 1;
|
||||
}
|
||||
|
||||
message StopSandboxRequest {
|
||||
string sandbox_id = 1;
|
||||
uint32 timeout_secs = 2;
|
||||
}
|
||||
|
||||
message StopSandboxResponse {}
|
||||
|
||||
message UpdateSandboxRequest {
|
||||
string sandbox_id = 1;
|
||||
google.protobuf.Any resources = 2;
|
||||
map<string, string> annotations = 3;
|
||||
}
|
||||
|
||||
message WaitSandboxRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message WaitSandboxResponse {
|
||||
uint32 exit_status = 1;
|
||||
google.protobuf.Timestamp exited_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message UpdateSandboxResponse {}
|
||||
|
||||
message SandboxStatusRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message PauseSandboxRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message PauseSandboxResponse {}
|
||||
|
||||
message ResumeSandboxRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message ResumeSandboxResponse {}
|
||||
|
||||
message SandboxStatusResponse {
|
||||
string id = 1;
|
||||
uint32 pid = 2;
|
||||
string state = 3;
|
||||
uint32 exit_status = 4;
|
||||
google.protobuf.Timestamp exited_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
google.protobuf.Any extra = 6;
|
||||
}
|
||||
|
||||
message PingRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message PingResponse {}
|
239
sandbox.go
Normal file
239
sandbox.go
Normal file
@ -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 containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/oci"
|
||||
api "github.com/containerd/containerd/sandbox"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/gogo/protobuf/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Sandbox is a high level client to containerd's sandboxes.
|
||||
type Sandbox interface {
|
||||
// ID is a sandbox identifier
|
||||
ID() string
|
||||
// PID returns sandbox's process PID or error if its not yet started.
|
||||
PID() (uint32, error)
|
||||
// NewContainer creates new container that will belong to this sandbox
|
||||
NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error)
|
||||
// Labels returns the labels set on the sandbox
|
||||
Labels(ctx context.Context) (map[string]string, error)
|
||||
// Start starts new sandbox instance
|
||||
Start(ctx context.Context) error
|
||||
// Stop sends stop request to the shim instance.
|
||||
Stop(ctx context.Context) error
|
||||
// Wait blocks until sandbox process exits.
|
||||
Wait(ctx context.Context) (<-chan ExitStatus, error)
|
||||
// Delete removes sandbox from the metadata store.
|
||||
Delete(ctx context.Context) error
|
||||
}
|
||||
|
||||
type sandboxClient struct {
|
||||
pid *uint32
|
||||
client *Client
|
||||
metadata api.Sandbox
|
||||
}
|
||||
|
||||
func (s *sandboxClient) ID() string {
|
||||
return s.metadata.ID
|
||||
}
|
||||
|
||||
func (s *sandboxClient) PID() (uint32, error) {
|
||||
if s.pid == nil {
|
||||
return 0, fmt.Errorf("sandbox not started")
|
||||
}
|
||||
|
||||
return *s.pid, nil
|
||||
}
|
||||
|
||||
func (s *sandboxClient) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) {
|
||||
return s.client.NewContainer(ctx, id, append(opts, WithSandbox(s.ID()))...)
|
||||
}
|
||||
|
||||
func (s *sandboxClient) Labels(ctx context.Context) (map[string]string, error) {
|
||||
sandbox, err := s.client.SandboxStore().Get(ctx, s.ID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sandbox.Labels, nil
|
||||
}
|
||||
|
||||
func (s *sandboxClient) Start(ctx context.Context) error {
|
||||
pid, err := s.client.SandboxController().Start(ctx, s.ID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.pid = &pid
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sandboxClient) Wait(ctx context.Context) (<-chan ExitStatus, error) {
|
||||
c := make(chan ExitStatus, 1)
|
||||
go func() {
|
||||
defer close(c)
|
||||
|
||||
resp, err := s.client.SandboxController().Wait(ctx, s.ID())
|
||||
if err != nil {
|
||||
c <- ExitStatus{
|
||||
code: UnknownExitStatus,
|
||||
err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c <- ExitStatus{
|
||||
code: resp.ExitStatus,
|
||||
exitedAt: resp.ExitedAt,
|
||||
}
|
||||
}()
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (s *sandboxClient) Stop(ctx context.Context) error {
|
||||
return s.client.SandboxController().Shutdown(ctx, s.ID())
|
||||
}
|
||||
|
||||
func (s *sandboxClient) Delete(ctx context.Context) error {
|
||||
return s.client.SandboxStore().Delete(ctx, s.ID())
|
||||
}
|
||||
|
||||
// NewSandbox creates new sandbox client
|
||||
func (c *Client) NewSandbox(ctx context.Context, sandboxID string, opts ...NewSandboxOpts) (Sandbox, error) {
|
||||
if sandboxID == "" {
|
||||
return nil, errors.New("sandbox ID must be specified")
|
||||
}
|
||||
|
||||
newSandbox := api.Sandbox{
|
||||
ID: sandboxID,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
if err := opt(ctx, c, &newSandbox); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
metadata, err := c.SandboxStore().Create(ctx, newSandbox)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &sandboxClient{
|
||||
pid: nil, // Not yet started
|
||||
client: c,
|
||||
metadata: metadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LoadSandbox laods existing sandbox metadata object using the id
|
||||
func (c *Client) LoadSandbox(ctx context.Context, id string) (Sandbox, error) {
|
||||
sandbox, err := c.SandboxStore().Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status, err := c.SandboxController().Status(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load sandbox %s, status request failed: %w", id, err)
|
||||
}
|
||||
|
||||
return &sandboxClient{
|
||||
pid: &status.Pid,
|
||||
client: c,
|
||||
metadata: sandbox,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewSandboxOpts is a sandbox options and extensions to be provided by client
|
||||
type NewSandboxOpts func(ctx context.Context, client *Client, sandbox *api.Sandbox) error
|
||||
|
||||
// WithSandboxRuntime allows a user to specify the runtime to be used to run a sandbox
|
||||
func WithSandboxRuntime(name string, options interface{}) NewSandboxOpts {
|
||||
return func(ctx context.Context, client *Client, s *api.Sandbox) error {
|
||||
if options == nil {
|
||||
options = &types.Empty{}
|
||||
}
|
||||
|
||||
opts, err := typeurl.MarshalAny(options)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to marshal sandbox runtime options")
|
||||
}
|
||||
|
||||
s.Runtime = api.RuntimeOpts{
|
||||
Name: name,
|
||||
Options: opts,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithSandboxSpec will provide the sandbox runtime spec
|
||||
func WithSandboxSpec(s *oci.Spec, opts ...oci.SpecOpts) NewSandboxOpts {
|
||||
return func(ctx context.Context, client *Client, sandbox *api.Sandbox) error {
|
||||
c := &containers.Container{ID: sandbox.ID}
|
||||
|
||||
if err := oci.ApplyOpts(ctx, client, c, s, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spec, err := typeurl.MarshalAny(s)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to marshal spec")
|
||||
}
|
||||
|
||||
sandbox.Spec = spec
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithSandboxExtension attaches an extension to sandbox
|
||||
func WithSandboxExtension(name string, ext interface{}) NewSandboxOpts {
|
||||
return func(ctx context.Context, client *Client, s *api.Sandbox) error {
|
||||
if s.Extensions == nil {
|
||||
s.Extensions = make(map[string]typeurl.Any)
|
||||
}
|
||||
|
||||
any, err := typeurl.MarshalAny(ext)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to marshal sandbox extension")
|
||||
}
|
||||
|
||||
s.Extensions[name] = any
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// WithSandboxLabels attaches map of labels to sandbox
|
||||
func WithSandboxLabels(labels map[string]string) NewSandboxOpts {
|
||||
return func(ctx context.Context, client *Client, sandbox *api.Sandbox) error {
|
||||
sandbox.Labels = labels
|
||||
return nil
|
||||
}
|
||||
}
|
41
sandbox/controller.go
Normal file
41
sandbox/controller.go
Normal file
@ -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 sandbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
)
|
||||
|
||||
// Controller is an interface to manage sandboxes at runtime.
|
||||
// When running in sandbox mode, shim expected to implement `SandboxService`.
|
||||
// Shim lifetimes are now managed manually via sandbox API by the containerd's client.
|
||||
type Controller interface {
|
||||
// Start will start new sandbox instance.
|
||||
// containerd will run new shim runtime instance and will invoke Start to create a sandbox process.
|
||||
// This routine must be invoked before scheduling containers on this instance.
|
||||
// Once started clients may run containers via Task service (additionally specifying sandbox id the container will belong to).
|
||||
Start(ctx context.Context, sandboxID string) (uint32, error)
|
||||
// Shutdown deletes and cleans all tasks and sandbox instance.
|
||||
Shutdown(ctx context.Context, sandboxID string) error
|
||||
// Wait blocks until sandbox process exits.
|
||||
Wait(ctx context.Context, sandboxID string) (*sandbox.ControllerWaitResponse, error)
|
||||
// Status will query sandbox process status. It is heavier than Ping call and must be used whenever you need to
|
||||
// gather metadata about current sandbox state (status, uptime, resource use, etc).
|
||||
Status(ctx context.Context, sandboxID string) (*sandbox.ControllerStatusResponse, error)
|
||||
}
|
68
sandbox/helpers.go
Normal file
68
sandbox/helpers.go
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES 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 (
|
||||
"github.com/containerd/containerd/api/types"
|
||||
"github.com/containerd/containerd/protobuf"
|
||||
"github.com/containerd/typeurl"
|
||||
gogo_types "github.com/gogo/protobuf/types"
|
||||
)
|
||||
|
||||
// ToProto will map Sandbox struct to it's protobuf definition
|
||||
func ToProto(sandbox *Sandbox) types.Sandbox {
|
||||
extensions := make(map[string]gogo_types.Any)
|
||||
for k, v := range sandbox.Extensions {
|
||||
extensions[k] = *protobuf.FromAny(v)
|
||||
}
|
||||
return types.Sandbox{
|
||||
SandboxID: sandbox.ID,
|
||||
Runtime: types.Sandbox_Runtime{
|
||||
Name: sandbox.Runtime.Name,
|
||||
Options: protobuf.FromAny(sandbox.Runtime.Options),
|
||||
},
|
||||
Labels: sandbox.Labels,
|
||||
CreatedAt: sandbox.CreatedAt,
|
||||
UpdatedAt: sandbox.UpdatedAt,
|
||||
Extensions: extensions,
|
||||
Spec: protobuf.FromAny(sandbox.Spec),
|
||||
}
|
||||
}
|
||||
|
||||
// FromProto map protobuf sandbox definition to Sandbox struct
|
||||
func FromProto(sandboxpb *types.Sandbox) Sandbox {
|
||||
runtime := RuntimeOpts{
|
||||
Name: sandboxpb.Runtime.Name,
|
||||
Options: sandboxpb.Runtime.Options,
|
||||
}
|
||||
|
||||
extensions := make(map[string]typeurl.Any)
|
||||
for k, v := range sandboxpb.Extensions {
|
||||
v := v
|
||||
extensions[k] = &v
|
||||
}
|
||||
|
||||
return Sandbox{
|
||||
ID: sandboxpb.SandboxID,
|
||||
Labels: sandboxpb.Labels,
|
||||
Runtime: runtime,
|
||||
Spec: sandboxpb.Spec,
|
||||
CreatedAt: sandboxpb.CreatedAt,
|
||||
UpdatedAt: sandboxpb.UpdatedAt,
|
||||
Extensions: extensions,
|
||||
}
|
||||
}
|
66
sandbox/store.go
Normal file
66
sandbox/store.go
Normal file
@ -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 sandbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/typeurl"
|
||||
)
|
||||
|
||||
// Sandbox is an object stored in metadata database
|
||||
type Sandbox struct {
|
||||
// ID uniquely identifies the sandbox in a namespace
|
||||
ID string
|
||||
// Labels provide metadata extension for a sandbox
|
||||
Labels map[string]string
|
||||
// Runtime shim to use for this sandbox
|
||||
Runtime RuntimeOpts
|
||||
// Spec carries the runtime specification used to implement the sandbox
|
||||
Spec typeurl.Any
|
||||
// CreatedAt is the time at which the sandbox was created
|
||||
CreatedAt time.Time
|
||||
// UpdatedAt is the time at which the sandbox was updated
|
||||
UpdatedAt time.Time
|
||||
// Extensions stores client-specified metadata
|
||||
Extensions map[string]typeurl.Any
|
||||
}
|
||||
|
||||
// RuntimeOpts holds runtime specific information
|
||||
type RuntimeOpts struct {
|
||||
Name string
|
||||
Options typeurl.Any
|
||||
}
|
||||
|
||||
// Store is a storage interface for sandbox metadata objects
|
||||
type Store interface {
|
||||
// Create a sandbox record in the store
|
||||
Create(ctx context.Context, sandbox Sandbox) (Sandbox, error)
|
||||
|
||||
// Update the sandbox with the provided sandbox object and fields
|
||||
Update(ctx context.Context, sandbox Sandbox, fieldpaths ...string) (Sandbox, error)
|
||||
|
||||
// Get sandbox metadata using the id
|
||||
Get(ctx context.Context, id string) (Sandbox, error)
|
||||
|
||||
// List returns sandboxes that match one or more of the provided filters
|
||||
List(ctx context.Context, filters ...string) ([]Sandbox, error)
|
||||
|
||||
// Delete a sandbox from metadata store using the id
|
||||
Delete(ctx context.Context, id string) error
|
||||
}
|
73
sandbox_controller.go
Normal file
73
sandbox_controller.go
Normal file
@ -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 containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
sb "github.com/containerd/containerd/sandbox"
|
||||
)
|
||||
|
||||
// sandboxRemoteController is a low level GRPC client for containerd's sandbox controller service
|
||||
type sandboxRemoteController struct {
|
||||
client api.ControllerClient
|
||||
}
|
||||
|
||||
var _ sb.Controller = (*sandboxRemoteController)(nil)
|
||||
|
||||
// NewSandboxRemoteController creates client for sandbox controller
|
||||
func NewSandboxRemoteController(client api.ControllerClient) sb.Controller {
|
||||
return &sandboxRemoteController{client: client}
|
||||
}
|
||||
|
||||
func (s *sandboxRemoteController) Start(ctx context.Context, sandboxID string) (uint32, error) {
|
||||
resp, err := s.client.Start(ctx, &api.ControllerStartRequest{SandboxID: sandboxID})
|
||||
if err != nil {
|
||||
return 0, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return resp.Pid, nil
|
||||
}
|
||||
|
||||
func (s *sandboxRemoteController) Shutdown(ctx context.Context, sandboxID string) error {
|
||||
_, err := s.client.Shutdown(ctx, &api.ControllerShutdownRequest{SandboxID: sandboxID})
|
||||
if err != nil {
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sandboxRemoteController) Wait(ctx context.Context, sandboxID string) (*api.ControllerWaitResponse, error) {
|
||||
resp, err := s.client.Wait(ctx, &api.ControllerWaitRequest{SandboxID: sandboxID})
|
||||
if err != nil {
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *sandboxRemoteController) Status(ctx context.Context, sandboxID string) (*api.ControllerStatusResponse, error) {
|
||||
resp, err := s.client.Status(ctx, &api.ControllerStatusRequest{SandboxID: sandboxID})
|
||||
if err != nil {
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
95
sandbox_store.go
Normal file
95
sandbox_store.go
Normal file
@ -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 containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
sb "github.com/containerd/containerd/sandbox"
|
||||
)
|
||||
|
||||
// remoteSandboxStore is a low-level containerd client to manage sandbox environments metadata
|
||||
type remoteSandboxStore struct {
|
||||
client api.StoreClient
|
||||
}
|
||||
|
||||
var _ sb.Store = (*remoteSandboxStore)(nil)
|
||||
|
||||
// NewRemoteSandboxStore create client for sandbox store
|
||||
func NewRemoteSandboxStore(client api.StoreClient) sb.Store {
|
||||
return &remoteSandboxStore{client: client}
|
||||
}
|
||||
|
||||
func (s *remoteSandboxStore) Create(ctx context.Context, sandbox sb.Sandbox) (sb.Sandbox, error) {
|
||||
resp, err := s.client.Create(ctx, &api.StoreCreateRequest{
|
||||
Sandbox: sb.ToProto(&sandbox),
|
||||
})
|
||||
if err != nil {
|
||||
return sb.Sandbox{}, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return sb.FromProto(&resp.Sandbox), nil
|
||||
}
|
||||
|
||||
func (s *remoteSandboxStore) Update(ctx context.Context, sandbox sb.Sandbox, fieldpaths ...string) (sb.Sandbox, error) {
|
||||
resp, err := s.client.Update(ctx, &api.StoreUpdateRequest{
|
||||
Sandbox: sb.ToProto(&sandbox),
|
||||
Fields: fieldpaths,
|
||||
})
|
||||
if err != nil {
|
||||
return sb.Sandbox{}, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return sb.FromProto(&resp.Sandbox), nil
|
||||
}
|
||||
|
||||
func (s *remoteSandboxStore) Get(ctx context.Context, id string) (sb.Sandbox, error) {
|
||||
resp, err := s.client.Get(ctx, &api.StoreGetRequest{
|
||||
SandboxID: id,
|
||||
})
|
||||
if err != nil {
|
||||
return sb.Sandbox{}, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return sb.FromProto(resp.Sandbox), nil
|
||||
}
|
||||
|
||||
func (s *remoteSandboxStore) List(ctx context.Context, filters ...string) ([]sb.Sandbox, error) {
|
||||
resp, err := s.client.List(ctx, &api.StoreListRequest{
|
||||
Filters: filters,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
out := make([]sb.Sandbox, len(resp.List))
|
||||
for i := range resp.List {
|
||||
out[i] = sb.FromProto(&resp.List[i])
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *remoteSandboxStore) Delete(ctx context.Context, id string) error {
|
||||
_, err := s.client.Delete(ctx, &api.StoreDeleteRequest{
|
||||
SandboxID: id,
|
||||
})
|
||||
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
18
services.go
18
services.go
@ -22,12 +22,14 @@ import (
|
||||
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"
|
||||
sandboxsapi "github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
"github.com/containerd/containerd/api/services/tasks/v1"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/sandbox"
|
||||
"github.com/containerd/containerd/services/introspection"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
)
|
||||
@ -43,6 +45,8 @@ type services struct {
|
||||
eventService EventService
|
||||
leasesService leases.Manager
|
||||
introspectionService introspection.Service
|
||||
sandboxStore sandbox.Store
|
||||
sandboxController sandbox.Controller
|
||||
}
|
||||
|
||||
// ServicesOpt allows callers to set options on the services
|
||||
@ -155,3 +159,17 @@ func WithIntrospectionService(in introspection.Service) ServicesOpt {
|
||||
s.introspectionService = in
|
||||
}
|
||||
}
|
||||
|
||||
// WithSandboxStore sets the sandbox store.
|
||||
func WithSandboxStore(client sandboxsapi.StoreClient) ServicesOpt {
|
||||
return func(s *services) {
|
||||
s.sandboxStore = NewRemoteSandboxStore(client)
|
||||
}
|
||||
}
|
||||
|
||||
// WithSandboxController sets the sandbox controller.
|
||||
func WithSandboxController(client sandboxsapi.ControllerClient) ServicesOpt {
|
||||
return func(s *services) {
|
||||
s.sandboxController = NewSandboxRemoteController(client)
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ func containerToProto(container *containers.Container) api.Container {
|
||||
CreatedAt: container.CreatedAt,
|
||||
UpdatedAt: container.UpdatedAt,
|
||||
Extensions: extensions,
|
||||
Sandbox: container.SandboxID,
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,5 +80,6 @@ func containerFromProto(containerpb *api.Container) containers.Container {
|
||||
Snapshotter: containerpb.Snapshotter,
|
||||
SnapshotKey: containerpb.SnapshotKey,
|
||||
Extensions: extensions,
|
||||
SandboxID: containerpb.Sandbox,
|
||||
}
|
||||
}
|
||||
|
196
services/sandbox/controller_local.go
Normal file
196
services/sandbox/controller_local.go
Normal file
@ -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 sandbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/events/exchange"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/runtime"
|
||||
v2 "github.com/containerd/containerd/runtime/v2"
|
||||
"github.com/containerd/containerd/runtime/v2/task"
|
||||
proto "github.com/containerd/containerd/runtime/v2/task"
|
||||
"github.com/containerd/containerd/sandbox"
|
||||
"github.com/containerd/containerd/services"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.ServicePlugin,
|
||||
ID: services.SandboxControllerService,
|
||||
Requires: []plugin.Type{
|
||||
plugin.RuntimePluginV2,
|
||||
plugin.MetadataPlugin,
|
||||
plugin.EventPlugin,
|
||||
},
|
||||
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
shimPlugin, err := ic.GetByID(plugin.RuntimePluginV2, "shim")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
metadataPlugin, err := ic.Get(plugin.MetadataPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exchangePlugin, err := ic.GetByID(plugin.EventPlugin, "exchange")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
shims = shimPlugin.(*v2.ShimManager)
|
||||
publisher = exchangePlugin.(*exchange.Exchange)
|
||||
db = metadataPlugin.(*metadata.DB)
|
||||
store = metadata.NewSandboxStore(db)
|
||||
)
|
||||
|
||||
return &controllerLocal{
|
||||
shims: shims,
|
||||
store: store,
|
||||
publisher: publisher,
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type controllerLocal struct {
|
||||
shims *v2.ShimManager
|
||||
store sandbox.Store
|
||||
publisher events.Publisher
|
||||
}
|
||||
|
||||
var _ api.ControllerClient = (*controllerLocal)(nil)
|
||||
|
||||
func (c *controllerLocal) Start(ctx context.Context, in *api.ControllerStartRequest, opts ...grpc.CallOption) (*api.ControllerStartResponse, error) {
|
||||
if _, err := c.shims.Get(ctx, in.SandboxID); err == nil {
|
||||
return nil, fmt.Errorf("sandbox %s already running: %w", in.SandboxID, errdefs.ErrAlreadyExists)
|
||||
}
|
||||
|
||||
info, err := c.store.Get(ctx, in.SandboxID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query sandbox metadata from store: %w", err)
|
||||
}
|
||||
|
||||
shim, err := c.shims.Start(ctx, in.SandboxID, runtime.CreateOpts{
|
||||
Spec: info.Spec,
|
||||
RuntimeOptions: info.Runtime.Options,
|
||||
Runtime: info.Runtime.Name,
|
||||
TaskOptions: nil,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start new sandbox: %w", err)
|
||||
}
|
||||
|
||||
svc := task.NewSandboxClient(shim.Client())
|
||||
|
||||
resp, err := svc.StartSandbox(ctx, &proto.StartSandboxRequest{
|
||||
SandboxID: in.SandboxID,
|
||||
BundlePath: shim.Bundle(),
|
||||
Rootfs: in.Rootfs,
|
||||
Options: in.Options,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start sandbox %s: %w", in.SandboxID, err)
|
||||
}
|
||||
|
||||
return &api.ControllerStartResponse{
|
||||
SandboxID: in.SandboxID,
|
||||
Pid: resp.Pid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *controllerLocal) Shutdown(ctx context.Context, in *api.ControllerShutdownRequest, opts ...grpc.CallOption) (*api.ControllerShutdownResponse, error) {
|
||||
svc, err := c.getSandbox(ctx, in.SandboxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := svc.StopSandbox(ctx, &proto.StopSandboxRequest{
|
||||
SandboxID: in.SandboxID,
|
||||
TimeoutSecs: in.TimeoutSecs,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("failed to stop sandbox: %w", err)
|
||||
}
|
||||
|
||||
if err := c.shims.Delete(ctx, in.SandboxID); err != nil {
|
||||
return nil, fmt.Errorf("failed to delete sandbox shim: %w", err)
|
||||
}
|
||||
|
||||
return &api.ControllerShutdownResponse{}, nil
|
||||
}
|
||||
|
||||
func (c *controllerLocal) Wait(ctx context.Context, in *api.ControllerWaitRequest, opts ...grpc.CallOption) (*api.ControllerWaitResponse, error) {
|
||||
svc, err := c.getSandbox(ctx, in.SandboxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := svc.WaitSandbox(ctx, &proto.WaitSandboxRequest{
|
||||
SandboxID: in.SandboxID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to wait sandbox %s: %w", in.SandboxID, err)
|
||||
}
|
||||
|
||||
return &api.ControllerWaitResponse{
|
||||
ExitStatus: resp.ExitStatus,
|
||||
ExitedAt: resp.ExitedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *controllerLocal) Status(ctx context.Context, in *api.ControllerStatusRequest, opts ...grpc.CallOption) (*api.ControllerStatusResponse, error) {
|
||||
svc, err := c.getSandbox(ctx, in.SandboxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := svc.SandboxStatus(ctx, &proto.SandboxStatusRequest{SandboxID: in.SandboxID})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query sandbox %s status: %w", in.SandboxID, err)
|
||||
}
|
||||
|
||||
return &api.ControllerStatusResponse{
|
||||
ID: resp.ID,
|
||||
Pid: resp.Pid,
|
||||
State: resp.State,
|
||||
ExitStatus: resp.ExitStatus,
|
||||
ExitedAt: resp.ExitedAt,
|
||||
Extra: resp.Extra,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *controllerLocal) getSandbox(ctx context.Context, id string) (task.SandboxService, error) {
|
||||
shim, err := c.shims.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, errdefs.ErrNotFound
|
||||
}
|
||||
|
||||
svc := task.NewSandboxClient(shim.Client())
|
||||
return svc, nil
|
||||
}
|
89
services/sandbox/controller_service.go
Normal file
89
services/sandbox/controller_service.go
Normal file
@ -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 (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/services"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "sandbox-controllers",
|
||||
Requires: []plugin.Type{
|
||||
plugin.ServicePlugin,
|
||||
},
|
||||
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
plugins, err := ic.GetByType(plugin.ServicePlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p, ok := plugins[services.SandboxControllerService]
|
||||
if !ok {
|
||||
return nil, errors.New("sandbox service not found")
|
||||
}
|
||||
|
||||
i, err := p.Instance()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &controllerService{
|
||||
local: i.(api.ControllerClient),
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type controllerService struct {
|
||||
local api.ControllerClient
|
||||
}
|
||||
|
||||
var _ api.ControllerServer = (*controllerService)(nil)
|
||||
|
||||
func (s *controllerService) Register(server *grpc.Server) error {
|
||||
api.RegisterControllerServer(server, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *controllerService) Start(ctx context.Context, req *api.ControllerStartRequest) (*api.ControllerStartResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("start sandbox")
|
||||
return s.local.Start(ctx, req)
|
||||
}
|
||||
|
||||
func (s *controllerService) Shutdown(ctx context.Context, req *api.ControllerShutdownRequest) (*api.ControllerShutdownResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("delete sandbox")
|
||||
return s.local.Shutdown(ctx, req)
|
||||
}
|
||||
|
||||
func (s *controllerService) Wait(ctx context.Context, req *api.ControllerWaitRequest) (*api.ControllerWaitResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("wait sandbox")
|
||||
return s.local.Wait(ctx, req)
|
||||
}
|
||||
|
||||
func (s *controllerService) Status(ctx context.Context, req *api.ControllerStatusRequest) (*api.ControllerStatusResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("sandbox status")
|
||||
return s.local.Status(ctx, req)
|
||||
}
|
111
services/sandbox/store_local.go
Normal file
111
services/sandbox/store_local.go
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES 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 (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/services"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
"github.com/containerd/containerd/api/types"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/sandbox"
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.ServicePlugin,
|
||||
ID: services.SandboxStoreService,
|
||||
Requires: []plugin.Type{
|
||||
plugin.MetadataPlugin,
|
||||
},
|
||||
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
m, err := ic.Get(plugin.MetadataPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db := m.(*metadata.DB)
|
||||
return &sandboxLocal{
|
||||
store: metadata.NewSandboxStore(db),
|
||||
publisher: ic.Events,
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type sandboxLocal struct {
|
||||
store sandbox.Store
|
||||
publisher events.Publisher
|
||||
}
|
||||
|
||||
var _ = (api.StoreClient)(&sandboxLocal{})
|
||||
|
||||
func (s *sandboxLocal) Create(ctx context.Context, in *api.StoreCreateRequest, _ ...grpc.CallOption) (*api.StoreCreateResponse, error) {
|
||||
sb, err := s.store.Create(ctx, sandbox.FromProto(&in.Sandbox))
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &api.StoreCreateResponse{Sandbox: sandbox.ToProto(&sb)}, nil
|
||||
}
|
||||
|
||||
func (s *sandboxLocal) Update(ctx context.Context, in *api.StoreUpdateRequest, _ ...grpc.CallOption) (*api.StoreUpdateResponse, error) {
|
||||
sb, err := s.store.Update(ctx, sandbox.FromProto(&in.Sandbox), in.Fields...)
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &api.StoreUpdateResponse{Sandbox: sandbox.ToProto(&sb)}, nil
|
||||
}
|
||||
|
||||
func (s *sandboxLocal) Get(ctx context.Context, in *api.StoreGetRequest, _ ...grpc.CallOption) (*api.StoreGetResponse, error) {
|
||||
resp, err := s.store.Get(ctx, in.SandboxID)
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
desc := sandbox.ToProto(&resp)
|
||||
return &api.StoreGetResponse{Sandbox: &desc}, nil
|
||||
}
|
||||
|
||||
func (s *sandboxLocal) List(ctx context.Context, in *api.StoreListRequest, _ ...grpc.CallOption) (*api.StoreListResponse, error) {
|
||||
resp, err := s.store.List(ctx, in.Filters...)
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
list := make([]types.Sandbox, len(resp))
|
||||
for i := range resp {
|
||||
list[i] = sandbox.ToProto(&resp[i])
|
||||
}
|
||||
|
||||
return &api.StoreListResponse{List: list}, nil
|
||||
}
|
||||
|
||||
func (s *sandboxLocal) Delete(ctx context.Context, in *api.StoreDeleteRequest, _ ...grpc.CallOption) (*api.StoreDeleteResponse, error) {
|
||||
if err := s.store.Delete(ctx, in.SandboxID); err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &api.StoreDeleteResponse{}, nil
|
||||
}
|
90
services/sandbox/store_service.go
Normal file
90
services/sandbox/store_service.go
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES 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 (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/sandbox/v1"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/services"
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "sandboxes",
|
||||
Requires: []plugin.Type{
|
||||
plugin.ServicePlugin,
|
||||
},
|
||||
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
plugins, err := ic.GetByType(plugin.ServicePlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, ok := plugins[services.SandboxStoreService]
|
||||
if !ok {
|
||||
return nil, errors.New("sandbox store service not found")
|
||||
}
|
||||
i, err := p.Instance()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &sandboxService{local: i.(api.StoreClient)}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type sandboxService struct {
|
||||
local api.StoreClient
|
||||
}
|
||||
|
||||
var _ api.StoreServer = (*sandboxService)(nil)
|
||||
|
||||
func (s *sandboxService) Register(server *grpc.Server) error {
|
||||
api.RegisterStoreServer(server, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sandboxService) Create(ctx context.Context, req *api.StoreCreateRequest) (*api.StoreCreateResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("create sandbox")
|
||||
return s.local.Create(ctx, req)
|
||||
}
|
||||
|
||||
func (s *sandboxService) Update(ctx context.Context, req *api.StoreUpdateRequest) (*api.StoreUpdateResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("update sandbox")
|
||||
return s.local.Update(ctx, req)
|
||||
}
|
||||
|
||||
func (s *sandboxService) List(ctx context.Context, req *api.StoreListRequest) (*api.StoreListResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("list sandboxes")
|
||||
return s.local.List(ctx, req)
|
||||
}
|
||||
|
||||
func (s *sandboxService) Get(ctx context.Context, req *api.StoreGetRequest) (*api.StoreGetResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("get sandbox")
|
||||
return s.local.Get(ctx, req)
|
||||
}
|
||||
|
||||
func (s *sandboxService) Delete(ctx context.Context, req *api.StoreDeleteRequest) (*api.StoreDeleteResponse, error) {
|
||||
log.G(ctx).WithField("req", req).Debug("delete sandbox")
|
||||
return s.local.Delete(ctx, req)
|
||||
}
|
@ -33,4 +33,8 @@ const (
|
||||
DiffService = "diff-service"
|
||||
// IntrospectionService is the id of introspection service
|
||||
IntrospectionService = "introspection-service"
|
||||
// SandboxStoreService is the id of Sandbox's store service
|
||||
SandboxStoreService = "sandbox-store-service"
|
||||
// SandboxControllerService is the id of Sandbox's controller service
|
||||
SandboxControllerService = "sandbox-controller-service"
|
||||
)
|
||||
|
@ -200,6 +200,7 @@ func (l *local) Create(ctx context.Context, r *api.CreateTaskRequest, _ ...grpc.
|
||||
Runtime: container.Runtime.Name,
|
||||
RuntimeOptions: container.Runtime.Options,
|
||||
TaskOptions: r.Options,
|
||||
SandboxID: container.SandboxID,
|
||||
}
|
||||
if r.RuntimePath != "" {
|
||||
opts.Runtime = r.RuntimePath
|
||||
|
Loading…
Reference in New Issue
Block a user