瀏覽代碼

Add inspect command

Signed-off-by: Ulysses Souza <[email protected]>
Ulysses Souza 5 年之前
父節點
當前提交
96bc1ca6f1

+ 9 - 0
azure/aci.go

@@ -87,6 +87,15 @@ func createACIContainers(ctx context.Context, aciContext store.AciContext, group
 	return err
 }
 
+func getACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) (containerinstance.ContainerGroup, error) {
+	containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
+	if err != nil {
+		return containerinstance.ContainerGroup{}, fmt.Errorf("cannot get container group client: %v", err)
+	}
+
+	return containerGroupsClient.Get(ctx, aciContext.ResourceGroup, containerGroupName)
+}
+
 func deleteACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) (containerinstance.ContainerGroup, error) {
 	containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
 	if err != nil {

+ 58 - 0
azure/backend.go

@@ -8,6 +8,8 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/Azure/go-autorest/autorest/to"
+
 	"github.com/docker/api/context/cloud"
 	"github.com/docker/api/errdefs"
 
@@ -30,6 +32,9 @@ const singleContainerName = "single--container--aci"
 // ErrNoSuchContainer is returned when the mentioned container does not exist
 var ErrNoSuchContainer = errors.New("no such container")
 
+// ErrTooManyContainers is returned when trying to inspect on multiple containers at once
+var ErrTooManyContainers = errors.New("more than one container in group ID")
+
 func init() {
 	backend.Register("aci", "aci", service, getCloudService)
 }
@@ -239,6 +244,59 @@ func (cs *aciContainerService) Delete(ctx context.Context, containerID string, _
 	return err
 }
 
+func (cs *aciContainerService) Inspect(ctx context.Context, containerID string) (containers.Container, error) {
+	cg, err := getACIContainerGroup(ctx, cs.ctx, containerID)
+	if err != nil {
+		return containers.Container{}, err
+	}
+	if cg.StatusCode == http.StatusNoContent {
+		return containers.Container{}, ErrNoSuchContainer
+	}
+
+	if cg.Containers != nil && len(*cg.Containers) > 1 {
+		return containers.Container{}, ErrTooManyContainers
+	}
+
+	return containerGroupToContainer(cg)
+}
+
+func containerGroupToContainer(cg containerinstance.ContainerGroup) (containers.Container, error) {
+	status := "unavailable"
+	cc := (*cg.Containers)[0]
+	if cc.InstanceView != nil &&
+		cc.InstanceView.CurrentState != nil &&
+		cc.InstanceView.CurrentState.State != nil {
+		status = to.String(cc.InstanceView.CurrentState.State)
+	}
+
+	memLimits := -1.
+	if cc.Resources != nil &&
+		cc.Resources.Limits != nil &&
+		cc.Resources.Limits.MemoryInGB != nil {
+		memLimits = *cc.Resources.Limits.MemoryInGB
+	}
+
+	command := ""
+	if cc.Command != nil {
+		command = strings.Join(*cc.Command, "")
+	}
+	c := containers.Container{
+		ID:          to.String(cg.Name),
+		Status:      status,
+		Image:       to.String(cc.Image),
+		Command:     command,
+		CPUTime:     0,
+		MemoryUsage: 0,
+		MemoryLimit: uint64(memLimits),
+		PidsCurrent: 0,
+		PidsLimit:   0,
+		Labels:      nil,
+		Ports:       convert.ToPorts(cg.IPAddress, *cc.Ports),
+	}
+
+	return c, nil
+}
+
 type aciComposeService struct {
 	ctx store.AciContext
 }

+ 44 - 0
cli/cmd/inspect.go

@@ -0,0 +1,44 @@
+package cmd
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+
+	"github.com/pkg/errors"
+	"github.com/spf13/cobra"
+
+	"github.com/docker/api/client"
+)
+
+// RmCommand deletes containers
+func InspectCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "inspect",
+		Short: "Inspect containers",
+		Args:  cobra.ExactArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return runInspect(cmd.Context(), args[0])
+		},
+	}
+
+	return cmd
+}
+
+func runInspect(ctx context.Context, id string) error {
+	c, err := client.New(ctx)
+	if err != nil {
+		return errors.Wrap(err, "cannot connect to backend")
+	}
+
+	container, err := c.ContainerService().Inspect(ctx, id)
+	if err != nil {
+		return err
+	}
+
+	b, err := json.MarshalIndent(container, "", "  ")
+	containerString := string(b)
+	fmt.Println(containerString)
+
+	return nil
+}

+ 1 - 0
cli/main.go

@@ -118,6 +118,7 @@ func main() {
 		cmd.ExecCommand(),
 		cmd.LogsCommand(),
 		cmd.RmCommand(),
+		cmd.InspectCommand(),
 		compose.Command(),
 		login.Command(),
 		cmd.VersionCommand(),

+ 2 - 0
containers/api.go

@@ -67,4 +67,6 @@ type Service interface {
 	Logs(ctx context.Context, containerName string, request LogsRequest) error
 	// Delete removes containers
 	Delete(ctx context.Context, id string, force bool) error
+	// Inspect get a specific container
+	Inspect(ctx context.Context, id string) (Container, error)
 }

+ 7 - 0
example/backend.go

@@ -36,6 +36,13 @@ func service(ctx context.Context) (backend.Service, error) {
 
 type containerService struct{}
 
+func (cs *containerService) Inspect(ctx context.Context, id string) (containers.Container, error) {
+	return containers.Container{
+		ID:    "id",
+		Image: "nginx",
+	}, nil
+}
+
 func (cs *containerService) List(ctx context.Context, all bool) ([]containers.Container, error) {
 	result := []containers.Container{
 		{

+ 1 - 1
go.mod

@@ -4,7 +4,7 @@ go 1.14
 
 require (
 	github.com/AlecAivazis/survey/v2 v2.0.7
-	github.com/Azure/azure-sdk-for-go v42.3.0+incompatible
+	github.com/Azure/azure-sdk-for-go v43.1.0+incompatible
 	github.com/Azure/azure-storage-file-go v0.7.0
 	github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
 	github.com/Azure/go-autorest/autorest v0.10.2

+ 3 - 0
go.sum

@@ -4,8 +4,11 @@ github.com/AlecAivazis/survey/v2 v2.0.7 h1:+f825XHLse/hWd2tE/V5df04WFGimk34Eyg/z
 github.com/AlecAivazis/survey/v2 v2.0.7/go.mod h1:mlizQTaPjnR4jcpwRSaSlkbsRfYFEyKgLQvYTzxxiHA=
 github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo=
 github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
+github.com/Azure/azure-sdk-for-go v0.2.0-beta h1:wYBqYNMWr0WL2lcEZi+dlK9n+N0wJ0Pjs4BKeOnDjfQ=
 github.com/Azure/azure-sdk-for-go v42.3.0+incompatible h1:PAHkmPqd/vQV4LJcqzEUM1elCyTMWjbrO8oFMl0dvBE=
 github.com/Azure/azure-sdk-for-go v42.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v43.1.0+incompatible h1:m6EAp2Dmb8/t+ToZ2jtmvdp+JBwsdfSlZuBV31WGLGQ=
+github.com/Azure/azure-sdk-for-go v43.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-storage-file-go v0.7.0 h1:yWoV0MYwzmoSgWACcVkdPolvAULFPNamcQLpIvS/Et4=
 github.com/Azure/azure-storage-file-go v0.7.0/go.mod h1:3w3mufGcMjcOJ3w+4Gs+5wsSgkT7xDwWWqMMIrXtW4c=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=

+ 26 - 0
local/backend.go

@@ -5,6 +5,7 @@ import (
 	"context"
 	"io"
 	"strconv"
+	"strings"
 	"time"
 
 	"github.com/docker/docker/pkg/stringid"
@@ -51,6 +52,31 @@ func (ms *local) ComposeService() compose.Service {
 	return nil
 }
 
+func (ms *local) Inspect(ctx context.Context, id string) (containers.Container, error) {
+	c, err := ms.apiClient.ContainerInspect(ctx, id)
+	if err != nil {
+		return containers.Container{}, err
+	}
+
+	status := ""
+	if c.State != nil {
+		status = c.State.Status
+	}
+
+	command := ""
+	if c.Config != nil &&
+		c.Config.Cmd != nil {
+		command = strings.Join(c.Config.Cmd, " ")
+	}
+
+	return containers.Container{
+		ID:      stringid.TruncateID(c.ID),
+		Status:  status,
+		Image:   c.Path + "@" + c.Image,
+		Command: command,
+	}, nil
+}
+
 func (ms *local) List(ctx context.Context, all bool) ([]containers.Container, error) {
 	css, err := ms.apiClient.ContainerList(ctx, types.ContainerListOptions{
 		All: all,

+ 1 - 1
protos/compose/v1/compose.pb.go

@@ -26,7 +26,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.22.0
+// 	protoc-gen-go v1.24.0
 // 	protoc        v3.11.2
 // source: protos/compose/v1/compose.proto
 

+ 349 - 175
protos/containers/v1/containers.pb.go

@@ -26,7 +26,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.22.0
+// 	protoc-gen-go v1.24.0
 // 	protoc        v3.11.2
 // source: protos/containers/v1/containers.proto
 
@@ -253,6 +253,100 @@ func (x *Container) GetPorts() []*Port {
 	return nil
 }
 
+type InspectRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *InspectRequest) Reset() {
+	*x = InspectRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *InspectRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InspectRequest) ProtoMessage() {}
+
+func (x *InspectRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InspectRequest.ProtoReflect.Descriptor instead.
+func (*InspectRequest) Descriptor() ([]byte, []int) {
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *InspectRequest) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+type InspectResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Container *Container `protobuf:"bytes,1,opt,name=container,proto3" json:"container,omitempty"`
+}
+
+func (x *InspectResponse) Reset() {
+	*x = InspectResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *InspectResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InspectResponse) ProtoMessage() {}
+
+func (x *InspectResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InspectResponse.ProtoReflect.Descriptor instead.
+func (*InspectResponse) Descriptor() ([]byte, []int) {
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *InspectResponse) GetContainer() *Container {
+	if x != nil {
+		return x.Container
+	}
+	return nil
+}
+
 type DeleteRequest struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -265,7 +359,7 @@ type DeleteRequest struct {
 func (x *DeleteRequest) Reset() {
 	*x = DeleteRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[2]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[4]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -278,7 +372,7 @@ func (x *DeleteRequest) String() string {
 func (*DeleteRequest) ProtoMessage() {}
 
 func (x *DeleteRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[2]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[4]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -291,7 +385,7 @@ func (x *DeleteRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead.
 func (*DeleteRequest) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{2}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *DeleteRequest) GetId() string {
@@ -317,7 +411,7 @@ type DeleteResponse struct {
 func (x *DeleteResponse) Reset() {
 	*x = DeleteResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[3]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[5]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -330,7 +424,7 @@ func (x *DeleteResponse) String() string {
 func (*DeleteResponse) ProtoMessage() {}
 
 func (x *DeleteResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[3]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[5]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -343,7 +437,7 @@ func (x *DeleteResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead.
 func (*DeleteResponse) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{3}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{5}
 }
 
 type StopRequest struct {
@@ -358,7 +452,7 @@ type StopRequest struct {
 func (x *StopRequest) Reset() {
 	*x = StopRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[4]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[6]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -371,7 +465,7 @@ func (x *StopRequest) String() string {
 func (*StopRequest) ProtoMessage() {}
 
 func (x *StopRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[4]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[6]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -384,7 +478,7 @@ func (x *StopRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use StopRequest.ProtoReflect.Descriptor instead.
 func (*StopRequest) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{4}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *StopRequest) GetId() string {
@@ -410,7 +504,7 @@ type StopResponse struct {
 func (x *StopResponse) Reset() {
 	*x = StopResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[5]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[7]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -423,7 +517,7 @@ func (x *StopResponse) String() string {
 func (*StopResponse) ProtoMessage() {}
 
 func (x *StopResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[5]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[7]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -436,7 +530,7 @@ func (x *StopResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use StopResponse.ProtoReflect.Descriptor instead.
 func (*StopResponse) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{5}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{7}
 }
 
 type RunRequest struct {
@@ -454,7 +548,7 @@ type RunRequest struct {
 func (x *RunRequest) Reset() {
 	*x = RunRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[6]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[8]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -467,7 +561,7 @@ func (x *RunRequest) String() string {
 func (*RunRequest) ProtoMessage() {}
 
 func (x *RunRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[6]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[8]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -480,7 +574,7 @@ func (x *RunRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RunRequest.ProtoReflect.Descriptor instead.
 func (*RunRequest) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{6}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *RunRequest) GetId() string {
@@ -527,7 +621,7 @@ type RunResponse struct {
 func (x *RunResponse) Reset() {
 	*x = RunResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[7]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[9]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -540,7 +634,7 @@ func (x *RunResponse) String() string {
 func (*RunResponse) ProtoMessage() {}
 
 func (x *RunResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[7]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[9]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -553,7 +647,7 @@ func (x *RunResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use RunResponse.ProtoReflect.Descriptor instead.
 func (*RunResponse) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{7}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{9}
 }
 
 type ExecRequest struct {
@@ -572,7 +666,7 @@ type ExecRequest struct {
 func (x *ExecRequest) Reset() {
 	*x = ExecRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[8]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -585,7 +679,7 @@ func (x *ExecRequest) String() string {
 func (*ExecRequest) ProtoMessage() {}
 
 func (x *ExecRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[8]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -598,7 +692,7 @@ func (x *ExecRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ExecRequest.ProtoReflect.Descriptor instead.
 func (*ExecRequest) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{8}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *ExecRequest) GetId() string {
@@ -654,7 +748,7 @@ type ExecResponse struct {
 func (x *ExecResponse) Reset() {
 	*x = ExecResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[9]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -667,7 +761,7 @@ func (x *ExecResponse) String() string {
 func (*ExecResponse) ProtoMessage() {}
 
 func (x *ExecResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[9]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -680,7 +774,7 @@ func (x *ExecResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ExecResponse.ProtoReflect.Descriptor instead.
 func (*ExecResponse) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{9}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *ExecResponse) GetOutput() []byte {
@@ -701,7 +795,7 @@ type ListRequest struct {
 func (x *ListRequest) Reset() {
 	*x = ListRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[10]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[12]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -714,7 +808,7 @@ func (x *ListRequest) String() string {
 func (*ListRequest) ProtoMessage() {}
 
 func (x *ListRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[10]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[12]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -727,7 +821,7 @@ func (x *ListRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListRequest.ProtoReflect.Descriptor instead.
 func (*ListRequest) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{10}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{12}
 }
 
 func (x *ListRequest) GetAll() bool {
@@ -748,7 +842,7 @@ type ListResponse struct {
 func (x *ListResponse) Reset() {
 	*x = ListResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[11]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[13]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -761,7 +855,7 @@ func (x *ListResponse) String() string {
 func (*ListResponse) ProtoMessage() {}
 
 func (x *ListResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[11]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[13]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -774,7 +868,7 @@ func (x *ListResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ListResponse.ProtoReflect.Descriptor instead.
 func (*ListResponse) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{11}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *ListResponse) GetContainers() []*Container {
@@ -796,7 +890,7 @@ type LogsRequest struct {
 func (x *LogsRequest) Reset() {
 	*x = LogsRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[12]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[14]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -809,7 +903,7 @@ func (x *LogsRequest) String() string {
 func (*LogsRequest) ProtoMessage() {}
 
 func (x *LogsRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[12]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[14]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -822,7 +916,7 @@ func (x *LogsRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LogsRequest.ProtoReflect.Descriptor instead.
 func (*LogsRequest) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{12}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *LogsRequest) GetContainerId() string {
@@ -850,7 +944,7 @@ type LogsResponse struct {
 func (x *LogsResponse) Reset() {
 	*x = LogsResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_containers_v1_containers_proto_msgTypes[13]
+		mi := &file_protos_containers_v1_containers_proto_msgTypes[15]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -863,7 +957,7 @@ func (x *LogsResponse) String() string {
 func (*LogsResponse) ProtoMessage() {}
 
 func (x *LogsResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_containers_v1_containers_proto_msgTypes[13]
+	mi := &file_protos_containers_v1_containers_proto_msgTypes[15]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -876,7 +970,7 @@ func (x *LogsResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LogsResponse.ProtoReflect.Descriptor instead.
 func (*LogsResponse) Descriptor() ([]byte, []int) {
-	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{13}
+	return file_protos_containers_v1_containers_proto_rawDescGZIP(), []int{15}
 }
 
 func (x *LogsResponse) GetValue() []byte {
@@ -924,107 +1018,122 @@ var file_protos_containers_v1_containers_proto_rawDesc = []byte{
 	0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70,
 	0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73,
 	0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x22,
-	0x35, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
-	0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
-	0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x70,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f,
-	0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
-	0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x22, 0x9d, 0x02, 0x0a, 0x0a, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
-	0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18,
-	0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b,
-	0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f,
-	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74,
-	0x52, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x53, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c,
-	0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f,
+	0x20, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
+	0x64, 0x22, 0x5f, 0x0a, 0x0f, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+	0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f,
 	0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
-	0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75,
-	0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45,
-	0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x18, 0x0a, 0x07,
-	0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x76,
-	0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
-	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
-	0x01, 0x22, 0x0d, 0x0a, 0x0b, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x22, 0x8c, 0x01, 0x0a, 0x0b, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
-	0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74,
-	0x72, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73,
-	0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18,
-	0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x65,
-	0x6e, 0x76, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x10, 0x0a,
-	0x03, 0x74, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x74, 0x79, 0x22,
-	0x26, 0x0a, 0x0c, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
-	0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
-	0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x1f, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x22, 0x5e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74,
-	0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63,
-	0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e,
-	0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x0a, 0x63, 0x6f,
-	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x48, 0x0a, 0x0b, 0x4c, 0x6f, 0x67, 0x73,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61,
-	0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63,
-	0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f,
-	0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x6c,
-	0x6f, 0x77, 0x22, 0x24, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x9f, 0x05, 0x0a, 0x0a, 0x43, 0x6f, 0x6e,
-	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x6b, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12,
+	0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f,
+	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+	0x65, 0x72, 0x22, 0x35, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c,
+	0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x0a, 0x0b, 0x53,
+	0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69,
+	0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x69, 0x6d,
+	0x65, 0x6f, 0x75, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9d, 0x02, 0x0a, 0x0a, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x05, 0x70, 0x6f, 0x72,
+	0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64,
+	0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+	0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50,
+	0x6f, 0x72, 0x74, 0x52, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x53, 0x0a, 0x06, 0x6c, 0x61,
+	0x62, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x63, 0x6f, 0x6d,
+	0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31,
+	0x2e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65,
+	0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12,
+	0x18, 0x0a, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62,
+	0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x22, 0x0d, 0x0a, 0x0b, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x22, 0x8c, 0x01, 0x0a, 0x0b, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x1b, 0x0a,
+	0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72,
+	0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x10,
+	0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x76,
+	0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74,
+	0x74, 0x79, 0x22, 0x26, 0x0a, 0x0c, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x1f, 0x0a, 0x0b, 0x4c, 0x69,
+	0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x22, 0x5e, 0x0a, 0x0c, 0x4c,
+	0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0a, 0x63,
+	0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x2e, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+	0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52,
+	0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x48, 0x0a, 0x0b, 0x4c,
+	0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f,
+	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a,
+	0x06, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x66,
+	0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x22, 0x24, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x95, 0x06, 0x0a, 0x0a,
+	0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x6b, 0x0a, 0x04, 0x4c, 0x69,
+	0x73, 0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e,
+	0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+	0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65,
+	0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e,
+	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12,
 	0x30, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
 	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
-	0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
 	0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61,
 	0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
-	0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x30, 0x2e, 0x63,
+	0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x03, 0x52, 0x75, 0x6e, 0x12, 0x2f, 0x2e, 0x63, 0x6f,
+	0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76,
+	0x31, 0x2e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63,
 	0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72,
 	0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e,
-	0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31,
-	0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
-	0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x12, 0x68, 0x0a, 0x03, 0x52, 0x75, 0x6e, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64,
+	0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b,
+	0x0a, 0x04, 0x45, 0x78, 0x65, 0x63, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63,
+	0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63,
+	0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65,
+	0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64,
 	0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
-	0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52,
-	0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6d, 0x2e,
-	0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e,
-	0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x04, 0x45,
-	0x78, 0x65, 0x63, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72,
+	0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45,
+	0x78, 0x65, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x04, 0x4c,
+	0x6f, 0x67, 0x73, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72,
 	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
-	0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65,
+	0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65,
 	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b,
 	0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f,
-	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x04, 0x4c, 0x6f, 0x67, 0x73,
-	0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70,
-	0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
-	0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e,
-	0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61,
-	0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73,
-	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x71, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74,
-	0x65, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61,
-	0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
-	0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b,
-	0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f,
-	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65,
-	0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69,
-	0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2f,
-	0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61,
-	0x69, 0x6e, 0x65, 0x72, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x73,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x71, 0x0a, 0x06, 0x44, 0x65,
+	0x6c, 0x65, 0x74, 0x65, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65,
+	0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e,
+	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
+	0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64,
+	0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+	0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44,
+	0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x74, 0x0a,
+	0x07, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x64,
+	0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+	0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49,
+	0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73,
+	0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+	0x6d, 0x2f, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2f, 0x76,
+	0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -1039,46 +1148,51 @@ func file_protos_containers_v1_containers_proto_rawDescGZIP() []byte {
 	return file_protos_containers_v1_containers_proto_rawDescData
 }
 
-var file_protos_containers_v1_containers_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
+var file_protos_containers_v1_containers_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
 var file_protos_containers_v1_containers_proto_goTypes = []interface{}{
-	(*Port)(nil),           // 0: com.docker.api.protos.containers.v1.Port
-	(*Container)(nil),      // 1: com.docker.api.protos.containers.v1.Container
-	(*DeleteRequest)(nil),  // 2: com.docker.api.protos.containers.v1.DeleteRequest
-	(*DeleteResponse)(nil), // 3: com.docker.api.protos.containers.v1.DeleteResponse
-	(*StopRequest)(nil),    // 4: com.docker.api.protos.containers.v1.StopRequest
-	(*StopResponse)(nil),   // 5: com.docker.api.protos.containers.v1.StopResponse
-	(*RunRequest)(nil),     // 6: com.docker.api.protos.containers.v1.RunRequest
-	(*RunResponse)(nil),    // 7: com.docker.api.protos.containers.v1.RunResponse
-	(*ExecRequest)(nil),    // 8: com.docker.api.protos.containers.v1.ExecRequest
-	(*ExecResponse)(nil),   // 9: com.docker.api.protos.containers.v1.ExecResponse
-	(*ListRequest)(nil),    // 10: com.docker.api.protos.containers.v1.ListRequest
-	(*ListResponse)(nil),   // 11: com.docker.api.protos.containers.v1.ListResponse
-	(*LogsRequest)(nil),    // 12: com.docker.api.protos.containers.v1.LogsRequest
-	(*LogsResponse)(nil),   // 13: com.docker.api.protos.containers.v1.LogsResponse
-	nil,                    // 14: com.docker.api.protos.containers.v1.RunRequest.LabelsEntry
+	(*Port)(nil),            // 0: com.docker.api.protos.containers.v1.Port
+	(*Container)(nil),       // 1: com.docker.api.protos.containers.v1.Container
+	(*InspectRequest)(nil),  // 2: com.docker.api.protos.containers.v1.InspectRequest
+	(*InspectResponse)(nil), // 3: com.docker.api.protos.containers.v1.InspectResponse
+	(*DeleteRequest)(nil),   // 4: com.docker.api.protos.containers.v1.DeleteRequest
+	(*DeleteResponse)(nil),  // 5: com.docker.api.protos.containers.v1.DeleteResponse
+	(*StopRequest)(nil),     // 6: com.docker.api.protos.containers.v1.StopRequest
+	(*StopResponse)(nil),    // 7: com.docker.api.protos.containers.v1.StopResponse
+	(*RunRequest)(nil),      // 8: com.docker.api.protos.containers.v1.RunRequest
+	(*RunResponse)(nil),     // 9: com.docker.api.protos.containers.v1.RunResponse
+	(*ExecRequest)(nil),     // 10: com.docker.api.protos.containers.v1.ExecRequest
+	(*ExecResponse)(nil),    // 11: com.docker.api.protos.containers.v1.ExecResponse
+	(*ListRequest)(nil),     // 12: com.docker.api.protos.containers.v1.ListRequest
+	(*ListResponse)(nil),    // 13: com.docker.api.protos.containers.v1.ListResponse
+	(*LogsRequest)(nil),     // 14: com.docker.api.protos.containers.v1.LogsRequest
+	(*LogsResponse)(nil),    // 15: com.docker.api.protos.containers.v1.LogsResponse
+	nil,                     // 16: com.docker.api.protos.containers.v1.RunRequest.LabelsEntry
 }
 var file_protos_containers_v1_containers_proto_depIdxs = []int32{
 	0,  // 0: com.docker.api.protos.containers.v1.Container.ports:type_name -> com.docker.api.protos.containers.v1.Port
-	0,  // 1: com.docker.api.protos.containers.v1.RunRequest.ports:type_name -> com.docker.api.protos.containers.v1.Port
-	14, // 2: com.docker.api.protos.containers.v1.RunRequest.labels:type_name -> com.docker.api.protos.containers.v1.RunRequest.LabelsEntry
-	1,  // 3: com.docker.api.protos.containers.v1.ListResponse.containers:type_name -> com.docker.api.protos.containers.v1.Container
-	10, // 4: com.docker.api.protos.containers.v1.Containers.List:input_type -> com.docker.api.protos.containers.v1.ListRequest
-	4,  // 5: com.docker.api.protos.containers.v1.Containers.Stop:input_type -> com.docker.api.protos.containers.v1.StopRequest
-	6,  // 6: com.docker.api.protos.containers.v1.Containers.Run:input_type -> com.docker.api.protos.containers.v1.RunRequest
-	8,  // 7: com.docker.api.protos.containers.v1.Containers.Exec:input_type -> com.docker.api.protos.containers.v1.ExecRequest
-	12, // 8: com.docker.api.protos.containers.v1.Containers.Logs:input_type -> com.docker.api.protos.containers.v1.LogsRequest
-	2,  // 9: com.docker.api.protos.containers.v1.Containers.Delete:input_type -> com.docker.api.protos.containers.v1.DeleteRequest
-	11, // 10: com.docker.api.protos.containers.v1.Containers.List:output_type -> com.docker.api.protos.containers.v1.ListResponse
-	5,  // 11: com.docker.api.protos.containers.v1.Containers.Stop:output_type -> com.docker.api.protos.containers.v1.StopResponse
-	7,  // 12: com.docker.api.protos.containers.v1.Containers.Run:output_type -> com.docker.api.protos.containers.v1.RunResponse
-	9,  // 13: com.docker.api.protos.containers.v1.Containers.Exec:output_type -> com.docker.api.protos.containers.v1.ExecResponse
-	13, // 14: com.docker.api.protos.containers.v1.Containers.Logs:output_type -> com.docker.api.protos.containers.v1.LogsResponse
-	3,  // 15: com.docker.api.protos.containers.v1.Containers.Delete:output_type -> com.docker.api.protos.containers.v1.DeleteResponse
-	10, // [10:16] is the sub-list for method output_type
-	4,  // [4:10] is the sub-list for method input_type
-	4,  // [4:4] is the sub-list for extension type_name
-	4,  // [4:4] is the sub-list for extension extendee
-	0,  // [0:4] is the sub-list for field type_name
+	1,  // 1: com.docker.api.protos.containers.v1.InspectResponse.container:type_name -> com.docker.api.protos.containers.v1.Container
+	0,  // 2: com.docker.api.protos.containers.v1.RunRequest.ports:type_name -> com.docker.api.protos.containers.v1.Port
+	16, // 3: com.docker.api.protos.containers.v1.RunRequest.labels:type_name -> com.docker.api.protos.containers.v1.RunRequest.LabelsEntry
+	1,  // 4: com.docker.api.protos.containers.v1.ListResponse.containers:type_name -> com.docker.api.protos.containers.v1.Container
+	12, // 5: com.docker.api.protos.containers.v1.Containers.List:input_type -> com.docker.api.protos.containers.v1.ListRequest
+	6,  // 6: com.docker.api.protos.containers.v1.Containers.Stop:input_type -> com.docker.api.protos.containers.v1.StopRequest
+	8,  // 7: com.docker.api.protos.containers.v1.Containers.Run:input_type -> com.docker.api.protos.containers.v1.RunRequest
+	10, // 8: com.docker.api.protos.containers.v1.Containers.Exec:input_type -> com.docker.api.protos.containers.v1.ExecRequest
+	14, // 9: com.docker.api.protos.containers.v1.Containers.Logs:input_type -> com.docker.api.protos.containers.v1.LogsRequest
+	4,  // 10: com.docker.api.protos.containers.v1.Containers.Delete:input_type -> com.docker.api.protos.containers.v1.DeleteRequest
+	2,  // 11: com.docker.api.protos.containers.v1.Containers.Inspect:input_type -> com.docker.api.protos.containers.v1.InspectRequest
+	13, // 12: com.docker.api.protos.containers.v1.Containers.List:output_type -> com.docker.api.protos.containers.v1.ListResponse
+	7,  // 13: com.docker.api.protos.containers.v1.Containers.Stop:output_type -> com.docker.api.protos.containers.v1.StopResponse
+	9,  // 14: com.docker.api.protos.containers.v1.Containers.Run:output_type -> com.docker.api.protos.containers.v1.RunResponse
+	11, // 15: com.docker.api.protos.containers.v1.Containers.Exec:output_type -> com.docker.api.protos.containers.v1.ExecResponse
+	15, // 16: com.docker.api.protos.containers.v1.Containers.Logs:output_type -> com.docker.api.protos.containers.v1.LogsResponse
+	5,  // 17: com.docker.api.protos.containers.v1.Containers.Delete:output_type -> com.docker.api.protos.containers.v1.DeleteResponse
+	3,  // 18: com.docker.api.protos.containers.v1.Containers.Inspect:output_type -> com.docker.api.protos.containers.v1.InspectResponse
+	12, // [12:19] is the sub-list for method output_type
+	5,  // [5:12] is the sub-list for method input_type
+	5,  // [5:5] is the sub-list for extension type_name
+	5,  // [5:5] is the sub-list for extension extendee
+	0,  // [0:5] is the sub-list for field type_name
 }
 
 func init() { file_protos_containers_v1_containers_proto_init() }
@@ -1112,7 +1226,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DeleteRequest); i {
+			switch v := v.(*InspectRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1124,7 +1238,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DeleteResponse); i {
+			switch v := v.(*InspectResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1136,7 +1250,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*StopRequest); i {
+			switch v := v.(*DeleteRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1148,7 +1262,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*StopResponse); i {
+			switch v := v.(*DeleteResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1160,7 +1274,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*RunRequest); i {
+			switch v := v.(*StopRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1172,7 +1286,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*RunResponse); i {
+			switch v := v.(*StopResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1184,7 +1298,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ExecRequest); i {
+			switch v := v.(*RunRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1196,7 +1310,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ExecResponse); i {
+			switch v := v.(*RunResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1208,7 +1322,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ListRequest); i {
+			switch v := v.(*ExecRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1220,7 +1334,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ListResponse); i {
+			switch v := v.(*ExecResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1232,7 +1346,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*LogsRequest); i {
+			switch v := v.(*ListRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1244,6 +1358,30 @@ func file_protos_containers_v1_containers_proto_init() {
 			}
 		}
 		file_protos_containers_v1_containers_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ListResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protos_containers_v1_containers_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*LogsRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protos_containers_v1_containers_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*LogsResponse); i {
 			case 0:
 				return &v.state
@@ -1262,7 +1400,7 @@ func file_protos_containers_v1_containers_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_protos_containers_v1_containers_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   15,
+			NumMessages:   17,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
@@ -1294,6 +1432,7 @@ type ContainersClient interface {
 	Exec(ctx context.Context, in *ExecRequest, opts ...grpc.CallOption) (*ExecResponse, error)
 	Logs(ctx context.Context, in *LogsRequest, opts ...grpc.CallOption) (Containers_LogsClient, error)
 	Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error)
+	Inspect(ctx context.Context, in *InspectRequest, opts ...grpc.CallOption) (*InspectResponse, error)
 }
 
 type containersClient struct {
@@ -1381,6 +1520,15 @@ func (c *containersClient) Delete(ctx context.Context, in *DeleteRequest, opts .
 	return out, nil
 }
 
+func (c *containersClient) Inspect(ctx context.Context, in *InspectRequest, opts ...grpc.CallOption) (*InspectResponse, error) {
+	out := new(InspectResponse)
+	err := c.cc.Invoke(ctx, "/com.docker.api.protos.containers.v1.Containers/Inspect", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 // ContainersServer is the server API for Containers service.
 type ContainersServer interface {
 	List(context.Context, *ListRequest) (*ListResponse, error)
@@ -1389,6 +1537,7 @@ type ContainersServer interface {
 	Exec(context.Context, *ExecRequest) (*ExecResponse, error)
 	Logs(*LogsRequest, Containers_LogsServer) error
 	Delete(context.Context, *DeleteRequest) (*DeleteResponse, error)
+	Inspect(context.Context, *InspectRequest) (*InspectResponse, error)
 }
 
 // UnimplementedContainersServer can be embedded to have forward compatible implementations.
@@ -1413,6 +1562,9 @@ func (*UnimplementedContainersServer) Logs(*LogsRequest, Containers_LogsServer)
 func (*UnimplementedContainersServer) Delete(context.Context, *DeleteRequest) (*DeleteResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
 }
+func (*UnimplementedContainersServer) Inspect(context.Context, *InspectRequest) (*InspectResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Inspect not implemented")
+}
 
 func RegisterContainersServer(s *grpc.Server, srv ContainersServer) {
 	s.RegisterService(&_Containers_serviceDesc, srv)
@@ -1529,6 +1681,24 @@ func _Containers_Delete_Handler(srv interface{}, ctx context.Context, dec func(i
 	return interceptor(ctx, in, info, handler)
 }
 
+func _Containers_Inspect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(InspectRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ContainersServer).Inspect(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/com.docker.api.protos.containers.v1.Containers/Inspect",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ContainersServer).Inspect(ctx, req.(*InspectRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 var _Containers_serviceDesc = grpc.ServiceDesc{
 	ServiceName: "com.docker.api.protos.containers.v1.Containers",
 	HandlerType: (*ContainersServer)(nil),
@@ -1553,6 +1723,10 @@ var _Containers_serviceDesc = grpc.ServiceDesc{
 			MethodName: "Delete",
 			Handler:    _Containers_Delete_Handler,
 		},
+		{
+			MethodName: "Inspect",
+			Handler:    _Containers_Inspect_Handler,
+		},
 	},
 	Streams: []grpc.StreamDesc{
 		{

+ 51 - 42
protos/containers/v1/containers.proto

@@ -32,88 +32,97 @@ package com.docker.api.protos.containers.v1;
 option go_package = "github.com/docker/api/protos/containers/v1;v1";
 
 service Containers {
-	rpc List(ListRequest) returns (ListResponse);
-	rpc Stop(StopRequest) returns (StopResponse);
-	rpc Run(RunRequest) returns (RunResponse);
-	rpc Exec(ExecRequest) returns (ExecResponse);
-	rpc Logs(LogsRequest) returns (stream LogsResponse);
-	rpc Delete(DeleteRequest) returns (DeleteResponse);
+  rpc List(ListRequest) returns (ListResponse);
+  rpc Stop(StopRequest) returns (StopResponse);
+  rpc Run(RunRequest) returns (RunResponse);
+  rpc Exec(ExecRequest) returns (ExecResponse);
+  rpc Logs(LogsRequest) returns (stream LogsResponse);
+  rpc Delete(DeleteRequest) returns (DeleteResponse);
+  rpc Inspect(InspectRequest) returns (InspectResponse);
 }
 
 message Port {
-	uint32 host_port = 1;
-	uint32 container_port = 2;
-	string protocol = 3;
-	string host_ip = 4;
+  uint32 host_port = 1;
+  uint32 container_port = 2;
+  string protocol = 3;
+  string host_ip = 4;
 }
 
 message Container {
-	string id = 1;
-	string image = 2;
-	string status = 3;
-	string command = 4;
-	uint64 cpu_time = 5;
-	uint64 memory_usage = 6;
-	uint64 memory_limit = 7;
-	uint64 pids_current = 8;
-	uint64 pids_limit = 9;
-	repeated string labels = 10;
-	repeated Port ports = 11;
+  string id = 1;
+  string image = 2;
+  string status = 3;
+  string command = 4;
+  uint64 cpu_time = 5;
+  uint64 memory_usage = 6;
+  uint64 memory_limit = 7;
+  uint64 pids_current = 8;
+  uint64 pids_limit = 9;
+  repeated string labels = 10;
+  repeated Port ports = 11;
+}
+
+message InspectRequest {
+  string id = 1;
+}
+
+message InspectResponse {
+  Container container = 1;
 }
 
 message DeleteRequest {
-	string id = 1;
-	bool force = 2;
+  string id = 1;
+  bool force = 2;
 }
 
 message DeleteResponse {
 }
 
 message StopRequest {
-	string id = 1;
-	uint32 timeout = 2;
+  string id = 1;
+  uint32 timeout = 2;
 }
 
 message StopResponse {
 }
 
 message RunRequest {
-	string id = 1;
-	string image = 2;
-	repeated Port ports = 3;
-	map<string, string> labels = 4;
-	repeated string volumes = 5;
+  string id = 1;
+  string image = 2;
+  repeated Port ports = 3;
+  map<string, string> labels = 4;
+  repeated string volumes = 5;
 }
 
 message RunResponse {
 }
 
 message ExecRequest {
-	string id = 1;
-	string command = 2;
-	string stream_id = 3;
-	repeated string args = 4;
-	repeated string env = 5;
-	bool tty = 6;
+  string id = 1;
+  string command = 2;
+  string stream_id = 3;
+  repeated string args = 4;
+  repeated string env = 5;
+  bool tty = 6;
 }
 
 message ExecResponse {
-	bytes output = 1;
+  bytes output = 1;
 }
 
 message ListRequest {
-	bool all = 1;
+  bool all = 1;
 }
 
 message ListResponse {
-	repeated Container containers = 1;
+  repeated Container containers = 1;
 }
 
 message LogsRequest {
-	string container_id = 1;
-	bool follow = 3;
+  string container_id = 1;
+  bool follow = 3;
 }
 
 message LogsResponse {
-	bytes value = 1;
+  bytes value = 1;
 }

+ 1 - 1
protos/contexts/v1/contexts.pb.go

@@ -26,7 +26,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.22.0
+// 	protoc-gen-go v1.24.0
 // 	protoc        v3.11.2
 // source: protos/contexts/v1/contexts.proto
 

+ 1 - 1
protos/streams/v1/streams.pb.go

@@ -1,6 +1,6 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.22.0
+// 	protoc-gen-go v1.24.0
 // 	protoc        v3.11.2
 // source: protos/streams/v1/streams.proto
 

+ 23 - 0
server/proxy/containers.go

@@ -76,6 +76,29 @@ func (p *proxy) Run(ctx context.Context, request *containersv1.RunRequest) (*con
 	})
 }
 
+func (p *proxy) Inspect(ctx context.Context, request *containersv1.InspectRequest) (*containersv1.InspectResponse, error) {
+	c, err := Client(ctx).ContainerService().Inspect(ctx, request.Id)
+	if err != nil {
+		return nil, err
+	}
+	response := &containersv1.InspectResponse{
+		Container: &containersv1.Container{
+			Id:          c.ID,
+			Image:       c.Image,
+			Status:      c.Status,
+			Command:     c.Command,
+			CpuTime:     c.CPUTime,
+			MemoryUsage: c.MemoryUsage,
+			MemoryLimit: c.MemoryLimit,
+			PidsCurrent: c.PidsCurrent,
+			PidsLimit:   c.PidsLimit,
+			Labels:      c.Labels,
+			Ports:       portsToGrpc(c.Ports),
+		},
+	}
+	return response, err
+}
+
 func (p *proxy) Delete(ctx context.Context, request *containersv1.DeleteRequest) (*containersv1.DeleteResponse, error) {
 	return &containersv1.DeleteResponse{}, Client(ctx).ContainerService().Delete(ctx, request.Id, request.Force)
 }