From 11adbe05cd008d6debcf9b0e04cb57dc430b2482 Mon Sep 17 00:00:00 2001 From: xiadanni Date: Tue, 22 Dec 2020 10:18:12 +0800 Subject: [PATCH] manifest: add manifest create/annotate/inspect Signed-off-by: xiadanni --- api/services/control.pb.go | 570 ++++++++++++++++++---- api/services/control.proto | 31 ++ builder/dockerfile/container/help.go | 5 +- builder/dockerfile/container/help_test.go | 2 +- cmd/cli/main.go | 5 + cmd/cli/manifest.go | 205 ++++++++ cmd/cli/manifest_test.go | 86 ++++ cmd/cli/mock.go | 18 + cmd/daemon/config/config.go | 13 +- cmd/daemon/main.go | 7 +- daemon/daemon.go | 1 + daemon/manifest.go | 351 +++++++++++++ 12 files changed, 1182 insertions(+), 112 deletions(-) create mode 100644 cmd/cli/manifest.go create mode 100644 cmd/cli/manifest_test.go create mode 100644 daemon/manifest.go diff --git a/api/services/control.pb.go b/api/services/control.pb.go index 2697610..713eb2c 100644 --- a/api/services/control.pb.go +++ b/api/services/control.pb.go @@ -1797,6 +1797,244 @@ func (m *InfoResponse) GetMemStat() *MemStat { return nil } +type ManifestCreateRequest struct { + ManifestList string `protobuf:"bytes,1,opt,name=manifestList,proto3" json:"manifestList,omitempty"` + Manifests []string `protobuf:"bytes,2,rep,name=manifests,proto3" json:"manifests,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ManifestCreateRequest) Reset() { *m = ManifestCreateRequest{} } +func (m *ManifestCreateRequest) String() string { return proto.CompactTextString(m) } +func (*ManifestCreateRequest) ProtoMessage() {} +func (*ManifestCreateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d71ef680555cb937, []int{32} +} +func (m *ManifestCreateRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ManifestCreateRequest.Unmarshal(m, b) +} +func (m *ManifestCreateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ManifestCreateRequest.Marshal(b, m, deterministic) +} +func (m *ManifestCreateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ManifestCreateRequest.Merge(m, src) +} +func (m *ManifestCreateRequest) XXX_Size() int { + return xxx_messageInfo_ManifestCreateRequest.Size(m) +} +func (m *ManifestCreateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ManifestCreateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ManifestCreateRequest proto.InternalMessageInfo + +func (m *ManifestCreateRequest) GetManifestList() string { + if m != nil { + return m.ManifestList + } + return "" +} + +func (m *ManifestCreateRequest) GetManifests() []string { + if m != nil { + return m.Manifests + } + return nil +} + +type ManifestCreateResponse struct { + 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 *ManifestCreateResponse) Reset() { *m = ManifestCreateResponse{} } +func (m *ManifestCreateResponse) String() string { return proto.CompactTextString(m) } +func (*ManifestCreateResponse) ProtoMessage() {} +func (*ManifestCreateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d71ef680555cb937, []int{33} +} +func (m *ManifestCreateResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ManifestCreateResponse.Unmarshal(m, b) +} +func (m *ManifestCreateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ManifestCreateResponse.Marshal(b, m, deterministic) +} +func (m *ManifestCreateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ManifestCreateResponse.Merge(m, src) +} +func (m *ManifestCreateResponse) XXX_Size() int { + return xxx_messageInfo_ManifestCreateResponse.Size(m) +} +func (m *ManifestCreateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ManifestCreateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ManifestCreateResponse proto.InternalMessageInfo + +func (m *ManifestCreateResponse) GetImageID() string { + if m != nil { + return m.ImageID + } + return "" +} + +type ManifestAnnotateRequest struct { + ManifestList string `protobuf:"bytes,1,opt,name=manifestList,proto3" json:"manifestList,omitempty"` + Manifest string `protobuf:"bytes,2,opt,name=manifest,proto3" json:"manifest,omitempty"` + Arch string `protobuf:"bytes,3,opt,name=arch,proto3" json:"arch,omitempty"` + Os string `protobuf:"bytes,4,opt,name=os,proto3" json:"os,omitempty"` + OsFeatures []string `protobuf:"bytes,5,rep,name=osFeatures,proto3" json:"osFeatures,omitempty"` + Variant string `protobuf:"bytes,6,opt,name=variant,proto3" json:"variant,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ManifestAnnotateRequest) Reset() { *m = ManifestAnnotateRequest{} } +func (m *ManifestAnnotateRequest) String() string { return proto.CompactTextString(m) } +func (*ManifestAnnotateRequest) ProtoMessage() {} +func (*ManifestAnnotateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d71ef680555cb937, []int{34} +} +func (m *ManifestAnnotateRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ManifestAnnotateRequest.Unmarshal(m, b) +} +func (m *ManifestAnnotateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ManifestAnnotateRequest.Marshal(b, m, deterministic) +} +func (m *ManifestAnnotateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ManifestAnnotateRequest.Merge(m, src) +} +func (m *ManifestAnnotateRequest) XXX_Size() int { + return xxx_messageInfo_ManifestAnnotateRequest.Size(m) +} +func (m *ManifestAnnotateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ManifestAnnotateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ManifestAnnotateRequest proto.InternalMessageInfo + +func (m *ManifestAnnotateRequest) GetManifestList() string { + if m != nil { + return m.ManifestList + } + return "" +} + +func (m *ManifestAnnotateRequest) GetManifest() string { + if m != nil { + return m.Manifest + } + return "" +} + +func (m *ManifestAnnotateRequest) GetArch() string { + if m != nil { + return m.Arch + } + return "" +} + +func (m *ManifestAnnotateRequest) GetOs() string { + if m != nil { + return m.Os + } + return "" +} + +func (m *ManifestAnnotateRequest) GetOsFeatures() []string { + if m != nil { + return m.OsFeatures + } + return nil +} + +func (m *ManifestAnnotateRequest) GetVariant() string { + if m != nil { + return m.Variant + } + return "" +} + +type ManifestInspectRequest struct { + ManifestList string `protobuf:"bytes,1,opt,name=manifestList,proto3" json:"manifestList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ManifestInspectRequest) Reset() { *m = ManifestInspectRequest{} } +func (m *ManifestInspectRequest) String() string { return proto.CompactTextString(m) } +func (*ManifestInspectRequest) ProtoMessage() {} +func (*ManifestInspectRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d71ef680555cb937, []int{35} +} +func (m *ManifestInspectRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ManifestInspectRequest.Unmarshal(m, b) +} +func (m *ManifestInspectRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ManifestInspectRequest.Marshal(b, m, deterministic) +} +func (m *ManifestInspectRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ManifestInspectRequest.Merge(m, src) +} +func (m *ManifestInspectRequest) XXX_Size() int { + return xxx_messageInfo_ManifestInspectRequest.Size(m) +} +func (m *ManifestInspectRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ManifestInspectRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ManifestInspectRequest proto.InternalMessageInfo + +func (m *ManifestInspectRequest) GetManifestList() string { + if m != nil { + return m.ManifestList + } + return "" +} + +type ManifestInspectResponse struct { + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ManifestInspectResponse) Reset() { *m = ManifestInspectResponse{} } +func (m *ManifestInspectResponse) String() string { return proto.CompactTextString(m) } +func (*ManifestInspectResponse) ProtoMessage() {} +func (*ManifestInspectResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d71ef680555cb937, []int{36} +} +func (m *ManifestInspectResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ManifestInspectResponse.Unmarshal(m, b) +} +func (m *ManifestInspectResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ManifestInspectResponse.Marshal(b, m, deterministic) +} +func (m *ManifestInspectResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ManifestInspectResponse.Merge(m, src) +} +func (m *ManifestInspectResponse) XXX_Size() int { + return xxx_messageInfo_ManifestInspectResponse.Size(m) +} +func (m *ManifestInspectResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ManifestInspectResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ManifestInspectResponse proto.InternalMessageInfo + +func (m *ManifestInspectResponse) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + func init() { proto.RegisterEnum("isula.build.v1.HealthCheckResponse_ServingStatus", HealthCheckResponse_ServingStatus_name, HealthCheckResponse_ServingStatus_value) proto.RegisterType((*BuildRequest)(nil), "isula.build.v1.BuildRequest") @@ -1832,112 +2070,128 @@ func init() { proto.RegisterType((*RegistryData)(nil), "isula.build.v1.RegistryData") proto.RegisterType((*InfoRequest)(nil), "isula.build.v1.InfoRequest") proto.RegisterType((*InfoResponse)(nil), "isula.build.v1.InfoResponse") + proto.RegisterType((*ManifestCreateRequest)(nil), "isula.build.v1.ManifestCreateRequest") + proto.RegisterType((*ManifestCreateResponse)(nil), "isula.build.v1.ManifestCreateResponse") + proto.RegisterType((*ManifestAnnotateRequest)(nil), "isula.build.v1.ManifestAnnotateRequest") + proto.RegisterType((*ManifestInspectRequest)(nil), "isula.build.v1.ManifestInspectRequest") + proto.RegisterType((*ManifestInspectResponse)(nil), "isula.build.v1.ManifestInspectResponse") } func init() { proto.RegisterFile("api/services/control.proto", fileDescriptor_d71ef680555cb937) } var fileDescriptor_d71ef680555cb937 = []byte{ - // 1589 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xcd, 0x72, 0xdb, 0x46, - 0x12, 0x5e, 0x10, 0x14, 0x45, 0x35, 0x28, 0x59, 0x85, 0x75, 0x79, 0x51, 0xb4, 0x6c, 0x6b, 0xb1, - 0xae, 0x5d, 0xad, 0xb6, 0x8a, 0x92, 0xb5, 0x7b, 0x58, 0xa7, 0x2a, 0xa9, 0x48, 0x94, 0xed, 0x30, - 0xb1, 0xe5, 0x18, 0x92, 0x9d, 0x5b, 0x5c, 0x23, 0x72, 0x44, 0xa1, 0x0c, 0x60, 0x90, 0x99, 0x81, - 0x6c, 0x26, 0x8f, 0x90, 0x6b, 0x8e, 0xc9, 0x2d, 0xd7, 0x9c, 0xf3, 0x10, 0x79, 0xa9, 0x54, 0xcf, - 0x0f, 0x00, 0x12, 0x94, 0xed, 0x1b, 0xbe, 0xaf, 0x7b, 0xba, 0x7b, 0x7a, 0x7a, 0x7a, 0x1a, 0xd0, - 0x27, 0x79, 0xbc, 0x27, 0x28, 0xbf, 0x8a, 0xc7, 0x54, 0xec, 0x8d, 0x59, 0x26, 0x39, 0x4b, 0x06, - 0x39, 0x67, 0x92, 0xf9, 0x1b, 0xb1, 0x28, 0x12, 0x32, 0x38, 0x2f, 0xe2, 0x64, 0x32, 0xb8, 0x7a, - 0xd0, 0xbf, 0x3d, 0x65, 0x6c, 0x9a, 0xd0, 0x3d, 0x25, 0x3d, 0x2f, 0x2e, 0xf6, 0x68, 0x9a, 0xcb, - 0x99, 0x56, 0xee, 0xdf, 0x5b, 0x14, 0xca, 0x38, 0xa5, 0x42, 0x92, 0x34, 0xd7, 0x0a, 0xe1, 0x6f, - 0x2e, 0xf4, 0x8e, 0xd0, 0x54, 0x44, 0xbf, 0x2b, 0xa8, 0x90, 0x7e, 0x00, 0xab, 0xca, 0xf4, 0xe8, - 0x38, 0x70, 0xb6, 0x9d, 0x9d, 0xb5, 0xc8, 0x42, 0x7f, 0x0b, 0xd6, 0xd4, 0xe7, 0xd9, 0x2c, 0xa7, - 0x41, 0x4b, 0xc9, 0x2a, 0xc2, 0xbf, 0x0b, 0x80, 0x71, 0xd2, 0x77, 0xf2, 0x38, 0xe6, 0x81, 0xab, - 0xc4, 0x35, 0xc6, 0xdf, 0x06, 0xef, 0x22, 0x4e, 0xe8, 0x10, 0x99, 0x4c, 0x06, 0x6d, 0xa5, 0x50, - 0xa7, 0xfc, 0x5b, 0xd0, 0x61, 0x85, 0xcc, 0x0b, 0x19, 0xac, 0x28, 0xa1, 0x41, 0xa5, 0xdf, 0x43, - 0x3e, 0x15, 0x41, 0x67, 0xdb, 0x2d, 0xfd, 0x22, 0xe1, 0xdf, 0x84, 0x95, 0x9c, 0xb3, 0x77, 0xb3, - 0x60, 0x75, 0xdb, 0xd9, 0xe9, 0x46, 0x1a, 0xe0, 0x2e, 0xe2, 0x78, 0x82, 0xd6, 0x83, 0xae, 0xde, - 0x85, 0x81, 0xfe, 0xa7, 0xe0, 0xa9, 0xc5, 0xa7, 0x92, 0xc8, 0x78, 0x1c, 0xac, 0x6d, 0x3b, 0x3b, - 0xde, 0xc1, 0xed, 0xc1, 0x7c, 0x52, 0x07, 0x47, 0x95, 0x4a, 0x54, 0xd7, 0xf7, 0xef, 0xc3, 0x3a, - 0x99, 0x4c, 0x62, 0x19, 0xb3, 0x8c, 0x24, 0x67, 0x64, 0x1a, 0x80, 0x32, 0x3f, 0x4f, 0xaa, 0x64, - 0x90, 0xfc, 0x70, 0x32, 0x79, 0x1a, 0x0b, 0x19, 0x78, 0x2a, 0xe6, 0x1a, 0xe3, 0xf7, 0xa1, 0x4b, - 0x33, 0x19, 0xcb, 0xd9, 0xe8, 0x38, 0xe8, 0x29, 0x03, 0x25, 0xc6, 0xed, 0xd2, 0x6c, 0xcc, 0x67, - 0xb9, 0xa4, 0x93, 0x60, 0x5d, 0x6d, 0xaa, 0x22, 0x42, 0x02, 0xeb, 0xa3, 0x34, 0x67, 0x5c, 0xda, - 0xf3, 0xea, 0x43, 0x37, 0x56, 0x44, 0x79, 0x60, 0x25, 0xc6, 0x8c, 0x0a, 0x56, 0xf0, 0xb1, 0x3d, - 0x2e, 0x83, 0xd0, 0x05, 0xa7, 0x17, 0x94, 0xd3, 0x6c, 0x4c, 0xcd, 0x51, 0x55, 0x44, 0x18, 0xc2, - 0x86, 0x75, 0x21, 0x72, 0x96, 0x09, 0xea, 0x6f, 0x82, 0x9b, 0xb0, 0xa9, 0x31, 0x8f, 0x9f, 0xe1, - 0x13, 0xf0, 0x6a, 0x29, 0xf2, 0xff, 0x6f, 0x4b, 0x23, 0x4e, 0xa9, 0x52, 0xf3, 0x0e, 0xfa, 0x03, - 0x5d, 0x7a, 0x03, 0x5b, 0x7a, 0x83, 0x33, 0x5b, 0x7a, 0x51, 0xa5, 0x1c, 0xfe, 0x1b, 0xd6, 0x4d, - 0xf9, 0x19, 0x5f, 0x78, 0x72, 0x29, 0x99, 0xd2, 0xaa, 0xfe, 0x0c, 0x44, 0x55, 0x74, 0x57, 0x88, - 0x0f, 0x96, 0x6a, 0xb8, 0x0b, 0x1b, 0x56, 0xb5, 0x32, 0x3b, 0x36, 0xa5, 0x67, 0x74, 0x0d, 0x0c, - 0xff, 0x03, 0x1e, 0x9e, 0x89, 0x35, 0xba, 0x05, 0x6b, 0xca, 0xe1, 0x09, 0x31, 0x5b, 0x59, 0x8b, - 0x2a, 0x22, 0xfc, 0x1f, 0xc0, 0x19, 0x99, 0x5a, 0xdd, 0x9b, 0xb0, 0xa2, 0x44, 0x46, 0x4f, 0x03, - 0xcc, 0x96, 0x24, 0x53, 0x93, 0x72, 0xfc, 0x0c, 0xff, 0x70, 0xa0, 0xa7, 0x7d, 0x98, 0x68, 0x3e, - 0x83, 0x8e, 0xd2, 0x15, 0x81, 0xb3, 0xed, 0xee, 0x78, 0x07, 0xff, 0x5c, 0xac, 0xbf, 0xba, 0xf6, - 0x60, 0xa4, 0x12, 0x90, 0x5d, 0xb0, 0xc8, 0xac, 0xea, 0xff, 0x00, 0x6b, 0x25, 0x89, 0xc5, 0xc6, - 0x69, 0xce, 0x44, 0x2c, 0x19, 0x9f, 0x99, 0x50, 0x6a, 0x4c, 0x33, 0x1e, 0x7f, 0x03, 0x5a, 0xf1, - 0xc4, 0x1c, 0x7c, 0x2b, 0x9e, 0xa8, 0xe4, 0x70, 0x4a, 0xb0, 0xe0, 0xda, 0x26, 0x39, 0x1a, 0xfa, - 0x3e, 0xb4, 0x45, 0xfc, 0x3d, 0x35, 0x37, 0x52, 0x7d, 0x87, 0xbf, 0x38, 0x70, 0xe3, 0x15, 0xe5, - 0x22, 0x66, 0x59, 0x3d, 0xbd, 0x57, 0x9a, 0xb2, 0xe9, 0x35, 0x10, 0xf3, 0x39, 0x65, 0x46, 0xdd, - 0x76, 0x8d, 0x92, 0x50, 0xd2, 0x58, 0x0e, 0x59, 0x9a, 0xc6, 0xd2, 0x56, 0x62, 0x49, 0x54, 0x1d, - 0x07, 0xcb, 0xaa, 0x5d, 0xef, 0x38, 0x71, 0x4a, 0x55, 0xbf, 0x10, 0x87, 0x7c, 0x7c, 0x59, 0xf6, - 0x0b, 0x85, 0xc2, 0x17, 0xb0, 0x1e, 0xd1, 0x94, 0x5d, 0xd1, 0x5a, 0x9d, 0x54, 0x25, 0xe5, 0xd6, - 0x4a, 0x0a, 0x53, 0x43, 0x92, 0x44, 0x85, 0xd5, 0x8d, 0xf0, 0x53, 0xb7, 0x93, 0x22, 0xd3, 0xd7, - 0x42, 0xb5, 0x93, 0x22, 0xc3, 0x63, 0xdf, 0xb0, 0x26, 0xcd, 0x86, 0x43, 0xe8, 0x25, 0x64, 0x46, - 0xf9, 0x33, 0x2a, 0x44, 0x55, 0x01, 0x73, 0x5c, 0xf8, 0xb3, 0x03, 0x7f, 0xfd, 0x82, 0x92, 0x44, - 0x5e, 0x0e, 0x2f, 0xe9, 0xf8, 0x4d, 0xb9, 0x76, 0x04, 0x1d, 0xa1, 0xaa, 0x53, 0xad, 0xda, 0x38, - 0x78, 0xb0, 0x78, 0xfa, 0x4b, 0x16, 0x0d, 0x4e, 0xf1, 0x35, 0xc8, 0xa6, 0xa6, 0xac, 0x8d, 0x81, - 0xf0, 0x13, 0x58, 0x9f, 0x13, 0xf8, 0x1e, 0xac, 0xbe, 0x3c, 0xf9, 0xea, 0xe4, 0xf9, 0x37, 0x27, - 0x9b, 0x7f, 0x41, 0x70, 0xfa, 0x28, 0x7a, 0x35, 0x3a, 0x79, 0xb2, 0xe9, 0xf8, 0x37, 0xc0, 0x3b, - 0x79, 0x7e, 0xf6, 0xda, 0x12, 0xad, 0xf0, 0x5b, 0xe8, 0x3d, 0x65, 0xd3, 0x38, 0xb3, 0x69, 0xc2, - 0x6e, 0x41, 0xf9, 0x15, 0xe5, 0x66, 0x33, 0x06, 0x61, 0x87, 0x29, 0x04, 0xe5, 0x19, 0x5e, 0x08, - 0x7d, 0x80, 0x25, 0x46, 0x59, 0x4e, 0x84, 0x78, 0xcb, 0xb8, 0xad, 0xa7, 0x12, 0xe3, 0x7d, 0x35, - 0xf6, 0x3f, 0x78, 0x07, 0x1f, 0x2a, 0x55, 0x56, 0xc8, 0x0f, 0xc5, 0xd2, 0x38, 0xb0, 0x70, 0x07, - 0x36, 0xec, 0x52, 0xe3, 0xe6, 0x16, 0x74, 0x38, 0x15, 0x45, 0x62, 0xbd, 0x18, 0x14, 0xfe, 0x1d, - 0xbc, 0xa7, 0x8c, 0x94, 0x0f, 0x9d, 0x0f, 0xed, 0x9c, 0xc8, 0x4b, 0xa3, 0xa4, 0xbe, 0xc3, 0x6d, - 0x4c, 0x09, 0x99, 0xbc, 0xa7, 0xf1, 0x0d, 0xc1, 0xfb, 0xba, 0x10, 0x97, 0xb5, 0x38, 0xf3, 0x42, - 0x5c, 0x96, 0x1d, 0xc8, 0xa0, 0xf9, 0x2e, 0xd2, 0x5a, 0xec, 0x22, 0xbb, 0xd0, 0xd3, 0x46, 0x8c, - 0x9b, 0x3e, 0x74, 0xb9, 0xf9, 0xb6, 0x3d, 0xdc, 0x62, 0xed, 0x30, 0x49, 0xe6, 0x1c, 0x26, 0x49, - 0xdd, 0x21, 0xa2, 0x8f, 0x71, 0x88, 0x46, 0x3e, 0xc2, 0xe1, 0x0b, 0xf0, 0x4e, 0x49, 0x75, 0x79, - 0xf0, 0x24, 0xc8, 0x55, 0xd5, 0x8e, 0x0d, 0x42, 0xde, 0xb4, 0xb0, 0x96, 0xba, 0x53, 0x06, 0x95, - 0x69, 0x75, 0xe7, 0xd3, 0xaa, 0x4d, 0x5e, 0x9b, 0xd6, 0x19, 0xac, 0x3e, 0xa3, 0xe9, 0x31, 0x91, - 0x04, 0x63, 0x4b, 0x69, 0x7a, 0xc6, 0x24, 0x49, 0x94, 0x86, 0x1b, 0x95, 0x18, 0x2b, 0x28, 0xa5, - 0xe9, 0x63, 0x4e, 0xf5, 0x1e, 0xdd, 0xc8, 0x42, 0xdc, 0xbf, 0x78, 0x4b, 0x72, 0xbd, 0xcc, 0x55, - 0xb2, 0x8a, 0x40, 0x9b, 0x08, 0xd4, 0xc2, 0xb6, 0xb6, 0x69, 0x71, 0xf8, 0xbb, 0xa3, 0x7c, 0xe3, - 0xfd, 0xc1, 0x4d, 0xa5, 0x34, 0x3d, 0x9d, 0xe9, 0x9b, 0xd9, 0x8e, 0x0c, 0x42, 0xbf, 0x97, 0x94, - 0xe4, 0x28, 0x68, 0x29, 0x81, 0x85, 0xe8, 0x17, 0x3f, 0x0f, 0x93, 0x84, 0x8d, 0x95, 0xdf, 0x76, - 0x54, 0x11, 0x56, 0x3a, 0xca, 0x5e, 0x0a, 0xed, 0xd8, 0x48, 0x15, 0x81, 0x51, 0x29, 0x30, 0x49, - 0x74, 0x83, 0x6d, 0x47, 0x25, 0xc6, 0xfe, 0x82, 0xdf, 0x11, 0x4d, 0x28, 0x11, 0x74, 0x12, 0x74, - 0x94, 0x7c, 0x8e, 0x0b, 0x5f, 0x83, 0x77, 0x2a, 0x19, 0x27, 0x53, 0xaa, 0x12, 0x77, 0x1f, 0xd6, - 0x85, 0x81, 0x3c, 0xae, 0xae, 0xce, 0x3c, 0xe9, 0xef, 0xc2, 0xa6, 0x21, 0x8e, 0xc8, 0xf8, 0x4d, - 0x9c, 0x4d, 0x1f, 0x0b, 0x53, 0x2f, 0x0d, 0x3e, 0xfc, 0xc9, 0x81, 0x5e, 0x44, 0xa7, 0xb1, 0x90, - 0x7c, 0xa6, 0x5c, 0xec, 0xc2, 0x26, 0xd7, 0x38, 0xa6, 0xe2, 0x94, 0x12, 0x6c, 0xbe, 0xba, 0xa5, - 0x36, 0x78, 0x7f, 0x00, 0x7e, 0xc5, 0x8d, 0x32, 0x41, 0xc7, 0x05, 0xa7, 0xa6, 0x58, 0x96, 0x48, - 0xfc, 0x1d, 0xb8, 0x51, 0xb1, 0x47, 0x09, 0x1b, 0xbf, 0x09, 0x5c, 0xa5, 0xbc, 0x48, 0x87, 0xff, - 0x02, 0x4f, 0xbd, 0x86, 0x55, 0x7b, 0xbf, 0xa2, 0xfc, 0x9c, 0x99, 0x5a, 0xee, 0x46, 0x16, 0x86, - 0x3f, 0xba, 0xd0, 0xd3, 0x9a, 0xa6, 0xf0, 0x1e, 0xa8, 0xfa, 0x41, 0xca, 0x4c, 0x29, 0x7f, 0x5b, - 0x6c, 0xbd, 0xa6, 0x0a, 0x23, 0xab, 0x87, 0xf3, 0xa2, 0xc9, 0x8b, 0x5a, 0xd6, 0x5a, 0x3e, 0x2f, - 0xd6, 0xce, 0x21, 0xaa, 0xeb, 0xfb, 0x9f, 0x43, 0xcf, 0x84, 0x3f, 0x53, 0xeb, 0x5d, 0xb5, 0x7e, - 0x6b, 0x71, 0x7d, 0x3d, 0xcb, 0xd1, 0xdc, 0x0a, 0xac, 0x92, 0x09, 0xb2, 0x8c, 0xd9, 0xa9, 0xb9, - 0xc4, 0xb8, 0x75, 0x5e, 0x64, 0x4a, 0xa4, 0xdf, 0x40, 0x0b, 0x71, 0x28, 0x78, 0x3e, 0x1c, 0x45, - 0x45, 0x86, 0x03, 0xbf, 0xaa, 0x9e, 0xb5, 0xa8, 0xc6, 0xa0, 0x5c, 0x39, 0xa7, 0xfc, 0xa4, 0x48, - 0xd5, 0xec, 0xec, 0x46, 0x35, 0x06, 0xe5, 0x53, 0x16, 0xb1, 0x42, 0xc6, 0x19, 0x15, 0x6a, 0x86, - 0x76, 0xa3, 0x1a, 0x63, 0x32, 0x89, 0x97, 0xc6, 0x8c, 0xd0, 0xcb, 0x32, 0x89, 0xe2, 0xc8, 0xea, - 0x1d, 0xfc, 0xda, 0x85, 0xd5, 0xa1, 0xfe, 0x95, 0xf1, 0x8f, 0x61, 0x45, 0x8d, 0x7d, 0xfe, 0xd6, - 0xd2, 0xc9, 0xdb, 0x1c, 0x6d, 0xff, 0xce, 0x35, 0xd2, 0xea, 0x21, 0x35, 0xcf, 0xde, 0x9d, 0xe6, - 0x81, 0xd4, 0x26, 0xc5, 0xfe, 0xdd, 0xeb, 0xc4, 0xda, 0xd0, 0xbe, 0xe3, 0x1f, 0x42, 0x5b, 0x4d, - 0xe6, 0xb7, 0x97, 0x4f, 0x62, 0xda, 0xcc, 0xd6, 0xfb, 0xc6, 0x34, 0xff, 0x08, 0x56, 0xed, 0x58, - 0x73, 0xab, 0x31, 0xfc, 0x3e, 0xc2, 0x9f, 0xb2, 0xfe, 0xbd, 0x45, 0x03, 0x8b, 0x73, 0xd4, 0x10, - 0xda, 0xf8, 0x32, 0x34, 0xc3, 0xa8, 0x3d, 0x3a, 0xcd, 0x30, 0xea, 0x8f, 0xc9, 0xbe, 0xa3, 0x8d, - 0x24, 0xc9, 0x32, 0x23, 0xe5, 0x43, 0xb2, 0xcc, 0x48, 0xf5, 0x40, 0xec, 0x3b, 0x98, 0x5b, 0x3d, - 0xf2, 0x34, 0x73, 0x3b, 0x37, 0x5d, 0x35, 0x73, 0x3b, 0x3f, 0x29, 0xed, 0x3b, 0xfe, 0x97, 0xe0, - 0xd5, 0x26, 0x9a, 0x6b, 0x93, 0xf3, 0x8f, 0x8f, 0x18, 0x83, 0xb0, 0x70, 0xd4, 0x50, 0xd1, 0x2c, - 0x9c, 0xfa, 0x2c, 0xd3, 0x2c, 0x9c, 0xf9, 0x49, 0xe4, 0x09, 0x74, 0xf4, 0xd0, 0xe0, 0x2f, 0x53, - 0xac, 0xe6, 0x90, 0xe6, 0xe6, 0x16, 0x66, 0x8d, 0x21, 0xb4, 0x71, 0x60, 0x58, 0x52, 0x36, 0xd5, - 0xa4, 0xb1, 0xa4, 0x6c, 0x6a, 0x33, 0x86, 0x4e, 0xb5, 0xfe, 0xe1, 0x6a, 0x46, 0x33, 0xf7, 0xaf, - 0xd7, 0x8c, 0x66, 0xfe, 0x3f, 0x6d, 0xdf, 0xf1, 0x1f, 0x82, 0x8b, 0xff, 0x9f, 0xfd, 0x45, 0xc5, - 0xea, 0xa7, 0xa5, 0x7f, 0x4d, 0xfa, 0x71, 0x2b, 0xf8, 0x48, 0x37, 0xb7, 0x52, 0x9b, 0x06, 0x9a, - 0x5b, 0xa9, 0xbf, 0xeb, 0xfa, 0x1a, 0xa9, 0xa6, 0xd5, 0x30, 0x52, 0x6b, 0xd8, 0x4d, 0x23, 0xf5, - 0x1e, 0x7d, 0xde, 0x51, 0x71, 0xfd, 0xf7, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd5, 0xc7, 0x01, - 0x9f, 0x04, 0x11, 0x00, 0x00, + // 1773 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x5f, 0x73, 0x23, 0x47, + 0x11, 0x67, 0x25, 0xf9, 0x5f, 0x4b, 0xd6, 0xb9, 0x86, 0x70, 0xd9, 0xd2, 0x39, 0x89, 0x59, 0x42, + 0xce, 0x1c, 0x85, 0xec, 0x33, 0x3c, 0x10, 0x0a, 0x28, 0x6c, 0x39, 0x77, 0x08, 0xee, 0x7c, 0x64, + 0xed, 0x84, 0xe2, 0x85, 0xab, 0xb1, 0x34, 0x5e, 0x6f, 0xdd, 0xee, 0xce, 0x32, 0x33, 0xeb, 0x44, + 0xf0, 0x11, 0x78, 0xe5, 0x11, 0x3e, 0x02, 0xcf, 0x79, 0xe3, 0x0b, 0xf0, 0xa5, 0x52, 0x3d, 0x7f, + 0xf6, 0x8f, 0x56, 0x8a, 0xef, 0xde, 0xf6, 0xd7, 0xdd, 0xd3, 0xdd, 0xd3, 0xd3, 0xd3, 0xf3, 0x5b, + 0x18, 0xd1, 0x3c, 0x3e, 0x92, 0x4c, 0xdc, 0xc5, 0x33, 0x26, 0x8f, 0x66, 0x3c, 0x53, 0x82, 0x27, + 0xe3, 0x5c, 0x70, 0xc5, 0xc9, 0x30, 0x96, 0x45, 0x42, 0xc7, 0xd7, 0x45, 0x9c, 0xcc, 0xc7, 0x77, + 0x4f, 0x47, 0x8f, 0x22, 0xce, 0xa3, 0x84, 0x1d, 0x69, 0xed, 0x75, 0x71, 0x73, 0xc4, 0xd2, 0x5c, + 0x2d, 0x8c, 0xf1, 0xe8, 0xa3, 0x65, 0xa5, 0x8a, 0x53, 0x26, 0x15, 0x4d, 0x73, 0x63, 0x10, 0xfc, + 0xb7, 0x0b, 0x83, 0x33, 0x74, 0x15, 0xb2, 0xbf, 0x15, 0x4c, 0x2a, 0xe2, 0xc3, 0x96, 0x76, 0x3d, + 0x3d, 0xf7, 0xbd, 0x03, 0xef, 0x70, 0x27, 0x74, 0x90, 0xec, 0xc3, 0x8e, 0xfe, 0xbc, 0x5a, 0xe4, + 0xcc, 0xef, 0x68, 0x5d, 0x25, 0x20, 0x1f, 0x02, 0x60, 0x9e, 0xec, 0x6b, 0x75, 0x1e, 0x0b, 0xbf, + 0xab, 0xd5, 0x35, 0x09, 0x39, 0x80, 0xfe, 0x4d, 0x9c, 0xb0, 0x09, 0x4a, 0x32, 0xe5, 0xf7, 0xb4, + 0x41, 0x5d, 0x44, 0x1e, 0xc2, 0x26, 0x2f, 0x54, 0x5e, 0x28, 0x7f, 0x43, 0x2b, 0x2d, 0x2a, 0xe3, + 0x9e, 0x8a, 0x48, 0xfa, 0x9b, 0x07, 0xdd, 0x32, 0x2e, 0x0a, 0xc8, 0x7b, 0xb0, 0x91, 0x0b, 0xfe, + 0xf5, 0xc2, 0xdf, 0x3a, 0xf0, 0x0e, 0xb7, 0x43, 0x03, 0x70, 0x17, 0x71, 0x3c, 0x47, 0xef, 0xfe, + 0xb6, 0xd9, 0x85, 0x85, 0xe4, 0x37, 0xd0, 0xd7, 0x8b, 0x2f, 0x15, 0x55, 0xf1, 0xcc, 0xdf, 0x39, + 0xf0, 0x0e, 0xfb, 0x27, 0x8f, 0xc6, 0xcd, 0xa2, 0x8e, 0xcf, 0x2a, 0x93, 0xb0, 0x6e, 0x4f, 0x3e, + 0x86, 0x5d, 0x3a, 0x9f, 0xc7, 0x2a, 0xe6, 0x19, 0x4d, 0xae, 0x68, 0xe4, 0x83, 0x76, 0xdf, 0x14, + 0xea, 0x62, 0xd0, 0xfc, 0x74, 0x3e, 0x7f, 0x11, 0x4b, 0xe5, 0xf7, 0x75, 0xce, 0x35, 0x09, 0x19, + 0xc1, 0x36, 0xcb, 0x54, 0xac, 0x16, 0xd3, 0x73, 0x7f, 0xa0, 0x1d, 0x94, 0x18, 0xb7, 0xcb, 0xb2, + 0x99, 0x58, 0xe4, 0x8a, 0xcd, 0xfd, 0x5d, 0xbd, 0xa9, 0x4a, 0x10, 0x50, 0xd8, 0x9d, 0xa6, 0x39, + 0x17, 0xca, 0x9d, 0xd7, 0x08, 0xb6, 0x63, 0x2d, 0x28, 0x0f, 0xac, 0xc4, 0x58, 0x51, 0xc9, 0x0b, + 0x31, 0x73, 0xc7, 0x65, 0x11, 0x86, 0x10, 0xec, 0x86, 0x09, 0x96, 0xcd, 0x98, 0x3d, 0xaa, 0x4a, + 0x10, 0x04, 0x30, 0x74, 0x21, 0x64, 0xce, 0x33, 0xc9, 0xc8, 0x1e, 0x74, 0x13, 0x1e, 0x59, 0xf7, + 0xf8, 0x19, 0x3c, 0x87, 0x7e, 0xad, 0x44, 0xe4, 0x97, 0xae, 0x35, 0xe2, 0x94, 0x69, 0xb3, 0xfe, + 0xc9, 0x68, 0x6c, 0x5a, 0x6f, 0xec, 0x5a, 0x6f, 0x7c, 0xe5, 0x5a, 0x2f, 0xac, 0x8c, 0x83, 0x9f, + 0xc0, 0xae, 0x6d, 0x3f, 0x1b, 0x0b, 0x4f, 0x2e, 0xa5, 0x11, 0xab, 0xfa, 0xcf, 0x42, 0x34, 0xc5, + 0x70, 0x85, 0xbc, 0xb7, 0x55, 0x83, 0x27, 0x30, 0x74, 0xa6, 0x95, 0xdb, 0x99, 0x6d, 0x3d, 0x6b, + 0x6b, 0x61, 0xf0, 0x53, 0xe8, 0xe3, 0x99, 0x38, 0xa7, 0xfb, 0xb0, 0xa3, 0x03, 0x5e, 0x50, 0xbb, + 0x95, 0x9d, 0xb0, 0x12, 0x04, 0xbf, 0x00, 0xb8, 0xa2, 0x91, 0xb3, 0x7d, 0x0f, 0x36, 0xb4, 0xca, + 0xda, 0x19, 0x80, 0xd5, 0x52, 0x34, 0xb2, 0x25, 0xc7, 0xcf, 0xe0, 0xff, 0x1e, 0x0c, 0x4c, 0x0c, + 0x9b, 0xcd, 0x6f, 0x61, 0x53, 0xdb, 0x4a, 0xdf, 0x3b, 0xe8, 0x1e, 0xf6, 0x4f, 0x3e, 0x59, 0xee, + 0xbf, 0xba, 0xf5, 0x78, 0xaa, 0x0b, 0x90, 0xdd, 0xf0, 0xd0, 0xae, 0x1a, 0xfd, 0x03, 0x76, 0x4a, + 0x21, 0x36, 0x9b, 0x60, 0x39, 0x97, 0xb1, 0xe2, 0x62, 0x61, 0x53, 0xa9, 0x49, 0xda, 0xf9, 0x90, + 0x21, 0x74, 0xe2, 0xb9, 0x3d, 0xf8, 0x4e, 0x3c, 0xd7, 0xc5, 0x11, 0x8c, 0x62, 0xc3, 0xf5, 0x6c, + 0x71, 0x0c, 0x24, 0x04, 0x7a, 0x32, 0xfe, 0x3b, 0xb3, 0x37, 0x52, 0x7f, 0x07, 0xff, 0xf1, 0xe0, + 0xc1, 0x97, 0x4c, 0xc8, 0x98, 0x67, 0xf5, 0xf2, 0xde, 0x19, 0x91, 0x2b, 0xaf, 0x85, 0x58, 0xcf, + 0x88, 0x5b, 0x73, 0x37, 0x35, 0x4a, 0x81, 0xd6, 0xc6, 0x6a, 0xc2, 0xd3, 0x34, 0x56, 0xae, 0x13, + 0x4b, 0x41, 0x35, 0x71, 0xb0, 0xad, 0x7a, 0xf5, 0x89, 0x13, 0xa7, 0x4c, 0xcf, 0x0b, 0x79, 0x2a, + 0x66, 0xb7, 0xe5, 0xbc, 0xd0, 0x28, 0xf8, 0x1c, 0x76, 0x43, 0x96, 0xf2, 0x3b, 0x56, 0xeb, 0x93, + 0xaa, 0xa5, 0xba, 0xb5, 0x96, 0xc2, 0xd2, 0xd0, 0x24, 0xd1, 0x69, 0x6d, 0x87, 0xf8, 0x69, 0xc6, + 0x49, 0x91, 0x99, 0x6b, 0xa1, 0xc7, 0x49, 0x91, 0xe1, 0xb1, 0x0f, 0x9d, 0x4b, 0xbb, 0xe1, 0x00, + 0x06, 0x09, 0x5d, 0x30, 0xf1, 0x92, 0x49, 0x59, 0x75, 0x40, 0x43, 0x16, 0xfc, 0xdb, 0x83, 0xef, + 0xff, 0x9e, 0xd1, 0x44, 0xdd, 0x4e, 0x6e, 0xd9, 0xec, 0x4d, 0xb9, 0x76, 0x0a, 0x9b, 0x52, 0x77, + 0xa7, 0x5e, 0x35, 0x3c, 0x79, 0xba, 0x7c, 0xfa, 0x2b, 0x16, 0x8d, 0x2f, 0xf1, 0x35, 0xc8, 0x22, + 0xdb, 0xd6, 0xd6, 0x41, 0xf0, 0x2b, 0xd8, 0x6d, 0x28, 0x48, 0x1f, 0xb6, 0xbe, 0xb8, 0xf8, 0xe3, + 0xc5, 0xab, 0x3f, 0x5f, 0xec, 0x7d, 0x0f, 0xc1, 0xe5, 0x67, 0xe1, 0x97, 0xd3, 0x8b, 0xe7, 0x7b, + 0x1e, 0x79, 0x00, 0xfd, 0x8b, 0x57, 0x57, 0xaf, 0x9d, 0xa0, 0x13, 0xfc, 0x15, 0x06, 0x2f, 0x78, + 0x14, 0x67, 0xae, 0x4c, 0x38, 0x2d, 0x98, 0xb8, 0x63, 0xc2, 0x6e, 0xc6, 0x22, 0x9c, 0x30, 0x85, + 0x64, 0x22, 0xc3, 0x0b, 0x61, 0x0e, 0xb0, 0xc4, 0xa8, 0xcb, 0xa9, 0x94, 0x5f, 0x71, 0xe1, 0xfa, + 0xa9, 0xc4, 0x78, 0x5f, 0xad, 0xff, 0x7b, 0xef, 0xe0, 0xa7, 0xda, 0x94, 0x17, 0xea, 0xbe, 0x5c, + 0x5a, 0x07, 0x16, 0x1c, 0xc2, 0xd0, 0x2d, 0xb5, 0x61, 0x1e, 0xc2, 0xa6, 0x60, 0xb2, 0x48, 0x5c, + 0x14, 0x8b, 0x82, 0x1f, 0x42, 0xff, 0x05, 0xa7, 0xe5, 0x43, 0x47, 0xa0, 0x97, 0x53, 0x75, 0x6b, + 0x8d, 0xf4, 0x77, 0x70, 0x80, 0x25, 0xa1, 0xf3, 0xef, 0x18, 0x7c, 0x13, 0xe8, 0xff, 0xa9, 0x90, + 0xb7, 0xb5, 0x3c, 0xf3, 0x42, 0xde, 0x96, 0x13, 0xc8, 0xa2, 0xe6, 0x14, 0xe9, 0x2c, 0x4f, 0x91, + 0x27, 0x30, 0x30, 0x4e, 0x6c, 0x98, 0x11, 0x6c, 0x0b, 0xfb, 0xed, 0x66, 0xb8, 0xc3, 0x26, 0x60, + 0x92, 0x34, 0x02, 0x26, 0x49, 0x3d, 0x20, 0xa2, 0xb7, 0x09, 0x88, 0x4e, 0xde, 0x22, 0xe0, 0xe7, + 0xd0, 0xbf, 0xa4, 0xd5, 0xe5, 0xc1, 0x93, 0xa0, 0x77, 0xd5, 0x38, 0xb6, 0x08, 0xe5, 0x76, 0x84, + 0x75, 0xf4, 0x9d, 0xb2, 0xa8, 0x2c, 0x6b, 0xb7, 0x59, 0x56, 0xe3, 0x72, 0x6d, 0x59, 0x17, 0xb0, + 0xf5, 0x92, 0xa5, 0xe7, 0x54, 0x51, 0xcc, 0x2d, 0x65, 0xe9, 0x15, 0x57, 0x34, 0xd1, 0x16, 0xdd, + 0xb0, 0xc4, 0xd8, 0x41, 0x29, 0x4b, 0x9f, 0x09, 0x66, 0xf6, 0xd8, 0x0d, 0x1d, 0xc4, 0xfd, 0xcb, + 0xaf, 0x68, 0x6e, 0x96, 0x75, 0xb5, 0xae, 0x12, 0xa0, 0x4f, 0x04, 0x7a, 0x61, 0xcf, 0xf8, 0x74, + 0x38, 0xf8, 0xc6, 0xd3, 0xb1, 0xf1, 0xfe, 0xe0, 0xa6, 0x52, 0x96, 0x5e, 0x2e, 0xcc, 0xcd, 0xec, + 0x85, 0x16, 0x61, 0xdc, 0x5b, 0x46, 0x73, 0x54, 0x74, 0xb4, 0xc2, 0x41, 0x8c, 0x8b, 0x9f, 0xa7, + 0x49, 0xc2, 0x67, 0x3a, 0x6e, 0x2f, 0xac, 0x04, 0x4e, 0x3b, 0xcd, 0xbe, 0x90, 0x26, 0xb0, 0xd5, + 0x6a, 0x01, 0x66, 0xa5, 0xc1, 0x3c, 0x31, 0x03, 0xb6, 0x17, 0x96, 0x18, 0xe7, 0x0b, 0x7e, 0x87, + 0x2c, 0x61, 0x54, 0xb2, 0xb9, 0xbf, 0xa9, 0xf5, 0x0d, 0x59, 0xf0, 0x1a, 0xfa, 0x97, 0x8a, 0x0b, + 0x1a, 0x31, 0x5d, 0xb8, 0x8f, 0x61, 0x57, 0x5a, 0x28, 0xe2, 0xea, 0xea, 0x34, 0x85, 0xe4, 0x09, + 0xec, 0x59, 0xc1, 0x19, 0x9d, 0xbd, 0x89, 0xb3, 0xe8, 0x99, 0xb4, 0xfd, 0xd2, 0x92, 0x07, 0xff, + 0xf2, 0x60, 0x10, 0xb2, 0x28, 0x96, 0x4a, 0x2c, 0x74, 0x88, 0x27, 0xb0, 0x27, 0x0c, 0x8e, 0x99, + 0xbc, 0x64, 0x14, 0x87, 0xaf, 0x19, 0xa9, 0x2d, 0x39, 0x19, 0x03, 0xa9, 0x64, 0xd3, 0x4c, 0xb2, + 0x59, 0x21, 0x98, 0x6d, 0x96, 0x15, 0x1a, 0x72, 0x08, 0x0f, 0x2a, 0xe9, 0x59, 0xc2, 0x67, 0x6f, + 0xfc, 0xae, 0x36, 0x5e, 0x16, 0x07, 0x8f, 0xa1, 0xaf, 0x5f, 0xc3, 0x6a, 0xbc, 0xdf, 0x31, 0x71, + 0xcd, 0x6d, 0x2f, 0x6f, 0x87, 0x0e, 0x06, 0xff, 0xec, 0xc2, 0xc0, 0x58, 0xda, 0xc6, 0x7b, 0xaa, + 0xfb, 0x07, 0x45, 0x96, 0xa5, 0xbc, 0xbf, 0x3c, 0x7a, 0x6d, 0x17, 0x86, 0xce, 0x0e, 0xf9, 0xa2, + 0xad, 0x8b, 0x5e, 0xd6, 0x59, 0xcd, 0x17, 0x6b, 0xe7, 0x10, 0xd6, 0xed, 0xc9, 0xef, 0x60, 0x60, + 0xd3, 0x5f, 0xe8, 0xf5, 0x5d, 0xbd, 0x7e, 0x7f, 0x79, 0x7d, 0xbd, 0xca, 0x61, 0x63, 0x05, 0x76, + 0xc9, 0x1c, 0xa5, 0x9c, 0x3b, 0xd6, 0x5c, 0x62, 0xdc, 0xba, 0x28, 0x32, 0xad, 0x32, 0x6f, 0xa0, + 0x83, 0x48, 0x0a, 0x5e, 0x4d, 0xa6, 0x61, 0x91, 0x21, 0xe1, 0xd7, 0xdd, 0xb3, 0x13, 0xd6, 0x24, + 0xa8, 0xd7, 0xc1, 0x99, 0xb8, 0x28, 0x52, 0xcd, 0x9d, 0xbb, 0x61, 0x4d, 0x82, 0xfa, 0x88, 0x87, + 0xbc, 0x50, 0x71, 0xc6, 0xa4, 0xe6, 0xd0, 0xdd, 0xb0, 0x26, 0xb1, 0x95, 0xc4, 0x4b, 0x63, 0x29, + 0xf4, 0xaa, 0x4a, 0xa2, 0x3a, 0x74, 0x76, 0xc1, 0x5f, 0xe0, 0x07, 0x2f, 0x69, 0x16, 0xdf, 0x30, + 0xa9, 0x26, 0x9a, 0x5e, 0xb8, 0x03, 0x0c, 0x60, 0x90, 0x5a, 0x85, 0xe6, 0xcb, 0xf6, 0x2d, 0xad, + 0xcb, 0xf0, 0x26, 0x39, 0xec, 0x26, 0x4e, 0x25, 0x08, 0x4e, 0xe0, 0xe1, 0xb2, 0xeb, 0x7b, 0xe9, + 0xe4, 0x37, 0x1e, 0xbc, 0xef, 0x16, 0x9d, 0x66, 0x19, 0x57, 0xef, 0x98, 0x11, 0xce, 0x29, 0x8b, + 0xdd, 0xb3, 0xe8, 0x30, 0x0e, 0x41, 0x7d, 0x37, 0xec, 0x10, 0xd4, 0xf7, 0x61, 0x08, 0x1d, 0x2e, + 0xed, 0x09, 0x76, 0xb8, 0xc4, 0x0a, 0x73, 0xf9, 0x8c, 0x51, 0x55, 0x08, 0x26, 0xfd, 0x0d, 0xf3, + 0x8f, 0x50, 0x49, 0x74, 0x5b, 0x53, 0x11, 0xd3, 0x4c, 0xd9, 0xe3, 0x73, 0x30, 0xf8, 0x75, 0xb5, + 0xdb, 0x69, 0x26, 0x73, 0x36, 0x53, 0xef, 0x90, 0x77, 0xf0, 0xb3, 0x6a, 0xdb, 0xe5, 0x6a, 0x5b, + 0x2c, 0x02, 0x3d, 0x6c, 0x2d, 0xbd, 0x6c, 0x10, 0xea, 0xef, 0x93, 0xff, 0x01, 0x6c, 0x4d, 0xcc, + 0x0f, 0x28, 0x39, 0x87, 0x0d, 0x4d, 0xd6, 0xc9, 0xfe, 0xca, 0xff, 0x25, 0x9b, 0xc5, 0xe8, 0x83, + 0x35, 0xda, 0x8a, 0xfe, 0x58, 0xb2, 0xf2, 0x41, 0xfb, 0x1a, 0xd5, 0xf8, 0xfd, 0xe8, 0xc3, 0x75, + 0x6a, 0xe3, 0xe8, 0xd8, 0x23, 0xa7, 0xd0, 0xd3, 0x67, 0xf1, 0x68, 0x35, 0x7f, 0x36, 0x6e, 0xf6, + 0xbf, 0x8b, 0x5c, 0x93, 0x33, 0xd8, 0x72, 0x64, 0xf4, 0x61, 0xeb, 0x97, 0xe5, 0x33, 0xfc, 0x95, + 0x1e, 0x7d, 0xb4, 0xec, 0x60, 0x99, 0xfd, 0x4e, 0xa0, 0x87, 0xef, 0x79, 0x3b, 0x8d, 0x1a, 0x55, + 0x68, 0xa7, 0x51, 0xa7, 0x00, 0xc7, 0x9e, 0x71, 0x92, 0x24, 0xab, 0x9c, 0x94, 0xcf, 0xff, 0x2a, + 0x27, 0xd5, 0xb3, 0x7e, 0xec, 0x61, 0x6d, 0x0d, 0x51, 0x6d, 0xd7, 0xb6, 0xc1, 0x89, 0xdb, 0xb5, + 0x6d, 0xf2, 0xdb, 0x63, 0x8f, 0xfc, 0x01, 0xfa, 0x35, 0x1e, 0xba, 0xb6, 0x38, 0x3f, 0x7a, 0x0b, + 0xf2, 0x8a, 0x8d, 0xa3, 0xa9, 0x60, 0xbb, 0x71, 0xea, 0x0c, 0xb4, 0xdd, 0x38, 0x4d, 0xfe, 0xf8, + 0x1c, 0x36, 0x0d, 0xd5, 0x23, 0xab, 0x0c, 0x2b, 0xf6, 0xd8, 0xde, 0xdc, 0x12, 0x43, 0x9c, 0x40, + 0x0f, 0x69, 0xde, 0x8a, 0xb6, 0xa9, 0xf8, 0xe1, 0x8a, 0xb6, 0xa9, 0x31, 0x43, 0x53, 0x6a, 0xf3, + 0x9b, 0xdc, 0xce, 0xa6, 0xf1, 0x87, 0xde, 0xce, 0xa6, 0xf9, 0x77, 0x7d, 0xec, 0x91, 0x4f, 0xa1, + 0x7b, 0x45, 0x23, 0x32, 0x5a, 0x36, 0xac, 0x7e, 0x35, 0x47, 0x6b, 0xca, 0x8f, 0x5b, 0x41, 0x6a, + 0xd5, 0xde, 0x4a, 0x8d, 0xc3, 0xb5, 0xb7, 0x52, 0x67, 0x63, 0xe6, 0x1a, 0xe9, 0xa7, 0xa6, 0xe5, + 0xa4, 0xf6, 0xcc, 0xb6, 0x9d, 0x34, 0x5e, 0xd6, 0xd7, 0x30, 0x6c, 0x4e, 0x60, 0xf2, 0xe3, 0xd6, + 0x83, 0xb0, 0x6a, 0xf8, 0x8f, 0x3e, 0xb9, 0xcf, 0xcc, 0x06, 0xb8, 0x84, 0xbd, 0xe5, 0x69, 0x4d, + 0x1e, 0xaf, 0x5b, 0xbb, 0x34, 0xcf, 0xd7, 0x56, 0xef, 0x1a, 0x1e, 0x2c, 0xcd, 0x42, 0xb2, 0x36, + 0x9f, 0xe6, 0xa8, 0x1d, 0x3d, 0xbe, 0xd7, 0xce, 0x24, 0x7e, 0xbd, 0xa9, 0x63, 0xfe, 0xfc, 0xdb, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x5f, 0xf8, 0x06, 0x77, 0xd4, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1982,6 +2236,12 @@ type ControlClient interface { Save(ctx context.Context, in *SaveRequest, opts ...grpc.CallOption) (Control_SaveClient, error) // Info requests isula-build system information Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) + // ManifestCreate requests to create manifest list + ManifestCreate(ctx context.Context, in *ManifestCreateRequest, opts ...grpc.CallOption) (*ManifestCreateResponse, error) + // ManifestAnnotate requests to annotate manifest list + ManifestAnnotate(ctx context.Context, in *ManifestAnnotateRequest, opts ...grpc.CallOption) (*types.Empty, error) + // ManifestInspect requests to inspect manifest list + ManifestInspect(ctx context.Context, in *ManifestInspectRequest, opts ...grpc.CallOption) (*ManifestInspectResponse, error) } type controlClient struct { @@ -2288,6 +2548,33 @@ func (c *controlClient) Info(ctx context.Context, in *InfoRequest, opts ...grpc. return out, nil } +func (c *controlClient) ManifestCreate(ctx context.Context, in *ManifestCreateRequest, opts ...grpc.CallOption) (*ManifestCreateResponse, error) { + out := new(ManifestCreateResponse) + err := c.cc.Invoke(ctx, "/isula.build.v1.Control/ManifestCreate", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) ManifestAnnotate(ctx context.Context, in *ManifestAnnotateRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/isula.build.v1.Control/ManifestAnnotate", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) ManifestInspect(ctx context.Context, in *ManifestInspectRequest, opts ...grpc.CallOption) (*ManifestInspectResponse, error) { + out := new(ManifestInspectResponse) + err := c.cc.Invoke(ctx, "/isula.build.v1.Control/ManifestInspect", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ControlServer is the server API for Control service. type ControlServer interface { // Build requests a new image building @@ -2320,6 +2607,12 @@ type ControlServer interface { Save(*SaveRequest, Control_SaveServer) error // Info requests isula-build system information Info(context.Context, *InfoRequest) (*InfoResponse, error) + // ManifestCreate requests to create manifest list + ManifestCreate(context.Context, *ManifestCreateRequest) (*ManifestCreateResponse, error) + // ManifestAnnotate requests to annotate manifest list + ManifestAnnotate(context.Context, *ManifestAnnotateRequest) (*types.Empty, error) + // ManifestInspect requests to inspect manifest list + ManifestInspect(context.Context, *ManifestInspectRequest) (*ManifestInspectResponse, error) } // UnimplementedControlServer can be embedded to have forward compatible implementations. @@ -2371,6 +2664,15 @@ func (*UnimplementedControlServer) Save(req *SaveRequest, srv Control_SaveServer func (*UnimplementedControlServer) Info(ctx context.Context, req *InfoRequest) (*InfoResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Info not implemented") } +func (*UnimplementedControlServer) ManifestCreate(ctx context.Context, req *ManifestCreateRequest) (*ManifestCreateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ManifestCreate not implemented") +} +func (*UnimplementedControlServer) ManifestAnnotate(ctx context.Context, req *ManifestAnnotateRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method ManifestAnnotate not implemented") +} +func (*UnimplementedControlServer) ManifestInspect(ctx context.Context, req *ManifestInspectRequest) (*ManifestInspectResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ManifestInspect not implemented") +} func RegisterControlServer(s *grpc.Server, srv ControlServer) { s.RegisterService(&_Control_serviceDesc, srv) @@ -2667,6 +2969,60 @@ func _Control_Info_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Control_ManifestCreate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ManifestCreateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).ManifestCreate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/isula.build.v1.Control/ManifestCreate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).ManifestCreate(ctx, req.(*ManifestCreateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_ManifestAnnotate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ManifestAnnotateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).ManifestAnnotate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/isula.build.v1.Control/ManifestAnnotate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).ManifestAnnotate(ctx, req.(*ManifestAnnotateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_ManifestInspect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ManifestInspectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).ManifestInspect(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/isula.build.v1.Control/ManifestInspect", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).ManifestInspect(ctx, req.(*ManifestInspectRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Control_serviceDesc = grpc.ServiceDesc{ ServiceName: "isula.build.v1.Control", HandlerType: (*ControlServer)(nil), @@ -2703,6 +3059,18 @@ var _Control_serviceDesc = grpc.ServiceDesc{ MethodName: "Info", Handler: _Control_Info_Handler, }, + { + MethodName: "ManifestCreate", + Handler: _Control_ManifestCreate_Handler, + }, + { + MethodName: "ManifestAnnotate", + Handler: _Control_ManifestAnnotate_Handler, + }, + { + MethodName: "ManifestInspect", + Handler: _Control_ManifestInspect_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/api/services/control.proto b/api/services/control.proto index 2d55994..0d57a02 100644 --- a/api/services/control.proto +++ b/api/services/control.proto @@ -48,6 +48,12 @@ service Control { rpc Save(SaveRequest) returns (stream SaveResponse); // Info requests isula-build system information rpc Info(InfoRequest) returns (InfoResponse); + // ManifestCreate requests to create manifest list + rpc ManifestCreate(ManifestCreateRequest) returns (ManifestCreateResponse); + // ManifestAnnotate requests to annotate manifest list + rpc ManifestAnnotate(ManifestAnnotateRequest) returns (google.protobuf.Empty); + // ManifestInspect requests to inspect manifest list + rpc ManifestInspect(ManifestInspectRequest) returns (ManifestInspectResponse); } message BuildRequest { @@ -319,3 +325,28 @@ message InfoResponse { MemStat memStat = 9; } +message ManifestCreateRequest { + string manifestList = 1; + repeated string manifests = 2; +} + +message ManifestCreateResponse { + string imageID = 1; +} + +message ManifestAnnotateRequest { + string manifestList = 1; + string manifest = 2; + string arch = 3; + string os = 4; + repeated string osFeatures = 5; + string variant = 6; +} + +message ManifestInspectRequest { + string manifestList = 1; +} + +message ManifestInspectResponse { + bytes data = 1; +} diff --git a/builder/dockerfile/container/help.go b/builder/dockerfile/container/help.go index 355d4fd..c5aa381 100644 --- a/builder/dockerfile/container/help.go +++ b/builder/dockerfile/container/help.go @@ -32,7 +32,8 @@ import ( ) const ( - schemaVersion = 2 + // SchemaVersion is the image manifest schema + SchemaVersion = 2 ) // create configs and manifests aimed to can edit without making unintended changes @@ -55,7 +56,7 @@ func (ref *Reference) createConfigsAndManifests() (docker.Image, docker.Manifest // 2. manifest dmanifest := docker.Manifest{ Versioned: docker.Versioned{ - SchemaVersion: schemaVersion, + SchemaVersion: SchemaVersion, MediaType: mimetypes.DockerV2Schema2MediaType, }, Config: docker.Descriptor{ diff --git a/builder/dockerfile/container/help_test.go b/builder/dockerfile/container/help_test.go index 4c44c50..7ebc82f 100644 --- a/builder/dockerfile/container/help_test.go +++ b/builder/dockerfile/container/help_test.go @@ -135,7 +135,7 @@ func TestCreateConfigsAndManifests(t *testing.T) { assert.DeepEqual(t, dmanifest, docker.Manifest{ Versioned: docker.Versioned{ - SchemaVersion: schemaVersion, + SchemaVersion: SchemaVersion, MediaType: "application/vnd.docker.distribution.manifest.v2+json", }, Config: docker.Descriptor{ diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 47206e7..4c6c56f 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -109,6 +109,11 @@ func addCommands(cmd *cobra.Command) { NewInfoCmd(), completionCmd, ) + if os.Getenv("ISULABUILD_CLI_EXPERIMENTAL") == "enabled" { + cmd.AddCommand( + NewManifestCmd(), + ) + } } // "completion" command to generate bash completion script diff --git a/cmd/cli/manifest.go b/cmd/cli/manifest.go new file mode 100644 index 0000000..3d39ddf --- /dev/null +++ b/cmd/cli/manifest.go @@ -0,0 +1,205 @@ +// 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: Danni Xia +// Create: 2020-12-01 +// Description: This file is used for manifest command. + +package main + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + + pb "isula.org/isula-build/api/services" + _ "isula.org/isula-build/exporter/register" +) + +const ( + manifestCreateExample = `isula-build manifest create openeuler +isula-build manifest create openeuler localhost:5000/openeuler_x86:latest` + manifestAnnotateExample = `isula-build manifest annotate --os linux --arch arm64 openeuler localhost:5000/openeuler_aarch64:latest` + manifestInspectExample = `isula-build manifest inspect openeuler:latest` +) + +type annotateOptions struct { + imageArch string + imageOS string + imageOSFeature []string + imageVariant string +} + +var annotateOpts annotateOptions + +// NewManifestCmd returns manifest operations commands +func NewManifestCmd() *cobra.Command { + manifestCmd := &cobra.Command{ + Use: "manifest", + Short: "Manipulate manifest lists", + } + manifestCmd.AddCommand( + NewManifestCreateCmd(), + NewManifestAnnotateCmd(), + NewManifestInspectCmd(), + ) + + return manifestCmd +} + +// NewManifestCreateCmd returns manifest create command +func NewManifestCreateCmd() *cobra.Command { + createCmd := &cobra.Command{ + Use: "create MANIFEST_LIST MANIFEST [MANIFEST...] ", + Short: "Create a local manifest list", + Example: manifestCreateExample, + RunE: manifestCreateCommand, + DisableFlagsInUseLine: true, + } + + return createCmd +} + +// NewManifestAnnotateCmd returns manifest annotate command +func NewManifestAnnotateCmd() *cobra.Command { + annotateCmd := &cobra.Command{ + Use: "annotate [FLAGS] MANIFEST_LIST MANIFEST", + Short: "Annotate a local manifest list", + Example: manifestAnnotateExample, + RunE: manifestAnnotateCommand, + } + + annotateCmd.PersistentFlags().StringVar(&annotateOpts.imageArch, "arch", "", "Set architecture") + annotateCmd.PersistentFlags().StringVar(&annotateOpts.imageOS, "os", "", "Set operating system") + annotateCmd.PersistentFlags().StringSliceVar(&annotateOpts.imageOSFeature, "os-features", []string{}, "Set operating system feature") + annotateCmd.PersistentFlags().StringVar(&annotateOpts.imageVariant, "variant", "", "Set architecture variant") + + return annotateCmd +} + +// NewManifestInspectCmd returns manifest inspect command +func NewManifestInspectCmd() *cobra.Command { + inspectCmd := &cobra.Command{ + Use: "inspect MANIFEST_LIST", + Short: "Inspect a local manifest list", + Example: manifestInspectExample, + RunE: manifestInspectCommand, + DisableFlagsInUseLine: true, + } + + return inspectCmd +} + +func manifestCreateCommand(c *cobra.Command, args []string) error { + if len(args) == 0 { + return errors.New("please specify a name to manifest list") + } + + listName := args[0] + manifestsName := args[1:] + + ctx := context.Background() + cli, err := NewClient(ctx) + if err != nil { + return err + } + + return runManifestCreate(ctx, cli, listName, manifestsName) +} + +func runManifestCreate(ctx context.Context, cli Cli, listName string, manifestsName []string) error { + resp, err := cli.Client().ManifestCreate(ctx, &pb.ManifestCreateRequest{ + ManifestList: listName, + Manifests: manifestsName, + }) + if err != nil { + return err + } + + fmt.Println(resp.ImageID) + + return nil +} + +func manifestAnnotateCommand(c *cobra.Command, args []string) error { + var validArgsLength = 2 + if len(args) != validArgsLength { + return errors.New("please specify the manifest list and the image name") + } + + listName := args[0] + manifestName := args[1] + + ctx := context.Background() + cli, err := NewClient(ctx) + if err != nil { + return err + } + + return runManifestAnnotate(ctx, cli, listName, manifestName) +} + +func runManifestAnnotate(ctx context.Context, cli Cli, listName, manifestName string) error { + if _, err := cli.Client().ManifestAnnotate(ctx, &pb.ManifestAnnotateRequest{ + ManifestList: listName, + Manifest: manifestName, + Arch: annotateOpts.imageArch, + Os: annotateOpts.imageOS, + OsFeatures: annotateOpts.imageOSFeature, + Variant: annotateOpts.imageVariant, + }); err != nil { + return err + } + + fmt.Println("manifest annotate succeed") + + return nil +} + +func manifestInspectCommand(c *cobra.Command, args []string) error { + if len(args) == 0 { + return errors.New("please specify the manifest list name") + } + + if len(args) > 1 { + return errors.New("only one manifest list can be specified") + } + + listName := args[0] + + ctx := context.Background() + cli, err := NewClient(ctx) + if err != nil { + return err + } + + return runManifestInspect(ctx, cli, listName) +} + +func runManifestInspect(ctx context.Context, cli Cli, listName string) error { + resp, err := cli.Client().ManifestInspect(ctx, &pb.ManifestInspectRequest{ + ManifestList: listName, + }) + if err != nil { + return err + } + + var b bytes.Buffer + if err = json.Indent(&b, resp.Data, "", " "); err != nil { + return errors.Wrap(err, "display manifest error") + } + + fmt.Println(b.String()) + + return nil +} diff --git a/cmd/cli/manifest_test.go b/cmd/cli/manifest_test.go new file mode 100644 index 0000000..56e2aad --- /dev/null +++ b/cmd/cli/manifest_test.go @@ -0,0 +1,86 @@ +// 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: Danni Xia +// Create: 2020-12-01 +// Description: This file is used for testing manifest command. + +package main + +import ( + "context" + "testing" + + "gotest.tools/assert" +) + +func TestManifestCommand(t *testing.T) { + manifestCmd := NewManifestCmd() + var args []string + err := manifestCreateCommand(manifestCmd, args) + assert.ErrorContains(t, err, "please specify a name to manifest list") + + args = []string{"openeuler"} + err = manifestCreateCommand(manifestCmd, args) + assert.ErrorContains(t, err, "isula_build.sock") + + args = []string{} + err = manifestAnnotateCommand(manifestCmd, args) + assert.ErrorContains(t, err, "please specify the manifest list and the image name") + + args = []string{"openeuler"} + err = manifestAnnotateCommand(manifestCmd, args) + assert.ErrorContains(t, err, "please specify the manifest list and the image name") + + args = []string{"openeuler", "aaa", "bbb"} + err = manifestAnnotateCommand(manifestCmd, args) + assert.ErrorContains(t, err, "please specify the manifest list and the image name") + + args = []string{"openeuler", "openeuler_x86"} + err = manifestAnnotateCommand(manifestCmd, args) + assert.ErrorContains(t, err, "isula_build.sock") + + args = []string{} + err = manifestInspectCommand(manifestCmd, args) + assert.ErrorContains(t, err, "please specify the manifest list name") + + args = []string{"openeuler", "bbb"} + err = manifestInspectCommand(manifestCmd, args) + assert.ErrorContains(t, err, "only one manifest list can be specified") + + args = []string{"openeuler"} + err = manifestInspectCommand(manifestCmd, args) + assert.ErrorContains(t, err, "isula_build.sock") +} + +func TestRunManifestCreate(t *testing.T) { + ctx := context.Background() + cli := newMockClient(&mockGrpcClient{}) + listName := "openeuler" + manifestsName := []string{"openeuler_x86"} + err := runManifestCreate(ctx, &cli, listName, manifestsName) + assert.NilError(t, err) +} + +func TestRunManifestAnnotate(t *testing.T) { + ctx := context.Background() + cli := newMockClient(&mockGrpcClient{}) + listName := "openeuler" + manifestsName := "openeuler_x86" + err := runManifestAnnotate(ctx, &cli, listName, manifestsName) + assert.NilError(t, err) +} + +func TestRunManifestInspect(t *testing.T) { + ctx := context.Background() + cli := newMockClient(&mockGrpcClient{}) + listName := "openeuler" + err := runManifestInspect(ctx, &cli, listName) + assert.NilError(t, err) +} diff --git a/cmd/cli/mock.go b/cmd/cli/mock.go index 56b11be..21bfea0 100644 --- a/cmd/cli/mock.go +++ b/cmd/cli/mock.go @@ -223,6 +223,24 @@ func (gcli *mockGrpcClient) Pull(ctx context.Context, in *pb.PullRequest, opts . return &mockPullClient{}, nil } +func (gcli *mockGrpcClient) ManifestCreate(ctx context.Context, in *pb.ManifestCreateRequest, opts ...grpc.CallOption) (*pb.ManifestCreateResponse, error) { + resp := &pb.ManifestCreateResponse{ + ImageID: "abc123", + } + return resp, nil +} + +func (gcli *mockGrpcClient) ManifestAnnotate(ctx context.Context, in *pb.ManifestAnnotateRequest, opts ...grpc.CallOption) (*types.Empty, error) { + return &types.Empty{}, nil +} + +func (gcli *mockGrpcClient) ManifestInspect(ctx context.Context, in *pb.ManifestInspectRequest, opts ...grpc.CallOption) (*pb.ManifestInspectResponse, error) { + resp := &pb.ManifestInspectResponse{ + Data: []byte(`{"schemaVersion": 2}`), + } + return resp, nil +} + func (gcli *mockGrpcClient) Load(ctx context.Context, in *pb.LoadRequest, opts ...grpc.CallOption) (pb.Control_LoadClient, error) { if gcli.loadFunc != nil { return gcli.loadFunc(ctx, in, opts...) diff --git a/cmd/daemon/config/config.go b/cmd/daemon/config/config.go index a861087..db44b4b 100644 --- a/cmd/daemon/config/config.go +++ b/cmd/daemon/config/config.go @@ -16,10 +16,11 @@ package config // TomlConfig defines the configuration of isula-builder type TomlConfig struct { - Debug bool `toml:"debug"` - Group string `toml:"group"` - LogLevel string `toml:"loglevel"` - Runtime string `toml:"runtime"` - RunRoot string `toml:"run_root"` - DataRoot string `toml:"data_root"` + Debug bool `toml:"debug"` + Experimental bool `toml:"experimental"` + Group string `toml:"group"` + LogLevel string `toml:"loglevel"` + Runtime string `toml:"runtime"` + RunRoot string `toml:"run_root"` + DataRoot string `toml:"data_root"` } diff --git a/cmd/daemon/main.go b/cmd/daemon/main.go index d6f1d08..41d2b60 100644 --- a/cmd/daemon/main.go +++ b/cmd/daemon/main.go @@ -18,7 +18,6 @@ import ( "io/ioutil" "os" "path/filepath" - "strconv" "github.com/BurntSushi/toml" "github.com/containers/storage/pkg/reexec" @@ -58,6 +57,7 @@ func newDaemonCommand() *cobra.Command { Version: fmt.Sprintf("%s, build %s", version.Version, version.GitCommit), } rootCmd.PersistentFlags().BoolVarP(&daemonOpts.Debug, "debug", "D", false, "Open debug mode") + rootCmd.PersistentFlags().BoolVarP(&daemonOpts.Experimental, "experimental", "", false, "Enable experimental features") rootCmd.PersistentFlags().StringVar(&daemonOpts.DataRoot, "dataroot", constant.DefaultDataRoot, "Persistent dir") rootCmd.PersistentFlags().StringVar(&daemonOpts.RunRoot, "runroot", constant.DefaultRunRoot, "Runtime dir") rootCmd.PersistentFlags().StringVar(&daemonOpts.Group, "group", "isula", "User group for unix socket isula-build.sock") @@ -250,9 +250,12 @@ func mergeStorageConfig(cmd *cobra.Command) error { } func mergeConfig(conf config.TomlConfig, cmd *cobra.Command) { - if strconv.FormatBool(conf.Debug) == "true" && !cmd.Flag("debug").Changed { + if conf.Debug && !cmd.Flag("debug").Changed { daemonOpts.Debug = true } + if conf.Experimental && !cmd.Flag("experimental").Changed { + daemonOpts.Experimental = true + } if conf.LogLevel != "" && !cmd.Flag("log-level").Changed { daemonOpts.LogLevel = conf.LogLevel } diff --git a/daemon/daemon.go b/daemon/daemon.go index 90ccf64..4e0435a 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -42,6 +42,7 @@ const dataRootTmpDirPrefix = "tmp" // Options carries the options configured to daemon type Options struct { Debug bool + Experimental bool Group string LogLevel string DataRoot string diff --git a/daemon/manifest.go b/daemon/manifest.go new file mode 100644 index 0000000..8007c8b --- /dev/null +++ b/daemon/manifest.go @@ -0,0 +1,351 @@ +// 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: Danni Xia +// Create: 2020-12-01 +// Description: This file is used for manifest command. + +package daemon + +import ( + "context" + "encoding/json" + + "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/transports" + "github.com/containers/storage" + gogotypes "github.com/gogo/protobuf/types" + "github.com/opencontainers/go-digest" + "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/builder/dockerfile/container" + "isula.org/isula-build/image" + "isula.org/isula-build/store" + "isula.org/isula-build/util" +) + +const instancesData = "instancesdata" + +type manifestList struct { + docker manifest.Schema2List + instances map[digest.Digest]string +} + +// ManifestCreate creates manifest list +func (b *Backend) ManifestCreate(ctx context.Context, req *pb.ManifestCreateRequest) (*pb.ManifestCreateResponse, error) { + if !b.daemon.opts.Experimental { + return &pb.ManifestCreateResponse{}, errors.New("please enable experimental to use manifest feature") + } + + logrus.WithFields(logrus.Fields{ + "ManifestList": req.GetManifestList(), + "Manifest": req.GetManifests(), + }).Info("ManifestCreateRequest received") + + manifestName := req.GetManifestList() + manifests := req.GetManifests() + + list := &manifestList{ + docker: manifest.Schema2List{ + SchemaVersion: container.SchemaVersion, + MediaType: manifest.DockerV2ListMediaType, + }, + instances: make(map[digest.Digest]string, 0), + } + + for _, imageSpec := range manifests { + // add image to list + if _, err := list.addImage(ctx, b.daemon.localStore, imageSpec); err != nil { + return &pb.ManifestCreateResponse{}, err + } + } + + // expand list name + _, imageName, err := dockerfile.CheckAndExpandTag(manifestName) + if err != nil { + return &pb.ManifestCreateResponse{}, err + } + // save list to image + imageID, err := list.saveListToImage(b.daemon.localStore, "", imageName, list.docker.MediaType) + + return &pb.ManifestCreateResponse{ + ImageID: imageID, + }, err +} + +// ManifestAnnotate modifies and updates manifest list +func (b *Backend) ManifestAnnotate(ctx context.Context, req *pb.ManifestAnnotateRequest) (*gogotypes.Empty, error) { + var emptyResp = &gogotypes.Empty{} + + if !b.daemon.opts.Experimental { + return emptyResp, errors.New("please enable experimental to use manifest feature") + } + + logrus.WithFields(logrus.Fields{ + "ManifestList": req.GetManifestList(), + "Manifest": req.GetManifest(), + }).Info("ManifestAnnotateRequest received") + + manifestName := req.GetManifestList() + manifestImage := req.GetManifest() + imageOS := req.GetOs() + imageArch := req.GetArch() + imageOSFeature := req.GetOsFeatures() + imageVariant := req.GetVariant() + + // get list image + _, listImage, err := image.FindImage(b.daemon.localStore, manifestName) + if err != nil { + return emptyResp, err + } + + // load list from list image + _, list, err := loadListFromImage(b.daemon.localStore, listImage.ID) + if err != nil { + return emptyResp, err + } + + // add image to list, if image already exists, it will be substituted + instanceDigest, err := list.addImage(ctx, b.daemon.localStore, manifestImage) + if err != nil { + return emptyResp, err + } + + // modify image platform if user specifies + for i := range list.docker.Manifests { + if list.docker.Manifests[i].Digest == instanceDigest { + if imageOS != "" { + list.docker.Manifests[i].Platform.OS = imageOS + } + if imageArch != "" { + list.docker.Manifests[i].Platform.Architecture = imageArch + } + if len(imageOSFeature) > 0 { + list.docker.Manifests[i].Platform.OSFeatures = append([]string{}, imageOSFeature...) + } + if imageVariant != "" { + list.docker.Manifests[i].Platform.Variant = imageVariant + } + } + } + + // save list to image + _, err = list.saveListToImage(b.daemon.localStore, listImage.ID, "", manifest.DockerV2ListMediaType) + + return emptyResp, err +} + +// ManifestInspect inspects manifest list +func (b *Backend) ManifestInspect(ctx context.Context, req *pb.ManifestInspectRequest) (*pb.ManifestInspectResponse, error) { + if !b.daemon.opts.Experimental { + return &pb.ManifestInspectResponse{}, errors.New("please enable experimental to use manifest feature") + } + + logrus.WithFields(logrus.Fields{ + "ManifestList": req.GetManifestList(), + }).Info("ManifestInspectRequest received") + + manifestName := req.GetManifestList() + + // get list image + ref, _, err := image.FindImage(b.daemon.localStore, manifestName) + if err != nil { + return &pb.ManifestInspectResponse{}, err + } + + // get image reference + src, err := ref.NewImageSource(ctx, image.GetSystemContext()) + if err != nil { + return &pb.ManifestInspectResponse{}, err + } + + defer func() { + if cErr := src.Close(); cErr != nil { + logrus.Warnf("Image source closing error: %v", cErr) + } + }() + + // get image manifest + manifestBytes, manifestType, err := src.GetManifest(ctx, nil) + if err != nil { + return &pb.ManifestInspectResponse{}, err + } + + // check whether image is a list image + if !manifest.MIMETypeIsMultiImage(manifestType) { + return &pb.ManifestInspectResponse{}, errors.Errorf("%v is not a manifest list", manifestName) + } + + // return list image data + return &pb.ManifestInspectResponse{ + Data: manifestBytes, + }, nil +} + +type instanceInfo struct { + OS, Architecture string + instanceDigest *digest.Digest + Size int64 +} + +func (l *manifestList) addImage(ctx context.Context, store *store.Store, imageSpec string) (digest.Digest, error) { + img, _, err := image.ResolveFromImage(&image.PrepareImageOptions{ + Ctx: ctx, + FromImage: util.DefaultTransport + imageSpec, + SystemContext: image.GetSystemContext(), + Store: store, + }) + if err != nil { + return "", err + } + + var instance instanceInfo + // get image OS and architecture + config, err := img.OCIConfig(ctx) + if err != nil { + return "", errors.Wrapf(err, "get oci config from image %v error", imageSpec) + } + instance.OS = config.OS + instance.Architecture = config.Architecture + + // get image manifest digest and size + manifestBytes, manifestType, err := img.Manifest(ctx) + if err != nil { + return "", errors.Wrapf(err, "get manifest from image %v error", imageSpec) + } + if manifest.MIMETypeIsMultiImage(manifestType) { + return "", errors.Errorf("%v is a manifest list", imageSpec) + } + manifestDigest, err := manifest.Digest(manifestBytes) + if err != nil { + return "", errors.Wrapf(err, "compute digest of manifest from image %v error", imageSpec) + } + instance.instanceDigest = &manifestDigest + instance.Size = int64(len(manifestBytes)) + + // add image information to list + l.addInstance(instance, manifestType) + + // update list instances + if _, ok := l.instances[*instance.instanceDigest]; !ok { + l.instances[*instance.instanceDigest] = transports.ImageName(img.Reference()) + } + + return manifestDigest, nil +} + +func (l *manifestList) addInstance(instanceInfo instanceInfo, manifestType string) { + // remove instance if it is already exists, as we want to substitute it + l.removeInstance(instanceInfo) + + schema2platform := manifest.Schema2PlatformSpec{ + Architecture: instanceInfo.Architecture, + OS: instanceInfo.OS, + } + + l.docker.Manifests = append(l.docker.Manifests, manifest.Schema2ManifestDescriptor{ + Schema2Descriptor: manifest.Schema2Descriptor{ + MediaType: manifestType, + Size: instanceInfo.Size, + Digest: *instanceInfo.instanceDigest, + }, + Platform: schema2platform, + }) +} + +func (l *manifestList) removeInstance(instanceInfo instanceInfo) { + newDockerManifests := make([]manifest.Schema2ManifestDescriptor, 0, len(l.docker.Manifests)) + + for i := range l.docker.Manifests { + if l.docker.Manifests[i].Digest != *instanceInfo.instanceDigest { + newDockerManifests = append(newDockerManifests, l.docker.Manifests[i]) + } + } + + l.docker.Manifests = newDockerManifests +} + +func (l *manifestList) saveListToImage(store *store.Store, imageID, name string, mimeType string) (string, error) { + // create an image to store list information + img, err := store.CreateImage(imageID, []string{name}, "", "", &storage.ImageOptions{}) + if err != nil && errors.Cause(err) != storage.ErrDuplicateID { + return "", errors.Wrap(err, "create image to store manifest list error") + } + + // err == nil means a new image is created, if not, means image already exists, just modify image data + if err == nil { + imageID = img.ID + } + + // marshal list information + manifestBytes, err := json.Marshal(&l.docker) + if err != nil { + return "", errors.Wrap(err, "marshall Docker manifest list error") + } + // save list.docker information to image + if err = store.SetImageBigData(imageID, storage.ImageDigestManifestBigDataNamePrefix, manifestBytes, manifest.Digest); err != nil { + if _, err2 := store.DeleteImage(img.ID, true); err2 != nil { + logrus.Errorf("delete image %v as save manifest list to image failed error", imageID) + } + return "", errors.Wrapf(err, "save manifest list to image %v error", imageID) + } + + //marshal list instance information + instancesBytes, err := json.Marshal(&l.instances) + if err != nil { + return "", errors.Wrap(err, "marshall list instances error") + } + // save list.instance information to image + if err = store.SetImageBigData(imageID, instancesData, instancesBytes, nil); err != nil { + if _, err2 := store.DeleteImage(img.ID, true); err2 != nil { + logrus.Errorf("delete image %v as save manifest list instance to image failed error", imageID) + } + return "", errors.Wrapf(err, "save manifest list instance to image %v error", imageID) + } + + return imageID, nil +} + +func loadListFromImage(store *store.Store, image string) (string, manifestList, error) { + list := manifestList{ + docker: manifest.Schema2List{ + SchemaVersion: container.SchemaVersion, + MediaType: manifest.DockerV2ListMediaType, + }, + } + + // get list image + img, err := store.Image(image) + if err != nil { + return "", list, errors.Wrapf(err, "get image %v for loading manifest list error", image) + } + + // load list.docker + manifestBytes, err := store.ImageBigData(img.ID, storage.ImageDigestManifestBigDataNamePrefix) + if err != nil { + return "", list, errors.Wrapf(err, "get image data for loading manifest list error") + } + if err = json.Unmarshal(manifestBytes, &list.docker); err != nil { + return "", list, errors.Wrapf(err, "parse image data to manifest list error") + } + + // load list.instance + instancesBytes, err := store.ImageBigData(img.ID, instancesData) + if err != nil { + return img.ID, list, errors.Wrapf(err, "get instance data for loading instance list error") + } + if err = json.Unmarshal(instancesBytes, &list.instances); err != nil { + return img.ID, list, errors.Wrapf(err, "parse instance data to instance list error") + } + + return img.ID, list, err +} -- Gitee