mirror of https://github.com/docker/compose.git
commit
67fb49c98c
|
@ -8,7 +8,8 @@ ENV GO111MODULE=on
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
docker \
|
docker \
|
||||||
make \
|
make \
|
||||||
protoc
|
protoc \
|
||||||
|
protobuf-dev
|
||||||
COPY go.* .
|
COPY go.* .
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containerd/console"
|
"github.com/containerd/console"
|
||||||
|
@ -41,15 +39,9 @@ func runExec(ctx context.Context, opts execOpts, name string, command string) er
|
||||||
return errors.Wrap(err, "cannot connect to backend")
|
return errors.Wrap(err, "cannot connect to backend")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
con := console.Current()
|
||||||
con console.Console
|
|
||||||
stdout io.Writer
|
|
||||||
)
|
|
||||||
|
|
||||||
stdout = os.Stdout
|
|
||||||
|
|
||||||
if opts.Tty {
|
if opts.Tty {
|
||||||
con = console.Current()
|
|
||||||
if err := con.SetRaw(); err != nil {
|
if err := con.SetRaw(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -58,9 +50,7 @@ func runExec(ctx context.Context, opts execOpts, name string, command string) er
|
||||||
fmt.Println("Unable to close the console")
|
fmt.Println("Unable to close the console")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
stdout = con
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.ContainerService().Exec(ctx, name, command, os.Stdin, stdout)
|
return c.ContainerService().Exec(ctx, name, command, con, con)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
containersv1 "github.com/docker/api/protos/containers/v1"
|
containersv1 "github.com/docker/api/protos/containers/v1"
|
||||||
contextsv1 "github.com/docker/api/protos/contexts/v1"
|
contextsv1 "github.com/docker/api/protos/contexts/v1"
|
||||||
|
streamsv1 "github.com/docker/api/protos/streams/v1"
|
||||||
"github.com/docker/api/server"
|
"github.com/docker/api/server"
|
||||||
"github.com/docker/api/server/proxy"
|
"github.com/docker/api/server/proxy"
|
||||||
)
|
)
|
||||||
|
@ -44,10 +45,11 @@ func runServe(ctx context.Context, opts serveOpts) error {
|
||||||
// nolint errcheck
|
// nolint errcheck
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
p := proxy.NewContainerAPI()
|
p := proxy.New()
|
||||||
contextsService := server.NewContexts()
|
contextsService := server.NewContexts()
|
||||||
|
|
||||||
containersv1.RegisterContainersServer(s, p)
|
containersv1.RegisterContainersServer(s, p)
|
||||||
|
streamsv1.RegisterStreamingServer(s, p)
|
||||||
contextsv1.RegisterContextsServer(s, contextsService)
|
contextsv1.RegisterContextsServer(s, contextsService)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -18,7 +18,7 @@ require (
|
||||||
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
|
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
|
||||||
github.com/compose-spec/compose-go v0.0.0-20200423124427-63dcf8c22cae
|
github.com/compose-spec/compose-go v0.0.0-20200423124427-63dcf8c22cae
|
||||||
github.com/containerd/console v1.0.0
|
github.com/containerd/console v1.0.0
|
||||||
github.com/containerd/containerd v1.3.4 // indirect
|
github.com/containerd/containerd v1.3.4
|
||||||
github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect
|
github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect
|
||||||
github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8
|
github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8
|
||||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||||
|
|
|
@ -138,18 +138,21 @@ func (ms *mobyService) Exec(ctx context.Context, name string, command string, re
|
||||||
cec, err := ms.apiClient.ContainerExecCreate(ctx, name, types.ExecConfig{
|
cec, err := ms.apiClient.ContainerExecCreate(ctx, name, types.ExecConfig{
|
||||||
Cmd: []string{command},
|
Cmd: []string{command},
|
||||||
Tty: true,
|
Tty: true,
|
||||||
AttachStderr: true,
|
|
||||||
AttachStdin: true,
|
AttachStdin: true,
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
|
AttachStderr: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resp, err := ms.apiClient.ContainerExecAttach(ctx, cec.ID, types.ExecStartCheck{})
|
resp, err := ms.apiClient.ContainerExecAttach(ctx, cec.ID, types.ExecStartCheck{
|
||||||
|
Tty: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer resp.Close()
|
defer resp.Close()
|
||||||
|
|
||||||
readChannel := make(chan error, 10)
|
readChannel := make(chan error, 10)
|
||||||
writeChannel := make(chan error, 10)
|
writeChannel := make(chan error, 10)
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -33,14 +33,11 @@ option go_package = "github.com/docker/api/protos/containers/v1;v1";
|
||||||
|
|
||||||
service Containers {
|
service Containers {
|
||||||
rpc List(ListRequest) returns (ListResponse);
|
rpc List(ListRequest) returns (ListResponse);
|
||||||
rpc Create(CreateRequest) returns (CreateResponse);
|
|
||||||
rpc Start(StartRequest) returns (StartResponse);
|
|
||||||
rpc Stop(StopRequest) returns (StopResponse);
|
rpc Stop(StopRequest) returns (StopResponse);
|
||||||
rpc Kill(KillRequest) returns (KillResponse);
|
rpc Run(RunRequest) returns (RunResponse);
|
||||||
rpc Delete(DeleteRequest) returns (DeleteResponse);
|
|
||||||
rpc Update(UpdateRequest) returns (UpdateResponse);
|
|
||||||
rpc Exec(ExecRequest) returns (ExecResponse);
|
rpc Exec(ExecRequest) returns (ExecResponse);
|
||||||
rpc Logs(LogsRequest) returns (stream LogsResponse);
|
rpc Logs(LogsRequest) returns (stream LogsResponse);
|
||||||
|
rpc Delete(DeleteRequest) returns (DeleteResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
message Port {
|
message Port {
|
||||||
|
@ -64,43 +61,6 @@ message Container {
|
||||||
repeated Port ports = 11;
|
repeated Port ports = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreateRequest {
|
|
||||||
string id = 1;
|
|
||||||
repeated string args = 2;
|
|
||||||
repeated string env = 3;
|
|
||||||
bool tty = 4;
|
|
||||||
string image = 5;
|
|
||||||
string hostname = 6;
|
|
||||||
repeated string networks = 7;
|
|
||||||
string snapshotter = 8;
|
|
||||||
string logger = 9;
|
|
||||||
string profile = 10;
|
|
||||||
string restart_status = 11;
|
|
||||||
repeated Mount mounts = 12;
|
|
||||||
string working_dir = 13;
|
|
||||||
map<string, string> labels = 14;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Mount {
|
|
||||||
string type = 1;
|
|
||||||
string source = 2;
|
|
||||||
string destination = 3;
|
|
||||||
repeated string options = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
message CreateResponse {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
message UpdateRequest {
|
|
||||||
string id = 1;
|
|
||||||
string image = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message UpdateResponse {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
message DeleteRequest {
|
message DeleteRequest {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
bool force = 2;
|
bool force = 2;
|
||||||
|
@ -109,15 +69,6 @@ message DeleteRequest {
|
||||||
message DeleteResponse {
|
message DeleteResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
message StartRequest {
|
|
||||||
string id = 1;
|
|
||||||
string stream_id = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message StartResponse {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
message StopRequest {
|
message StopRequest {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
uint32 timeout = 2;
|
uint32 timeout = 2;
|
||||||
|
@ -126,26 +77,28 @@ message StopRequest {
|
||||||
message StopResponse {
|
message StopResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message RunRequest {
|
||||||
|
string id = 1;
|
||||||
|
string image = 2;
|
||||||
|
repeated Port ports = 3;
|
||||||
|
map<string, string> labels = 4;
|
||||||
|
repeated string volumes = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RunResponse {
|
||||||
|
}
|
||||||
|
|
||||||
message ExecRequest {
|
message ExecRequest {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
string stream_id = 2;
|
string command = 2;
|
||||||
repeated string args = 3;
|
string stream_id = 3;
|
||||||
repeated string env = 4;
|
repeated string args = 4;
|
||||||
bool tty = 5;
|
repeated string env = 5;
|
||||||
string working_dir = 6;
|
bool tty = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ExecResponse {
|
message ExecResponse {
|
||||||
|
bytes output = 1;
|
||||||
}
|
|
||||||
|
|
||||||
message KillRequest {
|
|
||||||
string id = 1;
|
|
||||||
int64 signal = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message KillResponse {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListRequest {
|
message ListRequest {
|
||||||
|
@ -158,9 +111,9 @@ message ListResponse {
|
||||||
|
|
||||||
message LogsRequest {
|
message LogsRequest {
|
||||||
string container_id = 1;
|
string container_id = 1;
|
||||||
bool follow = 2;
|
bool follow = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LogsResponse {
|
message LogsResponse {
|
||||||
bytes logs = 1;
|
bytes value = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,480 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.22.0
|
||||||
|
// protoc v3.11.2
|
||||||
|
// source: protos/streams/v1/streams.proto
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
|
any "github.com/golang/protobuf/ptypes/any"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
|
type IOStream int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
IOStream_STDIN IOStream = 0
|
||||||
|
IOStream_STDOUT IOStream = 1
|
||||||
|
IOStream_STDERR IOStream = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for IOStream.
|
||||||
|
var (
|
||||||
|
IOStream_name = map[int32]string{
|
||||||
|
0: "STDIN",
|
||||||
|
1: "STDOUT",
|
||||||
|
2: "STDERR",
|
||||||
|
}
|
||||||
|
IOStream_value = map[string]int32{
|
||||||
|
"STDIN": 0,
|
||||||
|
"STDOUT": 1,
|
||||||
|
"STDERR": 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x IOStream) Enum() *IOStream {
|
||||||
|
p := new(IOStream)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x IOStream) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (IOStream) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_protos_streams_v1_streams_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (IOStream) Type() protoreflect.EnumType {
|
||||||
|
return &file_protos_streams_v1_streams_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x IOStream) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use IOStream.Descriptor instead.
|
||||||
|
func (IOStream) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_protos_streams_v1_streams_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type BytesMessage struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Type IOStream `protobuf:"varint,1,opt,name=type,proto3,enum=com.docker.api.protos.streams.v1.IOStream" json:"type,omitempty"`
|
||||||
|
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BytesMessage) Reset() {
|
||||||
|
*x = BytesMessage{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_protos_streams_v1_streams_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BytesMessage) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*BytesMessage) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *BytesMessage) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_protos_streams_v1_streams_proto_msgTypes[0]
|
||||||
|
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 BytesMessage.ProtoReflect.Descriptor instead.
|
||||||
|
func (*BytesMessage) Descriptor() ([]byte, []int) {
|
||||||
|
return file_protos_streams_v1_streams_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BytesMessage) GetType() IOStream {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return IOStream_STDIN
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BytesMessage) GetValue() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResizeMessage struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Width uint32 `protobuf:"varint,1,opt,name=width,proto3" json:"width,omitempty"`
|
||||||
|
Height uint32 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ResizeMessage) Reset() {
|
||||||
|
*x = ResizeMessage{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_protos_streams_v1_streams_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ResizeMessage) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ResizeMessage) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ResizeMessage) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_protos_streams_v1_streams_proto_msgTypes[1]
|
||||||
|
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 ResizeMessage.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ResizeMessage) Descriptor() ([]byte, []int) {
|
||||||
|
return file_protos_streams_v1_streams_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ResizeMessage) GetWidth() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Width
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ResizeMessage) GetHeight() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Height
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExitMessage struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Status uint32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ExitMessage) Reset() {
|
||||||
|
*x = ExitMessage{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_protos_streams_v1_streams_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ExitMessage) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ExitMessage) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ExitMessage) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_protos_streams_v1_streams_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 ExitMessage.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ExitMessage) Descriptor() ([]byte, []int) {
|
||||||
|
return file_protos_streams_v1_streams_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ExitMessage) GetStatus() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Status
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_protos_streams_v1_streams_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_protos_streams_v1_streams_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x1f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73,
|
||||||
|
0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x12, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70,
|
||||||
|
0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73,
|
||||||
|
0x2e, 0x76, 0x31, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x64,
|
||||||
|
0x0a, 0x0c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3e,
|
||||||
|
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x63,
|
||||||
|
0x6f, 0x6d, 0x2e, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||||
|
0x49, 0x4f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14,
|
||||||
|
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76,
|
||||||
|
0x61, 0x6c, 0x75, 0x65, 0x22, 0x3d, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x4d, 0x65,
|
||||||
|
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68,
|
||||||
|
0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x68, 0x65, 0x69,
|
||||||
|
0x67, 0x68, 0x74, 0x22, 0x25, 0x0a, 0x0b, 0x45, 0x78, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||||
|
0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, 0x2d, 0x0a, 0x08, 0x49, 0x4f,
|
||||||
|
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x44, 0x49, 0x4e, 0x10,
|
||||||
|
0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x44, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a,
|
||||||
|
0x06, 0x53, 0x54, 0x44, 0x45, 0x52, 0x52, 0x10, 0x02, 0x32, 0x48, 0x0a, 0x09, 0x53, 0x74, 0x72,
|
||||||
|
0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x3b, 0x0a, 0x09, 0x4e, 0x65, 0x77, 0x53, 0x74, 0x72,
|
||||||
|
0x65, 0x61, 0x6d, 0x12, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x28,
|
||||||
|
0x01, 0x30, 0x01, 0x42, 0x2c, 0x5a, 0x2a, 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, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x76,
|
||||||
|
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_protos_streams_v1_streams_proto_rawDescOnce sync.Once
|
||||||
|
file_protos_streams_v1_streams_proto_rawDescData = file_protos_streams_v1_streams_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_protos_streams_v1_streams_proto_rawDescGZIP() []byte {
|
||||||
|
file_protos_streams_v1_streams_proto_rawDescOnce.Do(func() {
|
||||||
|
file_protos_streams_v1_streams_proto_rawDescData = protoimpl.X.CompressGZIP(file_protos_streams_v1_streams_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_protos_streams_v1_streams_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_protos_streams_v1_streams_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
|
var file_protos_streams_v1_streams_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||||
|
var file_protos_streams_v1_streams_proto_goTypes = []interface{}{
|
||||||
|
(IOStream)(0), // 0: com.docker.api.protos.streams.v1.IOStream
|
||||||
|
(*BytesMessage)(nil), // 1: com.docker.api.protos.streams.v1.BytesMessage
|
||||||
|
(*ResizeMessage)(nil), // 2: com.docker.api.protos.streams.v1.ResizeMessage
|
||||||
|
(*ExitMessage)(nil), // 3: com.docker.api.protos.streams.v1.ExitMessage
|
||||||
|
(*any.Any)(nil), // 4: google.protobuf.Any
|
||||||
|
}
|
||||||
|
var file_protos_streams_v1_streams_proto_depIdxs = []int32{
|
||||||
|
0, // 0: com.docker.api.protos.streams.v1.BytesMessage.type:type_name -> com.docker.api.protos.streams.v1.IOStream
|
||||||
|
4, // 1: com.docker.api.protos.streams.v1.Streaming.NewStream:input_type -> google.protobuf.Any
|
||||||
|
4, // 2: com.docker.api.protos.streams.v1.Streaming.NewStream:output_type -> google.protobuf.Any
|
||||||
|
2, // [2:3] is the sub-list for method output_type
|
||||||
|
1, // [1:2] is the sub-list for method input_type
|
||||||
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
|
0, // [0:1] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_protos_streams_v1_streams_proto_init() }
|
||||||
|
func file_protos_streams_v1_streams_proto_init() {
|
||||||
|
if File_protos_streams_v1_streams_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_protos_streams_v1_streams_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*BytesMessage); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_protos_streams_v1_streams_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ResizeMessage); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_protos_streams_v1_streams_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ExitMessage); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_protos_streams_v1_streams_proto_rawDesc,
|
||||||
|
NumEnums: 1,
|
||||||
|
NumMessages: 3,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_protos_streams_v1_streams_proto_goTypes,
|
||||||
|
DependencyIndexes: file_protos_streams_v1_streams_proto_depIdxs,
|
||||||
|
EnumInfos: file_protos_streams_v1_streams_proto_enumTypes,
|
||||||
|
MessageInfos: file_protos_streams_v1_streams_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_protos_streams_v1_streams_proto = out.File
|
||||||
|
file_protos_streams_v1_streams_proto_rawDesc = nil
|
||||||
|
file_protos_streams_v1_streams_proto_goTypes = nil
|
||||||
|
file_protos_streams_v1_streams_proto_depIdxs = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConnInterface
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion6
|
||||||
|
|
||||||
|
// StreamingClient is the client API for Streaming service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||||
|
type StreamingClient interface {
|
||||||
|
NewStream(ctx context.Context, opts ...grpc.CallOption) (Streaming_NewStreamClient, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type streamingClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStreamingClient(cc grpc.ClientConnInterface) StreamingClient {
|
||||||
|
return &streamingClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *streamingClient) NewStream(ctx context.Context, opts ...grpc.CallOption) (Streaming_NewStreamClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &_Streaming_serviceDesc.Streams[0], "/com.docker.api.protos.streams.v1.Streaming/NewStream", opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &streamingNewStreamClient{stream}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Streaming_NewStreamClient interface {
|
||||||
|
Send(*any.Any) error
|
||||||
|
Recv() (*any.Any, error)
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type streamingNewStreamClient struct {
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *streamingNewStreamClient) Send(m *any.Any) error {
|
||||||
|
return x.ClientStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *streamingNewStreamClient) Recv() (*any.Any, error) {
|
||||||
|
m := new(any.Any)
|
||||||
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StreamingServer is the server API for Streaming service.
|
||||||
|
type StreamingServer interface {
|
||||||
|
NewStream(Streaming_NewStreamServer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedStreamingServer can be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedStreamingServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*UnimplementedStreamingServer) NewStream(Streaming_NewStreamServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method NewStream not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterStreamingServer(s *grpc.Server, srv StreamingServer) {
|
||||||
|
s.RegisterService(&_Streaming_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Streaming_NewStream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
return srv.(StreamingServer).NewStream(&streamingNewStreamServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Streaming_NewStreamServer interface {
|
||||||
|
Send(*any.Any) error
|
||||||
|
Recv() (*any.Any, error)
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type streamingNewStreamServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *streamingNewStreamServer) Send(m *any.Any) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *streamingNewStreamServer) Recv() (*any.Any, error) {
|
||||||
|
m := new(any.Any)
|
||||||
|
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Streaming_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "com.docker.api.protos.streams.v1.Streaming",
|
||||||
|
HandlerType: (*StreamingServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{},
|
||||||
|
Streams: []grpc.StreamDesc{
|
||||||
|
{
|
||||||
|
StreamName: "NewStream",
|
||||||
|
Handler: _Streaming_NewStream_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
ClientStreams: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Metadata: "protos/streams/v1/streams.proto",
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package com.docker.api.protos.streams.v1;
|
||||||
|
|
||||||
|
import "google/protobuf/any.proto";
|
||||||
|
|
||||||
|
option go_package = "github.com/docker/api/protos/streams/v1;v1";
|
||||||
|
|
||||||
|
service Streaming {
|
||||||
|
rpc NewStream(stream google.protobuf.Any) returns (stream google.protobuf.Any);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IOStream {
|
||||||
|
STDIN = 0;
|
||||||
|
STDOUT = 1;
|
||||||
|
STDERR = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BytesMessage {
|
||||||
|
IOStream type = 1;
|
||||||
|
bytes value = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ResizeMessage {
|
||||||
|
uint32 width = 1;
|
||||||
|
uint32 height = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ExitMessage {
|
||||||
|
uint32 status = 1;
|
||||||
|
}
|
|
@ -2,23 +2,16 @@ package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/docker/api/containers"
|
"github.com/docker/api/containers"
|
||||||
v1 "github.com/docker/api/protos/containers/v1"
|
containersv1 "github.com/docker/api/protos/containers/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewContainerAPI creates a proxy container server
|
func portsToGrpc(ports []containers.Port) []*containersv1.Port {
|
||||||
func NewContainerAPI() v1.ContainersServer {
|
var result []*containersv1.Port
|
||||||
return &proxyContainerAPI{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type proxyContainerAPI struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func portsToGrpc(ports []containers.Port) []*v1.Port {
|
|
||||||
var result []*v1.Port
|
|
||||||
for _, port := range ports {
|
for _, port := range ports {
|
||||||
result = append(result, &v1.Port{
|
result = append(result, &containersv1.Port{
|
||||||
ContainerPort: port.ContainerPort,
|
ContainerPort: port.ContainerPort,
|
||||||
HostPort: port.HostPort,
|
HostPort: port.HostPort,
|
||||||
HostIp: port.HostIP,
|
HostIp: port.HostIP,
|
||||||
|
@ -29,19 +22,19 @@ func portsToGrpc(ports []containers.Port) []*v1.Port {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *proxyContainerAPI) List(ctx context.Context, request *v1.ListRequest) (*v1.ListResponse, error) {
|
func (p *proxy) List(ctx context.Context, request *containersv1.ListRequest) (*containersv1.ListResponse, error) {
|
||||||
client := Client(ctx)
|
client := Client(ctx)
|
||||||
|
|
||||||
c, err := client.ContainerService().List(ctx, request.GetAll())
|
c, err := client.ContainerService().List(ctx, request.GetAll())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &v1.ListResponse{}, err
|
return &containersv1.ListResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response := &v1.ListResponse{
|
response := &containersv1.ListResponse{
|
||||||
Containers: []*v1.Container{},
|
Containers: []*containersv1.Container{},
|
||||||
}
|
}
|
||||||
for _, container := range c {
|
for _, container := range c {
|
||||||
response.Containers = append(response.Containers, &v1.Container{
|
response.Containers = append(response.Containers, &containersv1.Container{
|
||||||
Id: container.ID,
|
Id: container.ID,
|
||||||
Image: container.Image,
|
Image: container.Image,
|
||||||
Command: container.Command,
|
Command: container.Command,
|
||||||
|
@ -59,55 +52,62 @@ func (p *proxyContainerAPI) List(ctx context.Context, request *v1.ListRequest) (
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *proxyContainerAPI) Create(ctx context.Context, request *v1.CreateRequest) (*v1.CreateResponse, error) {
|
func (p *proxy) Stop(ctx context.Context, request *containersv1.StopRequest) (*containersv1.StopResponse, error) {
|
||||||
client := Client(ctx)
|
|
||||||
|
|
||||||
err := client.ContainerService().Run(ctx, containers.ContainerConfig{
|
|
||||||
ID: request.Id,
|
|
||||||
Image: request.Image,
|
|
||||||
})
|
|
||||||
|
|
||||||
return &v1.CreateResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *proxyContainerAPI) Start(_ context.Context, request *v1.StartRequest) (*v1.StartResponse, error) {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *proxyContainerAPI) Stop(ctx context.Context, request *v1.StopRequest) (*v1.StopResponse, error) {
|
|
||||||
c := Client(ctx)
|
c := Client(ctx)
|
||||||
timeoutValue := request.GetTimeout()
|
timeoutValue := request.GetTimeout()
|
||||||
return &v1.StopResponse{}, c.ContainerService().Stop(ctx, request.Id, &timeoutValue)
|
return &containersv1.StopResponse{}, c.ContainerService().Stop(ctx, request.Id, &timeoutValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *proxyContainerAPI) Kill(ctx context.Context, request *v1.KillRequest) (*v1.KillResponse, error) {
|
func (p *proxy) Run(ctx context.Context, request *containersv1.RunRequest) (*containersv1.RunResponse, error) {
|
||||||
c := Client(ctx)
|
ports := []containers.Port{}
|
||||||
return &v1.KillResponse{}, c.ContainerService().Delete(ctx, request.Id, false)
|
for _, p := range request.GetPorts() {
|
||||||
}
|
ports = append(ports, containers.Port{
|
||||||
|
ContainerPort: p.ContainerPort,
|
||||||
func (p *proxyContainerAPI) Delete(ctx context.Context, request *v1.DeleteRequest) (*v1.DeleteResponse, error) {
|
HostIP: p.HostIp,
|
||||||
err := Client(ctx).ContainerService().Delete(ctx, request.Id, request.Force)
|
HostPort: p.HostPort,
|
||||||
if err != nil {
|
Protocol: p.Protocol,
|
||||||
return &v1.DeleteResponse{}, err
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.DeleteResponse{}, nil
|
err := Client(ctx).ContainerService().Run(ctx, containers.ContainerConfig{
|
||||||
|
ID: request.GetId(),
|
||||||
|
Image: request.GetImage(),
|
||||||
|
Labels: request.GetLabels(),
|
||||||
|
Ports: ports,
|
||||||
|
Volumes: request.GetVolumes(),
|
||||||
|
})
|
||||||
|
|
||||||
|
return &containersv1.RunResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *proxyContainerAPI) Update(_ context.Context, _ *v1.UpdateRequest) (*v1.UpdateResponse, error) {
|
func (p *proxy) Delete(ctx context.Context, request *containersv1.DeleteRequest) (*containersv1.DeleteResponse, error) {
|
||||||
panic("not implemented") // TODO: Implement
|
err := Client(ctx).ContainerService().Delete(ctx, request.Id, request.Force)
|
||||||
|
if err != nil {
|
||||||
|
return &containersv1.DeleteResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &containersv1.DeleteResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *proxyContainerAPI) Exec(_ context.Context, _ *v1.ExecRequest) (*v1.ExecResponse, error) {
|
func (p *proxy) Exec(ctx context.Context, request *containersv1.ExecRequest) (*containersv1.ExecResponse, error) {
|
||||||
panic("not implemented") // TODO: Implement
|
p.mu.Lock()
|
||||||
|
stream, ok := p.streams[request.StreamId]
|
||||||
|
p.mu.Unlock()
|
||||||
|
if !ok {
|
||||||
|
return &containersv1.ExecResponse{}, errors.New("unknown stream id")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := Client(ctx).ContainerService().Exec(ctx, request.GetId(), request.GetCommand(), &reader{stream}, &writer{stream})
|
||||||
|
|
||||||
|
return &containersv1.ExecResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *proxyContainerAPI) Logs(request *v1.LogsRequest, stream v1.Containers_LogsServer) error {
|
func (p *proxy) Logs(request *containersv1.LogsRequest, stream containersv1.Containers_LogsServer) error {
|
||||||
ctx := stream.Context()
|
ctx := stream.Context()
|
||||||
c := Client(ctx)
|
c := Client(ctx)
|
||||||
|
|
||||||
return c.ContainerService().Logs(ctx, request.GetContainerId(), containers.LogsRequest{
|
return c.ContainerService().Logs(ctx, request.GetContainerId(), containers.LogsRequest{
|
||||||
Follow: request.Follow,
|
Follow: request.Follow,
|
||||||
Writer: &streamWriter{stream},
|
Writer: &logStream{stream},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
|
containersv1 "github.com/docker/api/protos/containers/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type logStream struct {
|
||||||
|
stream grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStreamWriter(stream grpc.ServerStream) io.Writer {
|
||||||
|
return &logStream{
|
||||||
|
stream: stream,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *logStream) Write(p []byte) (n int, err error) {
|
||||||
|
return len(p), w.stream.SendMsg(&containersv1.LogsResponse{
|
||||||
|
Value: p,
|
||||||
|
})
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type logServer struct {
|
type logServer struct {
|
||||||
logs []byte
|
logs interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *logServer) Send(response *v1.LogsResponse) error {
|
func (ls *logServer) Send(response *v1.LogsResponse) error {
|
||||||
|
@ -34,8 +34,7 @@ func (ls *logServer) Context() context.Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *logServer) SendMsg(m interface{}) error {
|
func (ls *logServer) SendMsg(m interface{}) error {
|
||||||
s, _ := m.(*v1.LogsResponse)
|
ls.logs = m
|
||||||
ls.logs = s.Logs
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,14 +42,17 @@ func (ls *logServer) RecvMsg(m interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStreamWriter(t *testing.T) {
|
func TestLogStreamWriter(t *testing.T) {
|
||||||
ls := &logServer{}
|
ls := &logServer{}
|
||||||
sw := newStreamWriter(ls)
|
sw := newStreamWriter(ls)
|
||||||
in := []byte{104, 101, 108, 108, 111}
|
in := []byte{104, 101, 108, 108, 111}
|
||||||
|
expected := &v1.LogsResponse{
|
||||||
|
Value: in,
|
||||||
|
}
|
||||||
|
|
||||||
l, err := sw.Write(in)
|
l, err := sw.Write(in)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, len(in), l)
|
assert.Equal(t, len(in), l)
|
||||||
assert.Equal(t, in, ls.logs)
|
assert.Equal(t, expected, ls.logs)
|
||||||
}
|
}
|
|
@ -2,8 +2,11 @@ package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/api/client"
|
"github.com/docker/api/client"
|
||||||
|
containersv1 "github.com/docker/api/protos/containers/v1"
|
||||||
|
streamsv1 "github.com/docker/api/protos/streams/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type clientKey struct{}
|
type clientKey struct{}
|
||||||
|
@ -18,3 +21,22 @@ func Client(ctx context.Context) *client.Client {
|
||||||
c, _ := ctx.Value(clientKey{}).(*client.Client)
|
c, _ := ctx.Value(clientKey{}).(*client.Client)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Proxy implements the gRPC server and forwards the actions
|
||||||
|
// to the right backend
|
||||||
|
type Proxy interface {
|
||||||
|
containersv1.ContainersServer
|
||||||
|
streamsv1.StreamingServer
|
||||||
|
}
|
||||||
|
|
||||||
|
type proxy struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
streams map[string]*Stream
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new proxy server
|
||||||
|
func New() Proxy {
|
||||||
|
return &proxy{
|
||||||
|
streams: map[string]*Stream{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/log"
|
||||||
|
"github.com/golang/protobuf/ptypes"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
|
||||||
|
streamsv1 "github.com/docker/api/protos/streams/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Stream is a bidirectional stream for container IO
|
||||||
|
type Stream struct {
|
||||||
|
streamsv1.Streaming_NewStreamServer
|
||||||
|
|
||||||
|
errm sync.Mutex
|
||||||
|
errChan chan<- error
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseWithError sends the result of an action to the errChan or nil
|
||||||
|
// if no erros
|
||||||
|
func (s *Stream) CloseWithError(err error) error {
|
||||||
|
s.errm.Lock()
|
||||||
|
defer s.errm.Unlock()
|
||||||
|
|
||||||
|
if s.errChan != nil {
|
||||||
|
if err != nil {
|
||||||
|
s.errChan <- err
|
||||||
|
}
|
||||||
|
close(s.errChan)
|
||||||
|
s.errChan = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *proxy) NewStream(stream streamsv1.Streaming_NewStreamServer) error {
|
||||||
|
var (
|
||||||
|
ctx = stream.Context()
|
||||||
|
id = uuid.New().String()
|
||||||
|
)
|
||||||
|
md := metadata.New(map[string]string{
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
|
||||||
|
// return the id of the stream to the client
|
||||||
|
if err := stream.SendHeader(md); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
errc := make(chan error)
|
||||||
|
|
||||||
|
p.mu.Lock()
|
||||||
|
p.streams[id] = &Stream{
|
||||||
|
Streaming_NewStreamServer: stream,
|
||||||
|
errChan: errc,
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
p.mu.Lock()
|
||||||
|
delete(p.streams, id)
|
||||||
|
p.mu.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-errc:
|
||||||
|
return err
|
||||||
|
case <-ctx.Done():
|
||||||
|
log.G(ctx).Debug("client context canceled")
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.Reader that forwards everything to the stream
|
||||||
|
type reader struct {
|
||||||
|
stream *Stream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r reader) Read(p []byte) (int, error) {
|
||||||
|
a, err := r.stream.Recv()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var m streamsv1.BytesMessage
|
||||||
|
err = ptypes.UnmarshalAny(a, &m)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy(p, m.Value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// io.Writer that writes
|
||||||
|
type writer struct {
|
||||||
|
stream grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writer) Write(p []byte) (n int, err error) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
message := streamsv1.BytesMessage{
|
||||||
|
Type: streamsv1.IOStream_STDOUT,
|
||||||
|
Value: p,
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := ptypes.MarshalAny(&message)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(message.Value), w.stream.SendMsg(m)
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/ptypes"
|
||||||
|
"github.com/golang/protobuf/ptypes/any"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
streamsv1 "github.com/docker/api/protos/streams/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type byteStream struct {
|
||||||
|
recvResult *any.Any
|
||||||
|
recvErr error
|
||||||
|
|
||||||
|
sendResult interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *byteStream) SetHeader(metadata.MD) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *byteStream) SendHeader(metadata.MD) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *byteStream) SetTrailer(metadata.MD) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *byteStream) Context() context.Context {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *byteStream) SendMsg(m interface{}) error {
|
||||||
|
bs.sendResult = m
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *byteStream) Send(*any.Any) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *byteStream) Recv() (*any.Any, error) {
|
||||||
|
return bs.recvResult, bs.recvErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *byteStream) RecvMsg(m interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getReader(t *testing.T, in []byte, errResult error) reader {
|
||||||
|
message := streamsv1.BytesMessage{
|
||||||
|
Type: streamsv1.IOStream_STDOUT,
|
||||||
|
Value: in,
|
||||||
|
}
|
||||||
|
m, err := ptypes.MarshalAny(&message)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
return reader{
|
||||||
|
stream: &Stream{
|
||||||
|
Streaming_NewStreamServer: &byteStream{
|
||||||
|
recvResult: m,
|
||||||
|
recvErr: errResult,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAny(t *testing.T, in []byte) *any.Any {
|
||||||
|
value, err := ptypes.MarshalAny(&streamsv1.BytesMessage{
|
||||||
|
Type: streamsv1.IOStream_STDOUT,
|
||||||
|
Value: in,
|
||||||
|
})
|
||||||
|
require.Nil(t, err)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStreamReader(t *testing.T) {
|
||||||
|
in := []byte{104, 101, 108, 108, 111}
|
||||||
|
r := getReader(t, in, nil)
|
||||||
|
buffer := make([]byte, 5)
|
||||||
|
|
||||||
|
n, err := r.Read(buffer)
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 5, n)
|
||||||
|
assert.Equal(t, in, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStreamReaderError(t *testing.T) {
|
||||||
|
errResult := errors.New("err")
|
||||||
|
r := getReader(t, nil, errResult)
|
||||||
|
var buffer []byte
|
||||||
|
|
||||||
|
n, err := r.Read(buffer)
|
||||||
|
|
||||||
|
assert.Equal(t, 0, n)
|
||||||
|
assert.Equal(t, err, errResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStreamWriter(t *testing.T) {
|
||||||
|
in := []byte{104, 101, 108, 108, 111}
|
||||||
|
expected := getAny(t, in)
|
||||||
|
|
||||||
|
bs := byteStream{}
|
||||||
|
w := writer{stream: &bs}
|
||||||
|
|
||||||
|
n, err := w.Write(in)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, len(in), n)
|
||||||
|
assert.Equal(t, expected, bs.sendResult)
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
|
|
||||||
v1 "github.com/docker/api/protos/containers/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type streamWriter struct {
|
|
||||||
stream v1.Containers_LogsServer
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStreamWriter(stream v1.Containers_LogsServer) io.Writer {
|
|
||||||
return &streamWriter{
|
|
||||||
stream: stream,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *streamWriter) Write(p []byte) (n int, err error) {
|
|
||||||
return len(p), w.stream.SendMsg(&v1.LogsResponse{
|
|
||||||
Logs: p,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -3,8 +3,10 @@ node_modules/.bin/grpc_tools_node_protoc \
|
||||||
--grpc_out=generate_package_definition:./grpc \
|
--grpc_out=generate_package_definition:./grpc \
|
||||||
-I ../../protos/contexts/v1 \
|
-I ../../protos/contexts/v1 \
|
||||||
-I ../../protos/containers/v1 \
|
-I ../../protos/containers/v1 \
|
||||||
|
-I ../../protos/streams/v1 \
|
||||||
../../protos/contexts/v1/*.proto \
|
../../protos/contexts/v1/*.proto \
|
||||||
../../protos/containers/v1/*.proto
|
../../protos/containers/v1/*.proto \
|
||||||
|
../../protos/streams/v1/*.proto
|
||||||
|
|
||||||
# generate d.ts codes
|
# generate d.ts codes
|
||||||
protoc \
|
protoc \
|
||||||
|
@ -12,5 +14,7 @@ protoc \
|
||||||
--ts_out=generate_package_definition:./grpc \
|
--ts_out=generate_package_definition:./grpc \
|
||||||
-I ../../protos/contexts/v1 \
|
-I ../../protos/contexts/v1 \
|
||||||
-I ../../protos/containers/v1 \
|
-I ../../protos/containers/v1 \
|
||||||
|
-I ../../protos/streams/v1 \
|
||||||
../../protos/contexts/v1/*.proto \
|
../../protos/contexts/v1/*.proto \
|
||||||
../../protos/containers/v1/*.proto
|
../../protos/containers/v1/*.proto \
|
||||||
|
../../protos/streams/v1/*.proto
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
import * as grpc from "@grpc/grpc-js";
|
||||||
|
import * as readline from "readline";
|
||||||
|
import * as google_protobuf_any_pb from "google-protobuf/google/protobuf/any_pb.js";
|
||||||
|
|
||||||
|
import * as continersPb from "./grpc/containers_grpc_pb";
|
||||||
|
import { IContainersClient } from "./grpc/containers_grpc_pb";
|
||||||
|
import { ExecRequest, ExecResponse, LogsRequest } from "./grpc/containers_pb";
|
||||||
|
|
||||||
|
import * as streamsPb from "./grpc/streams_grpc_pb";
|
||||||
|
import { IStreamingClient } from "./grpc/streams_grpc_pb";
|
||||||
|
import { BytesMessage } from "./grpc/streams_pb";
|
||||||
|
|
||||||
|
let address = process.argv[3] || "unix:///tmp/backend.sock";
|
||||||
|
|
||||||
|
const ContainersServiceClient = grpc.makeClientConstructor(
|
||||||
|
continersPb["com.docker.api.protos.containers.v1.Containers"],
|
||||||
|
"ContainersClient"
|
||||||
|
);
|
||||||
|
|
||||||
|
const client = (new ContainersServiceClient(
|
||||||
|
address,
|
||||||
|
grpc.credentials.createInsecure()
|
||||||
|
) as unknown) as IContainersClient;
|
||||||
|
|
||||||
|
const StreamsServiceClient = grpc.makeClientConstructor(
|
||||||
|
streamsPb["com.docker.api.protos.streams.v1.Streaming"],
|
||||||
|
"StreamsClient"
|
||||||
|
);
|
||||||
|
|
||||||
|
let streamClient = (new StreamsServiceClient(
|
||||||
|
address,
|
||||||
|
grpc.credentials.createInsecure()
|
||||||
|
) as unknown) as IStreamingClient;
|
||||||
|
|
||||||
|
let backend = process.argv[2] || "moby";
|
||||||
|
let containerId = process.argv[3];
|
||||||
|
const meta = new grpc.Metadata();
|
||||||
|
meta.set("CONTEXT_KEY", backend);
|
||||||
|
|
||||||
|
// Get the stream
|
||||||
|
const stream = streamClient.newStream();
|
||||||
|
|
||||||
|
stream.on("metadata", (m: grpc.Metadata) => {
|
||||||
|
let req = new ExecRequest();
|
||||||
|
req.setCommand("/bin/bash");
|
||||||
|
req.setStreamId(m.get("id")[0] as string);
|
||||||
|
req.setId(containerId);
|
||||||
|
req.setTty(true);
|
||||||
|
|
||||||
|
client.exec(req, meta, (err: any, _: ExecResponse) => {
|
||||||
|
if (err != null) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
readline.emitKeypressEvents(process.stdin);
|
||||||
|
process.stdin.setRawMode(true);
|
||||||
|
|
||||||
|
process.stdin.on("keypress", (str, key) => {
|
||||||
|
const mess = new BytesMessage();
|
||||||
|
const a = new Uint8Array(key.sequence.length);
|
||||||
|
for (let i = 0; i <= key.sequence.length; i++) {
|
||||||
|
a[i] = key.sequence.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
mess.setValue(a);
|
||||||
|
|
||||||
|
const any = new google_protobuf_any_pb.Any();
|
||||||
|
any.pack(
|
||||||
|
mess.serializeBinary(),
|
||||||
|
"type.googleapis.com/com.docker.api.protos.streams.v1.BytesMessage"
|
||||||
|
);
|
||||||
|
stream.write(any);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on("data", (chunk: any) => {
|
||||||
|
const m = chunk.unpack(
|
||||||
|
BytesMessage.deserializeBinary,
|
||||||
|
"com.docker.api.protos.streams.v1.BytesMessage"
|
||||||
|
) as BytesMessage;
|
||||||
|
process.stdout.write(m.getValue());
|
||||||
|
});
|
|
@ -12,6 +12,7 @@
|
||||||
"grpc": "^1.24.2",
|
"grpc": "^1.24.2",
|
||||||
"grpc-tools": "^1.8.1",
|
"grpc-tools": "^1.8.1",
|
||||||
"grpc_tools_node_protoc_ts": "^3.0.0",
|
"grpc_tools_node_protoc_ts": "^3.0.0",
|
||||||
|
"readline": "^1.3.0",
|
||||||
"ts-node": "^8.9.1",
|
"ts-node": "^8.9.1",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
declare module "google-protobuf/google/protobuf/any_pb.js";
|
|
@ -1653,6 +1653,11 @@ readable-stream@^2.0.6, readable-stream@~2.3.6:
|
||||||
string_decoder "~1.1.1"
|
string_decoder "~1.1.1"
|
||||||
util-deprecate "~1.0.1"
|
util-deprecate "~1.0.1"
|
||||||
|
|
||||||
|
readline@^1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c"
|
||||||
|
integrity sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=
|
||||||
|
|
||||||
regex-not@^1.0.0, regex-not@^1.0.2:
|
regex-not@^1.0.0, regex-not@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
|
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
|
||||||
|
|
Loading…
Reference in New Issue