From 4f8822a3954059cc8172b446b270a82821bd7556 Mon Sep 17 00:00:00 2001 From: zvier Date: Sat, 25 Jul 2020 15:20:39 +0800 Subject: [PATCH] import: support importing base image from a tarball Signed-off: liuzekun --- api/services/control.pb.go | 320 +++++++++++++++++------ api/services/control.proto | 14 + builder/dockerfile/cmd_builder_commit.go | 5 +- cmd/cli/build.go | 1 + cmd/cli/build_test.go | 5 + cmd/cli/grpc_client_test.go | 23 ++ cmd/cli/import.go | 126 +++++++++ daemon/import.go | 111 ++++++++ daemon/import_test.go | 77 ++++++ 9 files changed, 602 insertions(+), 80 deletions(-) create mode 100644 cmd/cli/import.go create mode 100644 daemon/import.go create mode 100644 daemon/import_test.go diff --git a/api/services/control.pb.go b/api/services/control.pb.go index 2b18915..776eb30 100644 --- a/api/services/control.pb.go +++ b/api/services/control.pb.go @@ -50,7 +50,7 @@ func (x HealthCheckResponse_ServingStatus) String() string { } func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{10, 0} + return fileDescriptor_d71ef680555cb937, []int{12, 0} } type BuildRequest struct { @@ -173,6 +173,93 @@ func (m *BuildRequest) GetEncryptKey() string { return "" } +type ImportRequest struct { + // reference is reference of the import image + Reference string `protobuf:"bytes,1,opt,name=reference,proto3" json:"reference,omitempty"` + // data is the tarball of the import image + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ImportRequest) Reset() { *m = ImportRequest{} } +func (m *ImportRequest) String() string { return proto.CompactTextString(m) } +func (*ImportRequest) ProtoMessage() {} +func (*ImportRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d71ef680555cb937, []int{1} +} +func (m *ImportRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ImportRequest.Unmarshal(m, b) +} +func (m *ImportRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ImportRequest.Marshal(b, m, deterministic) +} +func (m *ImportRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ImportRequest.Merge(m, src) +} +func (m *ImportRequest) XXX_Size() int { + return xxx_messageInfo_ImportRequest.Size(m) +} +func (m *ImportRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ImportRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ImportRequest proto.InternalMessageInfo + +func (m *ImportRequest) GetReference() string { + if m != nil { + return m.Reference + } + return "" +} + +func (m *ImportRequest) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +type ImportResponse struct { + // imageID is the ID of the import image + ImageID string `protobuf:"bytes,1,opt,name=imageID,proto3" json:"imageID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ImportResponse) Reset() { *m = ImportResponse{} } +func (m *ImportResponse) String() string { return proto.CompactTextString(m) } +func (*ImportResponse) ProtoMessage() {} +func (*ImportResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d71ef680555cb937, []int{2} +} +func (m *ImportResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ImportResponse.Unmarshal(m, b) +} +func (m *ImportResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ImportResponse.Marshal(b, m, deterministic) +} +func (m *ImportResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ImportResponse.Merge(m, src) +} +func (m *ImportResponse) XXX_Size() int { + return xxx_messageInfo_ImportResponse.Size(m) +} +func (m *ImportResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ImportResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ImportResponse proto.InternalMessageInfo + +func (m *ImportResponse) GetImageID() string { + if m != nil { + return m.ImageID + } + return "" +} + type BuildStatic struct { // buildTime is a fixed time for binary equivalence build BuildTime *types.Timestamp `protobuf:"bytes,1,opt,name=buildTime,proto3" json:"buildTime,omitempty"` @@ -185,7 +272,7 @@ func (m *BuildStatic) Reset() { *m = BuildStatic{} } func (m *BuildStatic) String() string { return proto.CompactTextString(m) } func (*BuildStatic) ProtoMessage() {} func (*BuildStatic) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{1} + return fileDescriptor_d71ef680555cb937, []int{3} } func (m *BuildStatic) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BuildStatic.Unmarshal(m, b) @@ -226,7 +313,7 @@ func (m *BuildResponse) Reset() { *m = BuildResponse{} } func (m *BuildResponse) String() string { return proto.CompactTextString(m) } func (*BuildResponse) ProtoMessage() {} func (*BuildResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{2} + return fileDescriptor_d71ef680555cb937, []int{4} } func (m *BuildResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BuildResponse.Unmarshal(m, b) @@ -272,7 +359,7 @@ func (m *StatusRequest) Reset() { *m = StatusRequest{} } func (m *StatusRequest) String() string { return proto.CompactTextString(m) } func (*StatusRequest) ProtoMessage() {} func (*StatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{3} + return fileDescriptor_d71ef680555cb937, []int{5} } func (m *StatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StatusRequest.Unmarshal(m, b) @@ -311,7 +398,7 @@ func (m *StatusResponse) Reset() { *m = StatusResponse{} } func (m *StatusResponse) String() string { return proto.CompactTextString(m) } func (*StatusResponse) ProtoMessage() {} func (*StatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{4} + return fileDescriptor_d71ef680555cb937, []int{6} } func (m *StatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StatusResponse.Unmarshal(m, b) @@ -350,7 +437,7 @@ func (m *ListRequest) Reset() { *m = ListRequest{} } func (m *ListRequest) String() string { return proto.CompactTextString(m) } func (*ListRequest) ProtoMessage() {} func (*ListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{5} + return fileDescriptor_d71ef680555cb937, []int{7} } func (m *ListRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRequest.Unmarshal(m, b) @@ -389,7 +476,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} } func (m *ListResponse) String() string { return proto.CompactTextString(m) } func (*ListResponse) ProtoMessage() {} func (*ListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{6} + return fileDescriptor_d71ef680555cb937, []int{8} } func (m *ListResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListResponse.Unmarshal(m, b) @@ -431,7 +518,7 @@ func (m *ListResponse_ImageInfo) Reset() { *m = ListResponse_ImageInfo{} func (m *ListResponse_ImageInfo) String() string { return proto.CompactTextString(m) } func (*ListResponse_ImageInfo) ProtoMessage() {} func (*ListResponse_ImageInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{6, 0} + return fileDescriptor_d71ef680555cb937, []int{8, 0} } func (m *ListResponse_ImageInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListResponse_ImageInfo.Unmarshal(m, b) @@ -506,7 +593,7 @@ func (m *VersionResponse) Reset() { *m = VersionResponse{} } func (m *VersionResponse) String() string { return proto.CompactTextString(m) } func (*VersionResponse) ProtoMessage() {} func (*VersionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{7} + return fileDescriptor_d71ef680555cb937, []int{9} } func (m *VersionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VersionResponse.Unmarshal(m, b) @@ -577,7 +664,7 @@ func (m *RemoveRequest) Reset() { *m = RemoveRequest{} } func (m *RemoveRequest) String() string { return proto.CompactTextString(m) } func (*RemoveRequest) ProtoMessage() {} func (*RemoveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{8} + return fileDescriptor_d71ef680555cb937, []int{10} } func (m *RemoveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RemoveRequest.Unmarshal(m, b) @@ -630,7 +717,7 @@ func (m *RemoveResponse) Reset() { *m = RemoveResponse{} } func (m *RemoveResponse) String() string { return proto.CompactTextString(m) } func (*RemoveResponse) ProtoMessage() {} func (*RemoveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{9} + return fileDescriptor_d71ef680555cb937, []int{11} } func (m *RemoveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RemoveResponse.Unmarshal(m, b) @@ -669,7 +756,7 @@ func (m *HealthCheckResponse) Reset() { *m = HealthCheckResponse{} } func (m *HealthCheckResponse) String() string { return proto.CompactTextString(m) } func (*HealthCheckResponse) ProtoMessage() {} func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{10} + return fileDescriptor_d71ef680555cb937, []int{12} } func (m *HealthCheckResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HealthCheckResponse.Unmarshal(m, b) @@ -714,7 +801,7 @@ func (m *LoginRequest) Reset() { *m = LoginRequest{} } func (m *LoginRequest) String() string { return proto.CompactTextString(m) } func (*LoginRequest) ProtoMessage() {} func (*LoginRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{11} + return fileDescriptor_d71ef680555cb937, []int{13} } func (m *LoginRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LoginRequest.Unmarshal(m, b) @@ -774,7 +861,7 @@ func (m *LoginResponse) Reset() { *m = LoginResponse{} } func (m *LoginResponse) String() string { return proto.CompactTextString(m) } func (*LoginResponse) ProtoMessage() {} func (*LoginResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{12} + return fileDescriptor_d71ef680555cb937, []int{14} } func (m *LoginResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LoginResponse.Unmarshal(m, b) @@ -815,7 +902,7 @@ func (m *LogoutRequest) Reset() { *m = LogoutRequest{} } func (m *LogoutRequest) String() string { return proto.CompactTextString(m) } func (*LogoutRequest) ProtoMessage() {} func (*LogoutRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{13} + return fileDescriptor_d71ef680555cb937, []int{15} } func (m *LogoutRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LogoutRequest.Unmarshal(m, b) @@ -861,7 +948,7 @@ func (m *LogoutResponse) Reset() { *m = LogoutResponse{} } func (m *LogoutResponse) String() string { return proto.CompactTextString(m) } func (*LogoutResponse) ProtoMessage() {} func (*LogoutResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{14} + return fileDescriptor_d71ef680555cb937, []int{16} } func (m *LogoutResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LogoutResponse.Unmarshal(m, b) @@ -900,7 +987,7 @@ func (m *LoadRequest) Reset() { *m = LoadRequest{} } func (m *LoadRequest) String() string { return proto.CompactTextString(m) } func (*LoadRequest) ProtoMessage() {} func (*LoadRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{15} + return fileDescriptor_d71ef680555cb937, []int{17} } func (m *LoadRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LoadRequest.Unmarshal(m, b) @@ -939,7 +1026,7 @@ func (m *LoadResponse) Reset() { *m = LoadResponse{} } func (m *LoadResponse) String() string { return proto.CompactTextString(m) } func (*LoadResponse) ProtoMessage() {} func (*LoadResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d71ef680555cb937, []int{16} + return fileDescriptor_d71ef680555cb937, []int{18} } func (m *LoadResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LoadResponse.Unmarshal(m, b) @@ -969,6 +1056,8 @@ func (m *LoadResponse) GetImageID() string { func init() { proto.RegisterEnum("isula.build.v1.HealthCheckResponse_ServingStatus", HealthCheckResponse_ServingStatus_name, HealthCheckResponse_ServingStatus_value) proto.RegisterType((*BuildRequest)(nil), "isula.build.v1.BuildRequest") + proto.RegisterType((*ImportRequest)(nil), "isula.build.v1.ImportRequest") + proto.RegisterType((*ImportResponse)(nil), "isula.build.v1.ImportResponse") proto.RegisterType((*BuildStatic)(nil), "isula.build.v1.BuildStatic") proto.RegisterType((*BuildResponse)(nil), "isula.build.v1.BuildResponse") proto.RegisterType((*StatusRequest)(nil), "isula.build.v1.StatusRequest") @@ -991,66 +1080,69 @@ func init() { func init() { proto.RegisterFile("api/services/control.proto", fileDescriptor_d71ef680555cb937) } var fileDescriptor_d71ef680555cb937 = []byte{ - // 942 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0x6d, 0x6f, 0xdc, 0x44, - 0x10, 0xc6, 0xf7, 0xe2, 0x4b, 0xc6, 0x97, 0x6b, 0xb4, 0xa0, 0xc8, 0x72, 0x42, 0x7b, 0x18, 0x09, - 0x1d, 0x20, 0x39, 0xed, 0xc1, 0x07, 0x40, 0x2a, 0x52, 0x5e, 0x4a, 0x38, 0x1a, 0xae, 0xc2, 0x09, - 0xe5, 0x23, 0xda, 0xdc, 0x6d, 0x9c, 0x55, 0x6d, 0xaf, 0xf1, 0xae, 0x8f, 0x1e, 0xfc, 0x05, 0x7e, - 0x02, 0xfc, 0x22, 0xc4, 0x7f, 0x42, 0xbb, 0xde, 0xb5, 0x7d, 0x2f, 0x69, 0xfb, 0x6d, 0xe7, 0x65, - 0x67, 0x67, 0xe6, 0x79, 0x66, 0x16, 0x3c, 0x9c, 0xd1, 0x63, 0x4e, 0xf2, 0x05, 0x9d, 0x11, 0x7e, - 0x3c, 0x63, 0xa9, 0xc8, 0x59, 0x1c, 0x64, 0x39, 0x13, 0x0c, 0x0d, 0x28, 0x2f, 0x62, 0x1c, 0xdc, - 0x14, 0x34, 0x9e, 0x07, 0x8b, 0x27, 0xde, 0x61, 0xc4, 0x58, 0x14, 0x93, 0x63, 0x65, 0xbd, 0x29, - 0x6e, 0x8f, 0x49, 0x92, 0x89, 0x65, 0xe9, 0xec, 0x3d, 0x5a, 0x37, 0x0a, 0x9a, 0x10, 0x2e, 0x70, - 0x92, 0x95, 0x0e, 0xfe, 0x7f, 0x2d, 0xe8, 0x9f, 0xca, 0x50, 0x21, 0xf9, 0xad, 0x20, 0x5c, 0xa0, - 0x23, 0xd8, 0x55, 0xa1, 0xaf, 0x97, 0x19, 0x71, 0xad, 0xa1, 0x35, 0xda, 0x0d, 0x6b, 0x05, 0x72, - 0xa1, 0xa7, 0x84, 0xc9, 0xb9, 0xdb, 0x52, 0x36, 0x23, 0xa2, 0x87, 0x00, 0x32, 0x4f, 0xf2, 0x5a, - 0x9c, 0xd3, 0xdc, 0x6d, 0x2b, 0x63, 0x43, 0x83, 0x86, 0xe0, 0xdc, 0xd2, 0x98, 0x9c, 0x49, 0x4d, - 0x2a, 0xdc, 0x8e, 0x72, 0x68, 0xaa, 0xd0, 0x01, 0xd8, 0xac, 0x10, 0x59, 0x21, 0xdc, 0xae, 0x32, - 0x6a, 0xa9, 0xca, 0xe8, 0x24, 0x8f, 0xb8, 0x6b, 0x0f, 0xdb, 0x55, 0x46, 0x52, 0x81, 0x3e, 0x80, - 0x6e, 0x96, 0xb3, 0xd7, 0x4b, 0xb7, 0x37, 0xb4, 0x46, 0x3b, 0x61, 0x29, 0xc8, 0x3c, 0x29, 0x9d, - 0xcb, 0xe8, 0xee, 0x4e, 0x99, 0xa7, 0x16, 0xd1, 0x53, 0x70, 0xd4, 0xe5, 0x2b, 0x81, 0x05, 0x9d, - 0xb9, 0xbb, 0x43, 0x6b, 0xe4, 0x8c, 0x0f, 0x83, 0xd5, 0xa6, 0x06, 0xa7, 0xb5, 0x4b, 0xd8, 0xf4, - 0x97, 0x65, 0x92, 0x74, 0x96, 0x2f, 0x33, 0xf1, 0x9c, 0x2c, 0x5d, 0x28, 0xcb, 0xac, 0x35, 0xfe, - 0x05, 0x38, 0x8d, 0xbb, 0xe8, 0x2b, 0xd3, 0x4d, 0x9a, 0x94, 0xdd, 0x74, 0xc6, 0x5e, 0x50, 0x62, - 0x12, 0x18, 0x4c, 0x82, 0x6b, 0x83, 0x49, 0x58, 0x3b, 0xfb, 0x4f, 0x61, 0x4f, 0xe3, 0xc2, 0x33, - 0x96, 0x72, 0xd5, 0x7a, 0x9a, 0xe0, 0x88, 0x4c, 0xce, 0x35, 0x2c, 0x46, 0x44, 0x08, 0x3a, 0x73, - 0x2c, 0xb0, 0x42, 0xa4, 0x1f, 0xaa, 0xb3, 0xff, 0x29, 0xec, 0xc9, 0x14, 0x0a, 0x6e, 0x70, 0x6d, - 0x20, 0x67, 0xad, 0x20, 0xe7, 0x7f, 0x06, 0x03, 0xe3, 0x5a, 0x3f, 0x35, 0xd3, 0x38, 0x69, 0x5f, - 0x2d, 0xfa, 0x9f, 0x83, 0x73, 0x49, 0xb9, 0x68, 0x90, 0x45, 0x25, 0x31, 0xc5, 0x49, 0x45, 0x96, - 0x4a, 0xe1, 0xff, 0x6b, 0x41, 0xbf, 0xf4, 0xd6, 0x71, 0xbf, 0x05, 0x5b, 0x59, 0xb9, 0x6b, 0x0d, - 0xdb, 0x23, 0x67, 0xfc, 0xc9, 0x7a, 0xdb, 0x9b, 0xde, 0xc1, 0x44, 0x95, 0x97, 0xde, 0xb2, 0x50, - 0xdf, 0xf2, 0xfe, 0x84, 0xdd, 0x4a, 0x29, 0x91, 0xc8, 0x49, 0xc6, 0x38, 0x15, 0x2c, 0x5f, 0xea, - 0xc7, 0x1b, 0x1a, 0xb4, 0x0f, 0x6d, 0x81, 0x23, 0x4d, 0x53, 0x79, 0x44, 0x03, 0x68, 0xd1, 0xb9, - 0xa6, 0x66, 0x8b, 0xce, 0x55, 0x99, 0x39, 0xc1, 0x82, 0xcc, 0x35, 0x1d, 0x8d, 0x28, 0x3b, 0xca, - 0xe9, 0x1f, 0x44, 0x13, 0x51, 0x9d, 0xfd, 0x7f, 0x2c, 0x78, 0xf0, 0x92, 0xe4, 0x9c, 0xb2, 0xb4, - 0xd9, 0xa8, 0x45, 0xa9, 0x32, 0x8d, 0xd2, 0xa2, 0xec, 0x4c, 0xc4, 0xb4, 0xbb, 0xce, 0xa1, 0x56, - 0x28, 0x2b, 0x15, 0x67, 0x2c, 0x49, 0xa8, 0xd0, 0x09, 0xd5, 0x8a, 0x7a, 0x04, 0x25, 0x69, 0x3a, - 0xcd, 0x11, 0xa4, 0x09, 0x51, 0x63, 0xc2, 0x4f, 0xf2, 0xd9, 0x5d, 0x35, 0x26, 0x4a, 0xf2, 0x7f, - 0x82, 0xbd, 0x90, 0x24, 0x6c, 0x41, 0x1a, 0x88, 0xd7, 0x84, 0x69, 0x37, 0x09, 0xb3, 0x0f, 0x6d, - 0x1c, 0xc7, 0x2a, 0xad, 0x9d, 0x50, 0x1e, 0xcb, 0x29, 0x2a, 0x52, 0xa2, 0x92, 0x51, 0x53, 0x54, - 0xa4, 0xc4, 0xff, 0x12, 0x06, 0x26, 0xa4, 0x2e, 0xd8, 0x87, 0x7e, 0x8c, 0x97, 0x24, 0xff, 0x91, - 0x70, 0x8e, 0x23, 0x83, 0xf9, 0x8a, 0xce, 0xff, 0xdb, 0x82, 0xf7, 0xbf, 0x27, 0x38, 0x16, 0x77, - 0x67, 0x77, 0x64, 0xf6, 0xaa, 0xba, 0x3b, 0x01, 0x9b, 0x2b, 0x9e, 0xa9, 0x5b, 0x83, 0xf1, 0x93, - 0x75, 0xf4, 0xb7, 0x5c, 0x0a, 0xae, 0xe4, 0x12, 0x4c, 0x23, 0x4d, 0x50, 0x1d, 0xc0, 0xff, 0x06, - 0xf6, 0x56, 0x0c, 0xc8, 0x81, 0xde, 0xcf, 0xd3, 0xe7, 0xd3, 0x17, 0xbf, 0x4c, 0xf7, 0xdf, 0x93, - 0xc2, 0xd5, 0xb3, 0xf0, 0xe5, 0x64, 0x7a, 0xb1, 0x6f, 0xa1, 0x07, 0xe0, 0x4c, 0x5f, 0x5c, 0xff, - 0x6a, 0x14, 0x2d, 0x3f, 0x83, 0xfe, 0x25, 0x8b, 0x68, 0x6a, 0xda, 0x74, 0x00, 0xb6, 0xdc, 0xb4, - 0x24, 0xd7, 0xc5, 0x68, 0x09, 0x79, 0xb0, 0x53, 0x70, 0x92, 0xa7, 0x92, 0xda, 0x25, 0x80, 0x95, - 0x2c, 0x6d, 0x19, 0xe6, 0xfc, 0x77, 0x96, 0x1b, 0x3e, 0x55, 0xb2, 0x6c, 0xee, 0x2b, 0xb2, 0xd4, - 0xb8, 0xc9, 0xa3, 0x9c, 0x45, 0xfd, 0xe2, 0x5b, 0xe7, 0xeb, 0x6b, 0xe5, 0xca, 0x0a, 0xf1, 0xb6, - 0xec, 0x36, 0x20, 0xf4, 0x47, 0x30, 0x30, 0x57, 0xf5, 0x33, 0x07, 0x60, 0xe7, 0x84, 0x17, 0xb1, - 0x79, 0x45, 0x4b, 0xfe, 0x47, 0xe0, 0x5c, 0x32, 0x5c, 0x6d, 0x7c, 0x04, 0x9d, 0x0c, 0x8b, 0x3b, - 0xed, 0xa4, 0xce, 0xfe, 0x48, 0x36, 0x09, 0xbf, 0xc3, 0xf2, 0x19, 0xff, 0xd5, 0x85, 0xde, 0x59, - 0xf9, 0x41, 0xa1, 0xef, 0xa0, 0xab, 0x76, 0x16, 0x3a, 0xda, 0xba, 0x4f, 0xf5, 0x83, 0xde, 0x87, - 0xf7, 0x58, 0xcb, 0xb7, 0x1e, 0x5b, 0x92, 0x29, 0x1a, 0xd7, 0x0d, 0xd7, 0x95, 0xa5, 0xe6, 0x3d, - 0xbc, 0xcf, 0x5c, 0x85, 0x3a, 0x81, 0x8e, 0x5c, 0x2a, 0xe8, 0x70, 0xfb, 0xaa, 0x29, 0xc3, 0x1c, - 0xbd, 0x69, 0x0f, 0xa1, 0x53, 0xe8, 0x99, 0xb9, 0x3d, 0xd8, 0xd8, 0xdd, 0xcf, 0xe4, 0x67, 0xeb, - 0x3d, 0x5a, 0x0f, 0xb0, 0xbe, 0x28, 0x26, 0x60, 0x97, 0x93, 0xb4, 0x59, 0xd1, 0xca, 0xd0, 0x6e, - 0x56, 0xb4, 0x3a, 0x80, 0x8f, 0x2d, 0xf4, 0x03, 0x38, 0x8d, 0x41, 0xb9, 0x37, 0xa5, 0x8f, 0xdf, - 0x61, 0xba, 0xd0, 0x39, 0x74, 0x15, 0x33, 0x37, 0x01, 0x6b, 0x8e, 0xc8, 0x26, 0x60, 0xab, 0x74, - 0xbe, 0x00, 0xbb, 0x64, 0x1e, 0xda, 0xe6, 0x58, 0x93, 0x79, 0xb3, 0xb8, 0x35, 0xc2, 0x4a, 0xb0, - 0x18, 0x9e, 0x6f, 0x01, 0xab, 0xa6, 0xeb, 0x16, 0xb0, 0x1a, 0x44, 0xbd, 0xb1, 0x55, 0x1b, 0xbe, - 0xf8, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x32, 0x55, 0x3c, 0x53, 0x42, 0x09, 0x00, 0x00, + // 986 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0x5b, 0x6f, 0xe3, 0xc4, + 0x17, 0xff, 0x3b, 0x17, 0xa7, 0x3d, 0x4e, 0xb2, 0xd5, 0xfc, 0x51, 0x65, 0xa5, 0x65, 0x37, 0x18, + 0x09, 0x05, 0x90, 0xdc, 0xdd, 0xc0, 0x03, 0x20, 0x2d, 0x52, 0x2f, 0x4b, 0x09, 0x5b, 0xb2, 0xc2, + 0x2d, 0xcb, 0x23, 0x9a, 0x26, 0xd3, 0x74, 0xb4, 0xb6, 0xc7, 0xcc, 0x8c, 0xcb, 0x06, 0xbe, 0x0a, + 0x7c, 0x22, 0xc4, 0x33, 0x5f, 0x07, 0xcd, 0x78, 0x7c, 0x8b, 0x53, 0xba, 0x6f, 0x73, 0x2e, 0x73, + 0xe6, 0x5c, 0x7e, 0xbf, 0x63, 0xc3, 0x08, 0x27, 0xf4, 0x48, 0x10, 0x7e, 0x47, 0x17, 0x44, 0x1c, + 0x2d, 0x58, 0x2c, 0x39, 0x0b, 0xfd, 0x84, 0x33, 0xc9, 0xd0, 0x90, 0x8a, 0x34, 0xc4, 0xfe, 0x75, + 0x4a, 0xc3, 0xa5, 0x7f, 0xf7, 0x6c, 0x74, 0xb0, 0x62, 0x6c, 0x15, 0x92, 0x23, 0x6d, 0xbd, 0x4e, + 0x6f, 0x8e, 0x48, 0x94, 0xc8, 0x75, 0xe6, 0x3c, 0x7a, 0xb2, 0x69, 0x94, 0x34, 0x22, 0x42, 0xe2, + 0x28, 0xc9, 0x1c, 0xbc, 0xbf, 0x5b, 0xd0, 0x3f, 0x51, 0xa1, 0x02, 0xf2, 0x4b, 0x4a, 0x84, 0x44, + 0x87, 0xb0, 0xab, 0x43, 0x5f, 0xad, 0x13, 0xe2, 0x5a, 0x63, 0x6b, 0xb2, 0x1b, 0x94, 0x0a, 0xe4, + 0x42, 0x4f, 0x0b, 0xb3, 0x33, 0xb7, 0xa5, 0x6d, 0xb9, 0x88, 0x1e, 0x03, 0xa8, 0x3c, 0xc9, 0x5b, + 0x79, 0x46, 0xb9, 0xdb, 0xd6, 0xc6, 0x8a, 0x06, 0x8d, 0xc1, 0xb9, 0xa1, 0x21, 0x39, 0x55, 0x9a, + 0x58, 0xba, 0x1d, 0xed, 0x50, 0x55, 0xa1, 0x7d, 0xb0, 0x59, 0x2a, 0x93, 0x54, 0xba, 0x5d, 0x6d, + 0x34, 0x52, 0x91, 0xd1, 0x31, 0x5f, 0x09, 0xd7, 0x1e, 0xb7, 0x8b, 0x8c, 0x94, 0x02, 0xbd, 0x07, + 0xdd, 0x84, 0xb3, 0xb7, 0x6b, 0xb7, 0x37, 0xb6, 0x26, 0x3b, 0x41, 0x26, 0xa8, 0x3c, 0x29, 0x5d, + 0xaa, 0xe8, 0xee, 0x4e, 0x96, 0xa7, 0x11, 0xd1, 0x73, 0x70, 0xf4, 0xe5, 0x4b, 0x89, 0x25, 0x5d, + 0xb8, 0xbb, 0x63, 0x6b, 0xe2, 0x4c, 0x0f, 0xfc, 0x7a, 0x53, 0xfd, 0x93, 0xd2, 0x25, 0xa8, 0xfa, + 0xab, 0x32, 0x49, 0xbc, 0xe0, 0xeb, 0x44, 0xbe, 0x24, 0x6b, 0x17, 0xb2, 0x32, 0x4b, 0x8d, 0x77, + 0x0c, 0x83, 0x59, 0x94, 0x30, 0x2e, 0x2b, 0xfd, 0xe4, 0xe4, 0x86, 0x70, 0x12, 0x2f, 0x8a, 0x7e, + 0x16, 0x0a, 0x84, 0xa0, 0xb3, 0xc4, 0x12, 0xeb, 0x66, 0xf6, 0x03, 0x7d, 0xf6, 0x3e, 0x81, 0x61, + 0x1e, 0x42, 0x24, 0x2c, 0x16, 0xba, 0xeb, 0x34, 0xc2, 0x2b, 0x32, 0x3b, 0x33, 0x11, 0x72, 0xd1, + 0x3b, 0x07, 0xa7, 0x92, 0x2a, 0xfa, 0x22, 0x1f, 0x1e, 0x8d, 0xb2, 0xc7, 0x9c, 0xe9, 0xc8, 0xcf, + 0x20, 0xe0, 0xe7, 0x10, 0xf0, 0xaf, 0x72, 0x08, 0x04, 0xa5, 0xb3, 0xf7, 0x1c, 0x06, 0x06, 0x06, + 0x0f, 0xbd, 0xb9, 0x35, 0xe7, 0x8f, 0x61, 0xa0, 0x52, 0x48, 0x45, 0x5e, 0x76, 0x05, 0x28, 0x56, + 0x0d, 0x28, 0xaa, 0xbc, 0xdc, 0xb5, 0x7c, 0x6a, 0x61, 0x60, 0x61, 0x7c, 0x8d, 0xe8, 0x7d, 0x0a, + 0xce, 0x05, 0x15, 0xd5, 0x5e, 0xea, 0x24, 0xe6, 0x38, 0x2a, 0x7a, 0x59, 0x28, 0xbc, 0xbf, 0x2c, + 0xe8, 0x67, 0xde, 0x26, 0xee, 0xd7, 0x60, 0x6b, 0xab, 0x70, 0xad, 0x71, 0x7b, 0xe2, 0x4c, 0x3f, + 0xda, 0x9c, 0x72, 0xd5, 0xdb, 0x9f, 0xe9, 0xf2, 0xe2, 0x1b, 0x16, 0x98, 0x5b, 0xa3, 0xdf, 0x61, + 0xb7, 0x50, 0xaa, 0xc1, 0x73, 0x92, 0x30, 0x41, 0x25, 0xe3, 0x6b, 0xf3, 0x78, 0x45, 0x83, 0xf6, + 0xa0, 0x2d, 0xf1, 0xca, 0xb0, 0x42, 0x1d, 0xd1, 0x10, 0x5a, 0x74, 0x69, 0x98, 0xd0, 0xa2, 0x4b, + 0x5d, 0x26, 0x27, 0x58, 0x92, 0xa5, 0x41, 0x7f, 0x2e, 0xaa, 0x8e, 0x0a, 0xfa, 0x1b, 0x31, 0xb8, + 0xd7, 0x67, 0xef, 0x4f, 0x0b, 0x1e, 0xbd, 0x26, 0x5c, 0x50, 0x16, 0x57, 0x1b, 0x75, 0x97, 0xa9, + 0xf2, 0x46, 0x19, 0x51, 0x75, 0x66, 0xc5, 0x8c, 0xbb, 0xc9, 0xa1, 0x54, 0x68, 0x2b, 0x95, 0xa7, + 0x2c, 0x8a, 0xa8, 0x34, 0x09, 0x95, 0x8a, 0x92, 0xf1, 0x0a, 0x34, 0x9d, 0x2a, 0xe3, 0x69, 0x44, + 0x34, 0x2b, 0xc5, 0x31, 0x5f, 0xdc, 0x16, 0xac, 0xd4, 0x92, 0xf7, 0x03, 0x0c, 0x02, 0x12, 0xb1, + 0x3b, 0x52, 0x99, 0x78, 0x09, 0x98, 0x76, 0x15, 0x30, 0x7b, 0xd0, 0xc6, 0x61, 0xa8, 0xd3, 0xda, + 0x09, 0xd4, 0x31, 0x23, 0x6d, 0x1a, 0x13, 0x9d, 0x8c, 0x26, 0x6d, 0x1a, 0x13, 0xef, 0x73, 0x18, + 0xe6, 0x21, 0x4d, 0xc1, 0x1e, 0xf4, 0x43, 0xbc, 0x26, 0xfc, 0x7b, 0x22, 0x04, 0x5e, 0xe5, 0x33, + 0xaf, 0xe9, 0xbc, 0x3f, 0x2c, 0xf8, 0xff, 0xb7, 0x04, 0x87, 0xf2, 0xf6, 0xf4, 0x96, 0x2c, 0xde, + 0x14, 0x77, 0x67, 0x60, 0x0b, 0x8d, 0x33, 0x7d, 0x6b, 0x38, 0x7d, 0xb6, 0x39, 0xfd, 0x2d, 0x97, + 0xfc, 0x4b, 0xb5, 0x73, 0xe3, 0x95, 0x01, 0xa8, 0x09, 0xe0, 0x7d, 0x05, 0x83, 0x9a, 0x01, 0x39, + 0xd0, 0xfb, 0x71, 0xfe, 0x72, 0xfe, 0xea, 0xa7, 0xf9, 0xde, 0xff, 0x94, 0x70, 0xf9, 0x22, 0x78, + 0x3d, 0x9b, 0x9f, 0xef, 0x59, 0xe8, 0x11, 0x38, 0xf3, 0x57, 0x57, 0x3f, 0xe7, 0x8a, 0x96, 0x97, + 0x40, 0xff, 0x82, 0xad, 0x68, 0x9c, 0xb7, 0x69, 0x1f, 0x6c, 0xb5, 0xd8, 0x09, 0x37, 0xc5, 0x18, + 0x09, 0x8d, 0x60, 0x27, 0x15, 0x84, 0xc7, 0x0a, 0xda, 0xd9, 0x00, 0x0b, 0x59, 0xd9, 0x12, 0x2c, + 0xc4, 0xaf, 0x8c, 0xe7, 0x78, 0x2a, 0x64, 0xd5, 0xdc, 0x37, 0x64, 0x6d, 0xe6, 0xa6, 0x8e, 0x8a, + 0x8b, 0xe6, 0xc5, 0x07, 0xf9, 0xf5, 0xa5, 0x76, 0x65, 0xa9, 0x7c, 0x28, 0xbb, 0xc6, 0x08, 0xbd, + 0x09, 0x0c, 0xf3, 0xab, 0xe6, 0x99, 0x7d, 0xb0, 0x39, 0x11, 0x69, 0x98, 0xbf, 0x62, 0x24, 0xef, + 0x03, 0x70, 0x2e, 0x18, 0x2e, 0x3e, 0x30, 0x08, 0x3a, 0x09, 0x96, 0xb7, 0xc6, 0x49, 0x9f, 0xbd, + 0x89, 0x6a, 0x12, 0x7e, 0x87, 0xe5, 0x33, 0xfd, 0xa7, 0x0b, 0xbd, 0xd3, 0xec, 0x7b, 0x88, 0xbe, + 0x81, 0xae, 0xde, 0x59, 0xe8, 0x70, 0xeb, 0xfa, 0x36, 0x0f, 0x8e, 0xde, 0xbf, 0xc7, 0x9a, 0xbd, + 0xf5, 0xd4, 0x52, 0x48, 0x31, 0x73, 0x6d, 0xb8, 0xd6, 0x96, 0xda, 0xe8, 0xf1, 0x7d, 0xe6, 0x22, + 0xd4, 0x31, 0x74, 0xd4, 0x52, 0x41, 0x07, 0xdb, 0x57, 0x4d, 0x16, 0xe6, 0xf0, 0xbf, 0xf6, 0x10, + 0x3a, 0x81, 0x5e, 0xce, 0xdb, 0xfd, 0xc6, 0xee, 0x7e, 0xa1, 0xbe, 0xed, 0xa3, 0x27, 0x9b, 0x01, + 0x36, 0x17, 0xc5, 0x0c, 0xec, 0x8c, 0x49, 0xcd, 0x8a, 0x6a, 0xa4, 0x6d, 0x56, 0x54, 0x27, 0xe0, + 0x53, 0x0b, 0x7d, 0x07, 0x4e, 0x85, 0x28, 0xf7, 0xa6, 0xf4, 0xe1, 0x3b, 0xb0, 0x0b, 0x9d, 0x41, + 0x57, 0x23, 0xb3, 0x39, 0xb0, 0x2a, 0x45, 0x9a, 0x03, 0xab, 0xc3, 0xf9, 0x1c, 0xec, 0x0c, 0x79, + 0x68, 0x9b, 0x63, 0x09, 0xe6, 0x66, 0x71, 0x1b, 0x80, 0x55, 0xc3, 0x62, 0x78, 0xb9, 0x65, 0x58, + 0x25, 0x5c, 0xb7, 0x0c, 0xab, 0x0a, 0xd4, 0x19, 0xd8, 0xd9, 0xb7, 0xba, 0x99, 0x4b, 0xed, 0x37, + 0xa0, 0x99, 0x4b, 0xfd, 0x13, 0x3f, 0xb1, 0xae, 0x6d, 0xdd, 0xd1, 0xcf, 0xfe, 0x0d, 0x00, 0x00, + 0xff, 0xff, 0xeb, 0x46, 0x9c, 0xd1, 0xfc, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1083,6 +1175,8 @@ type ControlClient interface { Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error) // Load requests an image tar load Load(ctx context.Context, in *LoadRequest, opts ...grpc.CallOption) (*LoadResponse, error) + // Import requests import a new image + Import(ctx context.Context, opts ...grpc.CallOption) (Control_ImportClient, error) } type controlClient struct { @@ -1243,6 +1337,40 @@ func (c *controlClient) Load(ctx context.Context, in *LoadRequest, opts ...grpc. return out, nil } +func (c *controlClient) Import(ctx context.Context, opts ...grpc.CallOption) (Control_ImportClient, error) { + stream, err := c.cc.NewStream(ctx, &_Control_serviceDesc.Streams[3], "/isula.build.v1.Control/Import", opts...) + if err != nil { + return nil, err + } + x := &controlImportClient{stream} + return x, nil +} + +type Control_ImportClient interface { + Send(*ImportRequest) error + CloseAndRecv() (*ImportResponse, error) + grpc.ClientStream +} + +type controlImportClient struct { + grpc.ClientStream +} + +func (x *controlImportClient) Send(m *ImportRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *controlImportClient) CloseAndRecv() (*ImportResponse, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(ImportResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // ControlServer is the server API for Control service. type ControlServer interface { // Build requests a new image building @@ -1263,6 +1391,8 @@ type ControlServer interface { Logout(context.Context, *LogoutRequest) (*LogoutResponse, error) // Load requests an image tar load Load(context.Context, *LoadRequest) (*LoadResponse, error) + // Import requests import a new image + Import(Control_ImportServer) error } // UnimplementedControlServer can be embedded to have forward compatible implementations. @@ -1296,6 +1426,9 @@ func (*UnimplementedControlServer) Logout(ctx context.Context, req *LogoutReques func (*UnimplementedControlServer) Load(ctx context.Context, req *LoadRequest) (*LoadResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Load not implemented") } +func (*UnimplementedControlServer) Import(srv Control_ImportServer) error { + return status.Errorf(codes.Unimplemented, "method Import not implemented") +} func RegisterControlServer(s *grpc.Server, srv ControlServer) { s.RegisterService(&_Control_serviceDesc, srv) @@ -1472,6 +1605,32 @@ func _Control_Load_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Control_Import_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(ControlServer).Import(&controlImportServer{stream}) +} + +type Control_ImportServer interface { + SendAndClose(*ImportResponse) error + Recv() (*ImportRequest, error) + grpc.ServerStream +} + +type controlImportServer struct { + grpc.ServerStream +} + +func (x *controlImportServer) SendAndClose(m *ImportResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *controlImportServer) Recv() (*ImportRequest, error) { + m := new(ImportRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + var _Control_serviceDesc = grpc.ServiceDesc{ ServiceName: "isula.build.v1.Control", HandlerType: (*ControlServer)(nil), @@ -1517,6 +1676,11 @@ var _Control_serviceDesc = grpc.ServiceDesc{ Handler: _Control_Remove_Handler, ServerStreams: true, }, + { + StreamName: "Import", + Handler: _Control_Import_Handler, + ClientStreams: true, + }, }, Metadata: "api/services/control.proto", } diff --git a/api/services/control.proto b/api/services/control.proto index 81cc769..0efad95 100644 --- a/api/services/control.proto +++ b/api/services/control.proto @@ -36,6 +36,8 @@ service Control { rpc Logout(LogoutRequest) returns (LogoutResponse); // Load requests an image tar load rpc Load(LoadRequest) returns (LoadResponse); + // Import requests import a new image + rpc Import(stream ImportRequest) returns (ImportResponse); } message BuildRequest { @@ -61,6 +63,18 @@ message BuildRequest { string encryptKey = 10; } +message ImportRequest { + // reference is reference of the import image + string reference = 1; + // data is the tarball of the import image + bytes data = 2; +} + +message ImportResponse { + // imageID is the ID of the import image + string imageID = 1; +} + message BuildStatic { // buildTime is a fixed time for binary equivalence build google.protobuf.Timestamp buildTime = 1; diff --git a/builder/dockerfile/cmd_builder_commit.go b/builder/dockerfile/cmd_builder_commit.go index 04c12c4..17c95e8 100644 --- a/builder/dockerfile/cmd_builder_commit.go +++ b/builder/dockerfile/cmd_builder_commit.go @@ -40,7 +40,8 @@ func newImageCopyOptions(reportWriter io.Writer) *cp.Options { } } -func getPolicyContext() (*signature.PolicyContext, error) { +// GetPolicyContext returns a specied policy context +func GetPolicyContext() (*signature.PolicyContext, error) { systemContext := image.GetSystemContext() systemContext.DirForceCompress = true commitPolicy, err := signature.DefaultPolicy(systemContext) @@ -124,7 +125,7 @@ func (c *cmdBuilder) commit(ctx context.Context) (string, error) { exporting = !c.isFromImageExist(storeTransport) } - policyContext, err := getPolicyContext() + policyContext, err := GetPolicyContext() if err != nil { return "", err } diff --git a/cmd/cli/build.go b/cmd/cli/build.go index aea71e3..5f4448e 100644 --- a/cmd/cli/build.go +++ b/cmd/cli/build.go @@ -84,6 +84,7 @@ func NewContainerImageBuildCmd() *cobra.Command { NewImagesCmd(), NewRemoveCmd(), NewLoadCmd(), + NewImportCmd(), ) return ctrImgBuildCmd diff --git a/cmd/cli/build_test.go b/cmd/cli/build_test.go index 054eda1..77d9716 100644 --- a/cmd/cli/build_test.go +++ b/cmd/cli/build_test.go @@ -57,12 +57,17 @@ type mockDaemon struct { loadReq *pb.LoadRequest loginReq *pb.LoginRequest logoutReq *pb.LogoutRequest + importReq *pb.ImportRequest } func newMockDaemon() *mockDaemon { return &mockDaemon{} } +func (f *mockDaemon) importImage(_ context.Context, opts ...grpc.CallOption) (pb.Control_ImportClient, error) { + return &mockImportClient{}, nil +} + func (f *mockDaemon) build(_ context.Context, in *pb.BuildRequest, opts ...grpc.CallOption) (pb.Control_BuildClient, error) { f.buildReq = in return &mockBuildClient{}, nil diff --git a/cmd/cli/grpc_client_test.go b/cmd/cli/grpc_client_test.go index 7ccd6f1..2c88cdd 100644 --- a/cmd/cli/grpc_client_test.go +++ b/cmd/cli/grpc_client_test.go @@ -40,6 +40,7 @@ type mockGrpcClient struct { loginFunc func(ctx context.Context, in *pb.LoginRequest, opts ...grpc.CallOption) (*pb.LoginResponse, error) logoutFunc func(ctx context.Context, in *pb.LogoutRequest, opts ...grpc.CallOption) (*pb.LogoutResponse, error) loadFunc func(ctx context.Context, in *pb.LoadRequest, opts ...grpc.CallOption) (*pb.LoadResponse, error) + importFunc func(ctx context.Context, opts ...grpc.CallOption) (pb.Control_ImportClient, error) } func (gcli *mockGrpcClient) Build(ctx context.Context, in *pb.BuildRequest, opts ...grpc.CallOption) (pb.Control_BuildClient, error) { @@ -49,6 +50,13 @@ func (gcli *mockGrpcClient) Build(ctx context.Context, in *pb.BuildRequest, opts return &mockBuildClient{isArchive: true}, nil } +func (gcli *mockGrpcClient) Import(ctx context.Context, opts ...grpc.CallOption) (pb.Control_ImportClient, error) { + if gcli.importFunc != nil { + return gcli.importFunc(ctx, opts...) + } + return nil, nil +} + func (gcli *mockGrpcClient) Remove(ctx context.Context, in *pb.RemoveRequest, opts ...grpc.CallOption) (pb.Control_RemoveClient, error) { if gcli.removeFunc != nil { return gcli.removeFunc(ctx, in, opts...) @@ -118,6 +126,10 @@ type mockBuildClient struct { isArchive bool } +type mockImportClient struct { + grpc.ClientStream +} + type mockStatusClient struct { grpc.ClientStream } @@ -137,6 +149,17 @@ func (bcli *mockBuildClient) Recv() (*pb.BuildResponse, error) { return resp, nil } +func (icli *mockImportClient) CloseAndRecv() (*pb.ImportResponse, error) { + resp := &pb.ImportResponse{ + ImageID: imageID, + } + return resp, nil +} + +func (icli *mockImportClient) Send(*pb.ImportRequest) error { + return nil +} + func (scli *mockStatusClient) Recv() (*pb.StatusResponse, error) { resp := &pb.StatusResponse{ Content: content, diff --git a/cmd/cli/import.go b/cmd/cli/import.go new file mode 100644 index 0000000..44ce50b --- /dev/null +++ b/cmd/cli/import.go @@ -0,0 +1,126 @@ +// Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. +// isula-build licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +// PURPOSE. +// See the Mulan PSL v2 for more details. +// Author: Zekun Liu +// Create: 2020-07-16 +// Description: This file is used for command import + +package main + +import ( + "bufio" + "context" + "fmt" + "io" + "os" + + dockerref "github.com/containers/image/v5/docker/reference" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + pb "isula.org/isula-build/api/services" + "isula.org/isula-build/util" +) + +const ( + bufferSize = 32 * 1024 + maxTarballSize = 10 * 1024 * 1024 * 1024 // support tarball max size at most 10G + importExample = `isula-build ctr-img import file [REPOSITORY[:TAG]]` + importArgsLen = 1 +) + +type importOptions struct { + source string + reference string +} + +var importOpts importOptions + +// NewImportCmd returns import command +func NewImportCmd() *cobra.Command { + importCmd := &cobra.Command{ + Use: "import", + Short: "Import the base image from a tarball to the image store", + Example: importExample, + RunE: importCommand, + } + return importCmd +} + +func importCommand(c *cobra.Command, args []string) error { + if len(args) < importArgsLen { + return errors.New("requires at least one argument") + } + if err := util.CheckFileSize(args[0], maxTarballSize); err != nil { + return err + } + importOpts.source = args[0] + if len(args) > importArgsLen { + importOpts.reference = args[1] + } + + ctx := context.TODO() + cli, err := NewClient(ctx) + if err != nil { + return err + } + return runImport(ctx, cli) +} + +func runImport(ctx context.Context, cli Cli) error { + if importOpts.reference != "" { + if _, err := dockerref.Parse(importOpts.reference); err != nil { + return err + } + } + file, err := os.Open(importOpts.source) + if err != nil { + return err + } + defer func() { + if ferr := file.Close(); ferr != nil { + logrus.Warnf("Close file %s failed", importOpts.source) + } + }() + + rpcCli, err := cli.Client().Import(ctx) + if err != nil { + return err + } + + reader := bufio.NewReader(file) + buf := make([]byte, bufferSize, bufferSize) + var length int + for { + length, err = reader.Read(buf) + if err != nil && err != io.EOF { + return err + } + if length == 0 { + break + } + if err = rpcCli.Send(&pb.ImportRequest{ + Data: buf[0:length], + Reference: importOpts.reference, + }); err != nil { + return err + } + } + + resp, err := rpcCli.CloseAndRecv() + if err != nil { + return err + } + if resp == nil { + return errors.New("import failed, got nil response") + } + fmt.Printf("Import success with image id: %s\n", resp.ImageID) + return nil +} diff --git a/daemon/import.go b/daemon/import.go new file mode 100644 index 0000000..681d33b --- /dev/null +++ b/daemon/import.go @@ -0,0 +1,111 @@ +// Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. +// isula-build licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +// PURPOSE. +// See the Mulan PSL v2 for more details. +// Author: Zekun Liu +// Create: 2020-07-22 +// Description: This file is "import" command for backend + +package daemon + +import ( + "io" + "strings" + + cp "github.com/containers/image/v5/copy" + dockerref "github.com/containers/image/v5/docker/reference" + is "github.com/containers/image/v5/storage" + "github.com/containers/image/v5/tarball" + "github.com/containers/image/v5/transports" + "github.com/containers/storage/pkg/stringid" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + pb "isula.org/isula-build/api/services" + "isula.org/isula-build/builder/dockerfile" + "isula.org/isula-build/util" +) + +const ( + tmpFilePattern = "isula-build-ctr-img-import" + noneReference = ":" + bufLen = 1024 +) + +// Import an image from a tarball +func (b *Backend) Import(serv pb.Control_ImportServer) error { + localStore := b.daemon.localStore + buf := make([]byte, 0, bufLen) + reference := "" + for { + msg, ierr := serv.Recv() + if ierr == io.EOF { + break + } + if ierr != nil { + return ierr + } + if msg == nil { + return errors.New("import failed, receive nil msg") + } + reference = msg.Reference + buf = append(buf, msg.Data...) + } + + logrus.Infof("Received and import image %q", reference) + reference, err := parseReference(reference) + if err != nil { + return err + } + srcRef, err := tarball.NewReference([]string{"-"}, buf) + if err != nil { + return err + } + + tmpName := stringid.GenerateRandomID() + "-import-tmp" + dstRef, err := is.Transport.ParseStoreReference(localStore, tmpName) + if err != nil { + return err + } + policyContext, err := dockerfile.GetPolicyContext() + if err != nil { + return err + } + if _, err = cp.Image(serv.Context(), policyContext, dstRef, srcRef, nil); err != nil { + return err + } + img, err := is.Transport.GetStoreImage(localStore, dstRef) + if err != nil { + return errors.Wrapf(err, "error locating image %q in local storage after import", transports.ImageName(dstRef)) + } + img.Names = append(img.Names, reference) + newNames := util.CopyStringsWithoutSpecificElem(img.Names, tmpName) + if err = localStore.SetNames(img.ID, newNames); err != nil { + return errors.Wrapf(err, "failed to prune temporary name from image %q", img.ID) + } + + resp := &pb.ImportResponse{ImageID: img.ID} + if err = serv.SendAndClose(resp); err != nil { + return err + } + logrus.Infof("Import success with image id %q", img.ID) + + return nil +} + +func parseReference(ref string) (string, error) { + ref = strings.TrimSpace(ref) + if ref == "" { + return noneReference, nil + } + if _, err := dockerref.Parse(ref); err != nil { + return "", err + } + + return ref, nil +} diff --git a/daemon/import_test.go b/daemon/import_test.go new file mode 100644 index 0000000..5c46244 --- /dev/null +++ b/daemon/import_test.go @@ -0,0 +1,77 @@ +// Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. +// isula-build licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +// PURPOSE. +// See the Mulan PSL v2 for more details. +// Author: Zekun Liu +// Create: 2020-07-25 +// Description: This is test file for daemon import.go + +package daemon + +import ( + "testing" + + "gotest.tools/assert" +) + +func TestParseReference(t *testing.T) { + type testcase struct { + name string + reference string + expect string + isErr bool + errStr string + } + var testcases = []testcase{ + { + name: "repo only", + reference: "busybox", + expect: "busybox", + }, + { + name: "repo and tag", + reference: "busybox:latest", + expect: "busybox:latest", + }, + { + name: "ref with tag missing", + reference: "busybox:", + isErr: true, + errStr: "invalid reference format", + }, + { + name: "empty ref", + reference: "", + expect: noneReference, + }, + { + name: "ref with no tag", + reference: "busybox", + expect: "busybox", + }, + { + name: "ref with space", + reference: "busybox: latest", + isErr: true, + errStr: "invalid reference format", + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + ref, err := parseReference(tc.reference) + assert.Equal(t, err != nil, tc.isErr, tc.name) + if err != nil { + assert.ErrorContains(t, err, tc.errStr, tc.name) + } + if err == nil { + assert.Equal(t, ref, tc.expect, tc.name) + } + }) + } +} -- GitLab