cmd/ctr, service/containers: implement container filter
Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
3332042ab6
commit
396d89e423
@ -125,7 +125,17 @@ func (*GetContainerResponse) ProtoMessage() {}
|
|||||||
func (*GetContainerResponse) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{2} }
|
func (*GetContainerResponse) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{2} }
|
||||||
|
|
||||||
type ListContainersRequest struct {
|
type ListContainersRequest struct {
|
||||||
Filter string `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"`
|
// Filters contains one or more filters using the syntax defined in the
|
||||||
|
// containerd filter package.
|
||||||
|
//
|
||||||
|
// The returned result will be those that match any of the provided
|
||||||
|
// filters. Expanded, containers that match the following will be
|
||||||
|
// returned:
|
||||||
|
//
|
||||||
|
// filters[0] or filters[1] or ... or filters[n-1] or filters[n]
|
||||||
|
//
|
||||||
|
// If filters is zero-length or nil, all items will be returned.
|
||||||
|
Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ListContainersRequest) Reset() { *m = ListContainersRequest{} }
|
func (m *ListContainersRequest) Reset() { *m = ListContainersRequest{} }
|
||||||
@ -601,11 +611,20 @@ func (m *ListContainersRequest) MarshalTo(dAtA []byte) (int, error) {
|
|||||||
_ = i
|
_ = i
|
||||||
var l int
|
var l int
|
||||||
_ = l
|
_ = l
|
||||||
if len(m.Filter) > 0 {
|
if len(m.Filters) > 0 {
|
||||||
|
for _, s := range m.Filters {
|
||||||
dAtA[i] = 0xa
|
dAtA[i] = 0xa
|
||||||
i++
|
i++
|
||||||
i = encodeVarintContainers(dAtA, i, uint64(len(m.Filter)))
|
l = len(s)
|
||||||
i += copy(dAtA[i:], m.Filter)
|
for l >= 1<<7 {
|
||||||
|
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
|
||||||
|
l >>= 7
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
dAtA[i] = uint8(l)
|
||||||
|
i++
|
||||||
|
i += copy(dAtA[i:], s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
@ -878,10 +897,12 @@ func (m *GetContainerResponse) Size() (n int) {
|
|||||||
func (m *ListContainersRequest) Size() (n int) {
|
func (m *ListContainersRequest) Size() (n int) {
|
||||||
var l int
|
var l int
|
||||||
_ = l
|
_ = l
|
||||||
l = len(m.Filter)
|
if len(m.Filters) > 0 {
|
||||||
if l > 0 {
|
for _, s := range m.Filters {
|
||||||
|
l = len(s)
|
||||||
n += 1 + l + sovContainers(uint64(l))
|
n += 1 + l + sovContainers(uint64(l))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1019,7 +1040,7 @@ func (this *ListContainersRequest) String() string {
|
|||||||
return "nil"
|
return "nil"
|
||||||
}
|
}
|
||||||
s := strings.Join([]string{`&ListContainersRequest{`,
|
s := strings.Join([]string{`&ListContainersRequest{`,
|
||||||
`Filter:` + fmt.Sprintf("%v", this.Filter) + `,`,
|
`Filters:` + fmt.Sprintf("%v", this.Filters) + `,`,
|
||||||
`}`,
|
`}`,
|
||||||
}, "")
|
}, "")
|
||||||
return s
|
return s
|
||||||
@ -1774,7 +1795,7 @@ func (m *ListContainersRequest) Unmarshal(dAtA []byte) error {
|
|||||||
switch fieldNum {
|
switch fieldNum {
|
||||||
case 1:
|
case 1:
|
||||||
if wireType != 2 {
|
if wireType != 2 {
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field Filter", wireType)
|
return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType)
|
||||||
}
|
}
|
||||||
var stringLen uint64
|
var stringLen uint64
|
||||||
for shift := uint(0); ; shift += 7 {
|
for shift := uint(0); ; shift += 7 {
|
||||||
@ -1799,7 +1820,7 @@ func (m *ListContainersRequest) Unmarshal(dAtA []byte) error {
|
|||||||
if postIndex > l {
|
if postIndex > l {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
m.Filter = string(dAtA[iNdEx:postIndex])
|
m.Filters = append(m.Filters, string(dAtA[iNdEx:postIndex]))
|
||||||
iNdEx = postIndex
|
iNdEx = postIndex
|
||||||
default:
|
default:
|
||||||
iNdEx = preIndex
|
iNdEx = preIndex
|
||||||
@ -2445,52 +2466,52 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptorContainers = []byte{
|
var fileDescriptorContainers = []byte{
|
||||||
// 738 bytes of a gzipped FileDescriptorProto
|
// 742 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x6e, 0xd3, 0x4a,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x6e, 0xd3, 0x4a,
|
||||||
0x14, 0xae, 0x93, 0xd4, 0x69, 0x4e, 0x36, 0x57, 0x73, 0x73, 0x73, 0x8d, 0x91, 0x92, 0x90, 0x55,
|
0x14, 0xae, 0x93, 0xd4, 0x69, 0x4e, 0x36, 0x57, 0x73, 0x73, 0x73, 0x8d, 0x91, 0x92, 0x90, 0x55,
|
||||||
0x16, 0x60, 0xd3, 0x80, 0xa0, 0x3f, 0xab, 0xa6, 0x7f, 0x42, 0x6a, 0x51, 0x35, 0xc0, 0x06, 0x16,
|
0x16, 0xe0, 0xd0, 0x80, 0xa0, 0x3f, 0xab, 0xa6, 0x7f, 0x42, 0x6a, 0x51, 0x35, 0xc0, 0x06, 0x16,
|
||||||
0xc5, 0x49, 0x26, 0xa9, 0x89, 0xe3, 0x31, 0x9e, 0x49, 0xa4, 0x88, 0x05, 0x3c, 0x02, 0x6f, 0xc1,
|
0xc5, 0x49, 0x26, 0xa9, 0x89, 0xed, 0x31, 0x9e, 0x49, 0xa4, 0x88, 0x05, 0x3c, 0x02, 0x6f, 0xc1,
|
||||||
0x53, 0xb0, 0xef, 0x92, 0x25, 0xab, 0xd2, 0xe6, 0x49, 0x90, 0xc7, 0xe3, 0x3a, 0xe4, 0x47, 0x38,
|
0x53, 0xb0, 0xef, 0x92, 0x25, 0xab, 0xd2, 0xe6, 0x49, 0x90, 0xc7, 0xe3, 0x3a, 0xe4, 0x47, 0x38,
|
||||||
0x85, 0xee, 0xe6, 0x78, 0xce, 0xf7, 0x9d, 0x33, 0xdf, 0x7c, 0x67, 0x64, 0x38, 0xea, 0xda, 0xfc,
|
0x85, 0xee, 0xe6, 0x78, 0xce, 0xf7, 0x9d, 0x33, 0xdf, 0x7c, 0x67, 0x64, 0x38, 0xea, 0x59, 0xfc,
|
||||||
0x6c, 0xd0, 0x34, 0x5a, 0xb4, 0x6f, 0xb6, 0xa8, 0xcb, 0x2d, 0xdb, 0x25, 0x7e, 0x7b, 0x72, 0x69,
|
0x6c, 0xd0, 0x32, 0xda, 0xd4, 0xa9, 0xb7, 0xa9, 0xcb, 0x4d, 0xcb, 0x25, 0x7e, 0x67, 0x72, 0x69,
|
||||||
0x79, 0xb6, 0xc9, 0x88, 0x3f, 0xb4, 0x5b, 0x84, 0xc5, 0xdf, 0x99, 0x39, 0x5c, 0x9f, 0x88, 0x0c,
|
0x7a, 0x56, 0x9d, 0x11, 0x7f, 0x68, 0xb5, 0x09, 0x8b, 0xbf, 0xb3, 0xfa, 0x70, 0x7d, 0x22, 0x32,
|
||||||
0xcf, 0xa7, 0x9c, 0xa2, 0x7b, 0x31, 0xce, 0x88, 0x30, 0xc6, 0x44, 0xd6, 0x70, 0x5d, 0x2f, 0x74,
|
0x3c, 0x9f, 0x72, 0x8a, 0xee, 0xc5, 0x38, 0x23, 0xc2, 0x18, 0x13, 0x59, 0xc3, 0x75, 0xbd, 0xd0,
|
||||||
0x69, 0x97, 0x8a, 0x6c, 0x33, 0x58, 0x85, 0x40, 0xfd, 0x4e, 0x97, 0xd2, 0xae, 0x43, 0x4c, 0x11,
|
0xa3, 0x3d, 0x2a, 0xb2, 0xeb, 0xc1, 0x2a, 0x04, 0xea, 0x77, 0x7a, 0x94, 0xf6, 0x6c, 0x52, 0x17,
|
||||||
0x35, 0x07, 0x1d, 0xd3, 0x72, 0x47, 0x72, 0xeb, 0xee, 0xf4, 0x16, 0xe9, 0x7b, 0x3c, 0xda, 0xac,
|
0x51, 0x6b, 0xd0, 0xad, 0x9b, 0xee, 0x48, 0x6e, 0xdd, 0x9d, 0xde, 0x22, 0x8e, 0xc7, 0xa3, 0xcd,
|
||||||
0x4c, 0x6f, 0x76, 0x6c, 0xe2, 0xb4, 0x4f, 0xfb, 0x16, 0xeb, 0xc9, 0x8c, 0xf2, 0x74, 0x06, 0xb7,
|
0xca, 0xf4, 0x66, 0xd7, 0x22, 0x76, 0xe7, 0xd4, 0x31, 0x59, 0x5f, 0x66, 0x94, 0xa7, 0x33, 0xb8,
|
||||||
0xfb, 0x84, 0x71, 0xab, 0xef, 0xc9, 0x84, 0xed, 0x44, 0x0a, 0xf0, 0x91, 0x47, 0x98, 0xd9, 0x26,
|
0xe5, 0x10, 0xc6, 0x4d, 0xc7, 0x93, 0x09, 0xdb, 0x89, 0x14, 0xe0, 0x23, 0x8f, 0xb0, 0x7a, 0x87,
|
||||||
0xac, 0xe5, 0xdb, 0x1e, 0xa7, 0x7e, 0x08, 0xae, 0x7e, 0xcd, 0x40, 0x6e, 0x37, 0xca, 0x44, 0x45,
|
0xb0, 0xb6, 0x6f, 0x79, 0x9c, 0xfa, 0x21, 0xb8, 0xfa, 0x35, 0x03, 0xb9, 0xdd, 0x28, 0x13, 0x15,
|
||||||
0x48, 0xd9, 0x6d, 0x4d, 0xa9, 0x28, 0xb5, 0x5c, 0x43, 0x1d, 0x5f, 0x94, 0x53, 0xcf, 0xf6, 0x70,
|
0x21, 0x65, 0x75, 0x34, 0xa5, 0xa2, 0xd4, 0x72, 0x4d, 0x75, 0x7c, 0x51, 0x4e, 0x3d, 0xdb, 0xc3,
|
||||||
0xca, 0x6e, 0xa3, 0x13, 0x50, 0x1d, 0xab, 0x49, 0x1c, 0xa6, 0xa5, 0x2a, 0xe9, 0x5a, 0xbe, 0xbe,
|
0x29, 0xab, 0x83, 0x4e, 0x40, 0xb5, 0xcd, 0x16, 0xb1, 0x99, 0x96, 0xaa, 0xa4, 0x6b, 0xf9, 0xc6,
|
||||||
0x61, 0xfc, 0x56, 0x27, 0xe3, 0x9a, 0xd5, 0x38, 0x12, 0xd0, 0x7d, 0x97, 0xfb, 0x23, 0x2c, 0x79,
|
0x86, 0xf1, 0x5b, 0x9d, 0x8c, 0x6b, 0x56, 0xe3, 0x48, 0x40, 0xf7, 0x5d, 0xee, 0x8f, 0xb0, 0xe4,
|
||||||
0x50, 0x01, 0x56, 0xed, 0xbe, 0xd5, 0x25, 0x5a, 0x3a, 0x28, 0x86, 0xc3, 0x00, 0x3d, 0x87, 0xac,
|
0x41, 0x05, 0x58, 0xb5, 0x1c, 0xb3, 0x47, 0xb4, 0x74, 0x50, 0x0c, 0x87, 0x01, 0x7a, 0x0e, 0x59,
|
||||||
0x3f, 0x70, 0x83, 0x03, 0x6a, 0x99, 0x8a, 0x52, 0xcb, 0xd7, 0x1f, 0x2f, 0x55, 0x08, 0x87, 0x58,
|
0x7f, 0xe0, 0x06, 0x07, 0xd4, 0x32, 0x15, 0xa5, 0x96, 0x6f, 0x3c, 0x5e, 0xaa, 0x10, 0x0e, 0xb1,
|
||||||
0x1c, 0x91, 0xa0, 0x1a, 0x64, 0x98, 0x47, 0x5a, 0xda, 0xaa, 0x20, 0x2b, 0x18, 0xa1, 0x94, 0x46,
|
0x38, 0x22, 0x41, 0x35, 0xc8, 0x30, 0x8f, 0xb4, 0xb5, 0x55, 0x41, 0x56, 0x30, 0x42, 0x29, 0x8d,
|
||||||
0x24, 0xa5, 0xb1, 0xe3, 0x8e, 0xb0, 0xc8, 0x40, 0x55, 0x50, 0x7d, 0x4a, 0x79, 0x87, 0x69, 0xaa,
|
0x48, 0x4a, 0x63, 0xc7, 0x1d, 0x61, 0x91, 0x81, 0xaa, 0xa0, 0xfa, 0x94, 0xf2, 0x2e, 0xd3, 0x54,
|
||||||
0x38, 0x3d, 0x8c, 0x2f, 0xca, 0x2a, 0xa6, 0x94, 0x1f, 0xbc, 0xc0, 0x72, 0x07, 0xed, 0x02, 0xb4,
|
0x71, 0x7a, 0x18, 0x5f, 0x94, 0x55, 0x4c, 0x29, 0x3f, 0x78, 0x81, 0xe5, 0x0e, 0xda, 0x05, 0x68,
|
||||||
0x7c, 0x62, 0x71, 0xd2, 0x3e, 0xb5, 0xb8, 0x96, 0x15, 0x9c, 0xfa, 0x0c, 0xe7, 0xcb, 0xe8, 0x7a,
|
0xfb, 0xc4, 0xe4, 0xa4, 0x73, 0x6a, 0x72, 0x2d, 0x2b, 0x38, 0xf5, 0x19, 0xce, 0x97, 0xd1, 0xf5,
|
||||||
0x1a, 0x6b, 0xe7, 0x17, 0xe5, 0x95, 0xcf, 0x3f, 0xca, 0x0a, 0xce, 0x49, 0xdc, 0x0e, 0x0f, 0x48,
|
0x34, 0xd7, 0xce, 0x2f, 0xca, 0x2b, 0x9f, 0x7f, 0x94, 0x15, 0x9c, 0x93, 0xb8, 0x1d, 0x1e, 0x90,
|
||||||
0x06, 0x5e, 0x3b, 0x22, 0x59, 0x5b, 0x86, 0x44, 0xe2, 0x76, 0xb8, 0xbe, 0x09, 0xf9, 0x09, 0x51,
|
0x0c, 0xbc, 0x4e, 0x44, 0xb2, 0xb6, 0x0c, 0x89, 0xc4, 0xed, 0x70, 0x7d, 0x13, 0xf2, 0x13, 0xa2,
|
||||||
0xd1, 0x3f, 0x90, 0xee, 0x91, 0x51, 0x78, 0x6f, 0x38, 0x58, 0x06, 0xf2, 0x0e, 0x2d, 0x67, 0x40,
|
0xa2, 0x7f, 0x20, 0xdd, 0x27, 0xa3, 0xf0, 0xde, 0x70, 0xb0, 0x0c, 0xe4, 0x1d, 0x9a, 0xf6, 0x80,
|
||||||
0xb4, 0x54, 0x28, 0xaf, 0x08, 0xb6, 0x52, 0x1b, 0x8a, 0x7e, 0x0c, 0x59, 0x29, 0x13, 0x42, 0x90,
|
0x68, 0xa9, 0x50, 0x5e, 0x11, 0x6c, 0xa5, 0x36, 0x14, 0xfd, 0x18, 0xb2, 0x52, 0x26, 0x84, 0x20,
|
||||||
0x71, 0xad, 0x3e, 0x91, 0x38, 0xb1, 0x46, 0x06, 0x64, 0xa9, 0xc7, 0x6d, 0xea, 0x32, 0x01, 0x5d,
|
0xe3, 0x9a, 0x0e, 0x91, 0x38, 0xb1, 0x46, 0x06, 0x64, 0xa9, 0xc7, 0x2d, 0xea, 0x32, 0x01, 0x5d,
|
||||||
0x24, 0x5a, 0x94, 0x54, 0x7d, 0x00, 0xff, 0x1e, 0x12, 0x7e, 0x7d, 0x05, 0x98, 0xbc, 0x1f, 0x10,
|
0x24, 0x5a, 0x94, 0x54, 0x7d, 0x00, 0xff, 0x1e, 0x12, 0x7e, 0x7d, 0x05, 0x98, 0xbc, 0x1f, 0x10,
|
||||||
0xc6, 0x17, 0x19, 0xa9, 0x7a, 0x06, 0x85, 0x5f, 0xd3, 0x99, 0x47, 0x5d, 0x46, 0xd0, 0x09, 0xe4,
|
0xc6, 0x17, 0x19, 0xa9, 0x7a, 0x06, 0x85, 0x5f, 0xd3, 0x99, 0x47, 0x5d, 0x46, 0xd0, 0x09, 0xe4,
|
||||||
0xae, 0x2f, 0x55, 0xc0, 0xf2, 0xf5, 0xfb, 0xcb, 0x5c, 0x7d, 0x23, 0x13, 0xc8, 0x84, 0x63, 0x92,
|
0xae, 0x2f, 0x55, 0xc0, 0xf2, 0x8d, 0xfb, 0xcb, 0x5c, 0x7d, 0x33, 0x13, 0xc8, 0x84, 0x63, 0x92,
|
||||||
0xaa, 0x09, 0xff, 0x1d, 0xd9, 0x2c, 0x2e, 0xc5, 0xe2, 0xd6, 0xd4, 0x8e, 0xed, 0x70, 0x59, 0x27,
|
0xea, 0x3a, 0xfc, 0x77, 0x64, 0xb1, 0xb8, 0x14, 0x8b, 0x5a, 0xd3, 0x20, 0xdb, 0xb5, 0x6c, 0x4e,
|
||||||
0x87, 0x65, 0x54, 0x75, 0xa0, 0x38, 0x0d, 0x90, 0xcd, 0x61, 0x80, 0xb8, 0xac, 0xa6, 0x88, 0x09,
|
0x7c, 0xa6, 0x29, 0x95, 0x74, 0x2d, 0x87, 0xa3, 0xb0, 0x6a, 0x43, 0x71, 0x1a, 0x22, 0xdb, 0xc3,
|
||||||
0xb8, 0x49, 0x77, 0x13, 0x2c, 0xd5, 0x77, 0x50, 0xdc, 0x15, 0x9e, 0x98, 0x91, 0xee, 0xef, 0x4b,
|
0x00, 0x71, 0x61, 0x01, 0xbb, 0x59, 0x7f, 0x13, 0x2c, 0xd5, 0x77, 0x50, 0xdc, 0x15, 0xae, 0x98,
|
||||||
0xd1, 0x83, 0xff, 0x67, 0x6a, 0xdd, 0x9a, 0xee, 0x5f, 0x14, 0x28, 0xbe, 0x12, 0x46, 0xbd, 0xfd,
|
0x11, 0xef, 0xef, 0x8b, 0xd1, 0x87, 0xff, 0x67, 0x6a, 0xdd, 0x9a, 0xf2, 0x5f, 0x14, 0x28, 0xbe,
|
||||||
0x93, 0xa1, 0x6d, 0xc8, 0x87, 0x43, 0x21, 0x1e, 0x4c, 0xe9, 0xd8, 0xd9, 0x69, 0x3a, 0x08, 0xde,
|
0x12, 0x56, 0xbd, 0xfd, 0x93, 0xa1, 0x6d, 0xc8, 0x87, 0x63, 0x21, 0x9e, 0x4c, 0xe9, 0xd9, 0xd9,
|
||||||
0xd4, 0x63, 0x8b, 0xf5, 0xb0, 0x9c, 0xbd, 0x60, 0x1d, 0xc8, 0x32, 0xd3, 0xe8, 0xad, 0xc9, 0xf2,
|
0x79, 0x3a, 0x08, 0x5e, 0xd5, 0x63, 0x93, 0xf5, 0xb1, 0x9c, 0xbe, 0x60, 0x1d, 0xc8, 0x32, 0xd3,
|
||||||
0x10, 0x8a, 0x7b, 0xc4, 0x21, 0x73, 0x54, 0x59, 0x30, 0x2a, 0xf5, 0xcb, 0x0c, 0x40, 0x6c, 0x46,
|
0xe8, 0xad, 0xc9, 0xf2, 0x10, 0x8a, 0x7b, 0xc4, 0x26, 0x73, 0x54, 0x59, 0x30, 0x2c, 0x8d, 0xcb,
|
||||||
0x34, 0x84, 0xf4, 0x21, 0xe1, 0xe8, 0x49, 0x82, 0x36, 0xe6, 0x0c, 0xa4, 0xfe, 0x74, 0x69, 0x9c,
|
0x0c, 0x40, 0x6c, 0x46, 0x34, 0x84, 0xf4, 0x21, 0xe1, 0xe8, 0x49, 0x82, 0x36, 0xe6, 0x8c, 0xa4,
|
||||||
0x94, 0xe2, 0x03, 0x64, 0x82, 0xb1, 0x40, 0x49, 0x9e, 0xfc, 0xb9, 0x03, 0xa7, 0x6f, 0xde, 0x00,
|
0xfe, 0x74, 0x69, 0x9c, 0x94, 0xe2, 0x03, 0x64, 0x82, 0xb1, 0x40, 0x49, 0x1e, 0xfd, 0xb9, 0x23,
|
||||||
0x29, 0x8b, 0x7f, 0x04, 0x35, 0x74, 0x2e, 0x4a, 0x42, 0x32, 0x7f, 0xa0, 0xf4, 0xad, 0x9b, 0x40,
|
0xa7, 0x6f, 0xde, 0x00, 0x29, 0x8b, 0x7f, 0x04, 0x35, 0x74, 0x2e, 0x4a, 0x42, 0x32, 0x7f, 0xa0,
|
||||||
0xe3, 0x06, 0x42, 0x8f, 0x24, 0x6a, 0x60, 0xbe, 0xef, 0x13, 0x35, 0xb0, 0xc8, 0x89, 0x6f, 0x40,
|
0xf4, 0xad, 0x9b, 0x40, 0xe3, 0x06, 0x42, 0x8f, 0x24, 0x6a, 0x60, 0xbe, 0xef, 0x13, 0x35, 0xb0,
|
||||||
0x0d, 0x7d, 0x93, 0xa8, 0x81, 0xf9, 0x16, 0xd3, 0x8b, 0x33, 0x13, 0xb1, 0x1f, 0xfc, 0x82, 0x34,
|
0xc8, 0x89, 0x6f, 0x40, 0x0d, 0x7d, 0x93, 0xa8, 0x81, 0xf9, 0x16, 0xd3, 0x8b, 0x33, 0x13, 0xb1,
|
||||||
0xde, 0x9e, 0x5f, 0x95, 0x56, 0xbe, 0x5f, 0x95, 0x56, 0x3e, 0x8d, 0x4b, 0xca, 0xf9, 0xb8, 0xa4,
|
0x1f, 0xfc, 0x84, 0x34, 0xdf, 0x9e, 0x5f, 0x95, 0x56, 0xbe, 0x5f, 0x95, 0x56, 0x3e, 0x8d, 0x4b,
|
||||||
0x7c, 0x1b, 0x97, 0x94, 0xcb, 0x71, 0x49, 0x79, 0x7d, 0xf0, 0x07, 0x7f, 0x55, 0xdb, 0x71, 0xd4,
|
0xca, 0xf9, 0xb8, 0xa4, 0x7c, 0x1b, 0x97, 0x94, 0xcb, 0x71, 0x49, 0x79, 0x7d, 0xf0, 0x07, 0xff,
|
||||||
0x54, 0x45, 0xc5, 0x47, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x07, 0x2d, 0x75, 0x3c, 0xa6, 0x09,
|
0x55, 0xdb, 0x71, 0xd4, 0x52, 0x45, 0xc5, 0x47, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x6b, 0x95,
|
||||||
0x00, 0x00,
|
0xa9, 0x10, 0xa8, 0x09, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,17 @@ message GetContainerResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message ListContainersRequest {
|
message ListContainersRequest {
|
||||||
string filter = 1; // TODO(stevvooe): Define a filtering syntax to make these queries.
|
// Filters contains one or more filters using the syntax defined in the
|
||||||
|
// containerd filter package.
|
||||||
|
//
|
||||||
|
// The returned result will be those that match any of the provided
|
||||||
|
// filters. Expanded, containers that match the following will be
|
||||||
|
// returned:
|
||||||
|
//
|
||||||
|
// filters[0] or filters[1] or ... or filters[n-1] or filters[n]
|
||||||
|
//
|
||||||
|
// If filters is zero-length or nil, all items will be returned.
|
||||||
|
repeated string filters = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListContainersResponse {
|
message ListContainersResponse {
|
||||||
|
@ -127,8 +127,10 @@ func (c *Client) IsServing(ctx context.Context) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Containers returns all containers created in containerd
|
// Containers returns all containers created in containerd
|
||||||
func (c *Client) Containers(ctx context.Context) ([]Container, error) {
|
func (c *Client) Containers(ctx context.Context, filters ...string) ([]Container, error) {
|
||||||
r, err := c.ContainerService().List(ctx, &containers.ListContainersRequest{})
|
r, err := c.ContainerService().List(ctx, &containers.ListContainersRequest{
|
||||||
|
Filters: filters,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
52
cmd/ctr/labels.go
Normal file
52
cmd/ctr/labels.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var containersSetLabelsCommand = cli.Command{
|
||||||
|
Name: "set-labels",
|
||||||
|
Usage: "Set and clear labels for a container.",
|
||||||
|
ArgsUsage: "[flags] <name> [<key>=<value>, ...]",
|
||||||
|
Description: "Set and clear labels for a container.",
|
||||||
|
Flags: []cli.Flag{},
|
||||||
|
Action: func(clicontext *cli.Context) error {
|
||||||
|
var (
|
||||||
|
ctx, cancel = appContext(clicontext)
|
||||||
|
containerID, labels = objectWithLabelArgs(clicontext)
|
||||||
|
)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
client, err := newClient(clicontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if containerID == "" {
|
||||||
|
return errors.New("please specify a container")
|
||||||
|
}
|
||||||
|
|
||||||
|
container, err := client.LoadContainer(ctx, containerID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
setlabels, err := container.SetLabels(ctx, labels)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var labelStrings []string
|
||||||
|
for k, v := range setlabels {
|
||||||
|
labelStrings = append(labelStrings, fmt.Sprintf("%s=%s", k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(strings.Join(labelStrings, ","))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
@ -3,11 +3,11 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
tasks "github.com/containerd/containerd/api/services/tasks/v1"
|
tasks "github.com/containerd/containerd/api/services/tasks/v1"
|
||||||
tasktypes "github.com/containerd/containerd/api/types/task"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,14 +31,10 @@ var taskListCommand = cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var containerListCommand = cli.Command{
|
var containersListCommand = cli.Command{
|
||||||
Name: "containers",
|
|
||||||
Usage: "manage containers (metadata)",
|
|
||||||
Aliases: []string{"c"},
|
|
||||||
Subcommands: []cli.Command{
|
|
||||||
{
|
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "list tasks",
|
Usage: "list all tasks or those that match a filter",
|
||||||
|
ArgsUsage: "[filter, ...]",
|
||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
@ -47,8 +43,6 @@ var containerListCommand = cli.Command{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: containerListFn,
|
Action: containerListFn,
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func taskListFn(context *cli.Context) error {
|
func taskListFn(context *cli.Context) error {
|
||||||
@ -62,66 +56,25 @@ func taskListFn(context *cli.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
containers, err := client.Containers(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
s := client.TaskService()
|
s := client.TaskService()
|
||||||
|
response, err := s.List(ctx, &tasks.ListTasksRequest{})
|
||||||
tasksResponse, err := s.List(ctx, &tasks.ListTasksRequest{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join with tasks to get status.
|
|
||||||
tasksByContainerID := map[string]*tasktypes.Task{}
|
|
||||||
for _, task := range tasksResponse.Tasks {
|
|
||||||
tasksByContainerID[task.ContainerID] = task
|
|
||||||
}
|
|
||||||
|
|
||||||
if quiet {
|
if quiet {
|
||||||
for _, c := range containers {
|
for _, task := range response.Tasks {
|
||||||
task, ok := tasksByContainerID[c.ID()]
|
fmt.Println(task.ID)
|
||||||
if ok {
|
|
||||||
fmt.Printf("%s\t%d\n", c.ID(), task.Pid)
|
|
||||||
} else {
|
|
||||||
//Since task is not running, PID is printed 0
|
|
||||||
fmt.Printf("%s\t%d\n", c.ID(), 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0)
|
||||||
w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
|
fmt.Fprintln(w, "TASK\tPID\tSTATUS\t")
|
||||||
fmt.Fprintln(w, "TASK-ID\tIMAGE\tPID\tSTATUS")
|
for _, task := range response.Tasks {
|
||||||
for _, c := range containers {
|
if _, err := fmt.Fprintf(w, "%s\t%d\t%s\n",
|
||||||
var imageName string
|
task.ID,
|
||||||
if image, err := c.Image(ctx); err != nil {
|
task.Pid,
|
||||||
if err != containerd.ErrNoImage {
|
task.Status.String(),
|
||||||
return err
|
|
||||||
}
|
|
||||||
imageName = "-"
|
|
||||||
} else {
|
|
||||||
imageName = image.Name()
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
status string
|
|
||||||
pid uint32
|
|
||||||
)
|
|
||||||
task, ok := tasksByContainerID[c.ID()]
|
|
||||||
if ok {
|
|
||||||
status = task.Status.String()
|
|
||||||
pid = task.Pid
|
|
||||||
} else {
|
|
||||||
status = "STOPPED" // TODO(stevvooe): Is this assumption correct?
|
|
||||||
pid = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := fmt.Fprintf(w, "%s\t%s\t%d\t%s\n",
|
|
||||||
c.ID(),
|
|
||||||
imageName,
|
|
||||||
pid,
|
|
||||||
status,
|
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -133,6 +86,7 @@ func taskListFn(context *cli.Context) error {
|
|||||||
|
|
||||||
func containerListFn(context *cli.Context) error {
|
func containerListFn(context *cli.Context) error {
|
||||||
var (
|
var (
|
||||||
|
filters = context.Args()
|
||||||
quiet = context.Bool("quiet")
|
quiet = context.Bool("quiet")
|
||||||
ctx, cancel = appContext(context)
|
ctx, cancel = appContext(context)
|
||||||
)
|
)
|
||||||
@ -142,18 +96,28 @@ func containerListFn(context *cli.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
containers, err := client.Containers(ctx)
|
containers, err := client.Containers(ctx, filters...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if quiet {
|
if quiet {
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
fmt.Printf("%s\n", c.ID())
|
fmt.Printf("%s\n", c.ID())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cl := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0)
|
||||||
fmt.Fprintln(cl, "ID\tIMAGE\tRUNTIME\tSIZE")
|
fmt.Fprintln(w, "CONTAINER\tIMAGE\tRUNTIME\tLABELS\t")
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
|
var labelStrings []string
|
||||||
|
for k, v := range c.Proto().Labels {
|
||||||
|
labelStrings = append(labelStrings, strings.Join([]string{k, v}, "="))
|
||||||
|
}
|
||||||
|
labels := strings.Join(labelStrings, ",")
|
||||||
|
if labels == "" {
|
||||||
|
labels = "-"
|
||||||
|
}
|
||||||
|
|
||||||
var imageName string
|
var imageName string
|
||||||
if image, err := c.Image(ctx); err != nil {
|
if image, err := c.Image(ctx); err != nil {
|
||||||
if err != containerd.ErrNoImage {
|
if err != containerd.ErrNoImage {
|
||||||
@ -163,17 +127,18 @@ func containerListFn(context *cli.Context) error {
|
|||||||
} else {
|
} else {
|
||||||
imageName = image.Name()
|
imageName = image.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
proto := c.Proto()
|
proto := c.Proto()
|
||||||
if _, err := fmt.Fprintf(cl, "%s\t%s\t%s\t%d\n",
|
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%v\t\n",
|
||||||
c.ID(),
|
c.ID(),
|
||||||
imageName,
|
imageName,
|
||||||
proto.Runtime.Name,
|
proto.Runtime.Name,
|
||||||
proto.Size(),
|
labels,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cl.Flush()
|
return w.Flush()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ containerd CLI
|
|||||||
deleteCommand,
|
deleteCommand,
|
||||||
namespacesCommand,
|
namespacesCommand,
|
||||||
eventsCommand,
|
eventsCommand,
|
||||||
containerListCommand,
|
containersCommand,
|
||||||
taskListCommand,
|
taskListCommand,
|
||||||
infoCommand,
|
infoCommand,
|
||||||
killCommand,
|
killCommand,
|
||||||
@ -83,3 +83,13 @@ containerd CLI
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var containersCommand = cli.Command{
|
||||||
|
Name: "containers",
|
||||||
|
Usage: "manage containers (metadata)",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Subcommands: []cli.Command{
|
||||||
|
containersListCommand,
|
||||||
|
containersSetLabelsCommand,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -33,7 +33,7 @@ var namespacesCreateCommand = cli.Command{
|
|||||||
Action: func(clicontext *cli.Context) error {
|
Action: func(clicontext *cli.Context) error {
|
||||||
var (
|
var (
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
namespace, labels = namespaceWithLabelArgs(clicontext)
|
namespace, labels = objectWithLabelArgs(clicontext)
|
||||||
)
|
)
|
||||||
|
|
||||||
if namespace == "" {
|
if namespace == "" {
|
||||||
@ -53,27 +53,6 @@ var namespacesCreateCommand = cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func namespaceWithLabelArgs(clicontext *cli.Context) (string, map[string]string) {
|
|
||||||
var (
|
|
||||||
namespace = clicontext.Args().First()
|
|
||||||
labelStrings = clicontext.Args().Tail()
|
|
||||||
labels = make(map[string]string, len(labelStrings))
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, label := range labelStrings {
|
|
||||||
parts := strings.SplitN(label, "=", 2)
|
|
||||||
key := parts[0]
|
|
||||||
value := "true"
|
|
||||||
if len(parts) > 1 {
|
|
||||||
value = parts[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
labels[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
return namespace, labels
|
|
||||||
}
|
|
||||||
|
|
||||||
var namespacesSetLabelsCommand = cli.Command{
|
var namespacesSetLabelsCommand = cli.Command{
|
||||||
Name: "set-labels",
|
Name: "set-labels",
|
||||||
Usage: "Set and clear labels for a namespace.",
|
Usage: "Set and clear labels for a namespace.",
|
||||||
@ -83,7 +62,7 @@ var namespacesSetLabelsCommand = cli.Command{
|
|||||||
Action: func(clicontext *cli.Context) error {
|
Action: func(clicontext *cli.Context) error {
|
||||||
var (
|
var (
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
namespace, labels = namespaceWithLabelArgs(clicontext)
|
namespace, labels = objectWithLabelArgs(clicontext)
|
||||||
)
|
)
|
||||||
|
|
||||||
namespaces, err := getNamespacesService(clicontext)
|
namespaces, err := getNamespacesService(clicontext)
|
||||||
|
@ -74,6 +74,10 @@ var runCommand = cli.Command{
|
|||||||
Name: "env",
|
Name: "env",
|
||||||
Usage: "specify additional container environment variables (i.e. FOO=bar)",
|
Usage: "specify additional container environment variables (i.e. FOO=bar)",
|
||||||
},
|
},
|
||||||
|
cli.StringSliceFlag{
|
||||||
|
Name: "label",
|
||||||
|
Usage: "specify additional labels (foo=bar)",
|
||||||
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "rm",
|
Name: "rm",
|
||||||
Usage: "remove the container after running",
|
Usage: "remove the container after running",
|
||||||
|
@ -61,7 +61,11 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
|||||||
id = context.Args().Get(1)
|
id = context.Args().Get(1)
|
||||||
args = context.Args()[2:]
|
args = context.Args()[2:]
|
||||||
tty = context.Bool("tty")
|
tty = context.Bool("tty")
|
||||||
|
labelStrings = context.StringSlice("label")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
labels := labelArgs(labelStrings)
|
||||||
|
|
||||||
if raw := context.String("checkpoint"); raw != "" {
|
if raw := context.String("checkpoint"); raw != "" {
|
||||||
if checkpointIndex, err = digest.Parse(raw); err != nil {
|
if checkpointIndex, err = digest.Parse(raw); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -71,6 +75,7 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkpointIndex == "" {
|
if checkpointIndex == "" {
|
||||||
opts := []containerd.SpecOpts{
|
opts := []containerd.SpecOpts{
|
||||||
containerd.WithImageConfig(ctx, image),
|
containerd.WithImageConfig(ctx, image),
|
||||||
@ -96,12 +101,15 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
|||||||
} else {
|
} else {
|
||||||
rootfs = containerd.WithNewRootFS(id, image)
|
rootfs = containerd.WithNewRootFS(id, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.NewContainer(ctx, id,
|
return client.NewContainer(ctx, id,
|
||||||
containerd.WithSpec(spec),
|
containerd.WithSpec(spec),
|
||||||
containerd.WithImage(image),
|
containerd.WithImage(image),
|
||||||
|
containerd.WithContainerLabels(labels),
|
||||||
rootfs,
|
rootfs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.NewContainer(ctx, id, containerd.WithCheckpoint(v1.Descriptor{
|
return client.NewContainer(ctx, id, containerd.WithCheckpoint(v1.Descriptor{
|
||||||
Digest: checkpointIndex,
|
Digest: checkpointIndex,
|
||||||
}, id))
|
}, id))
|
||||||
|
@ -247,3 +247,28 @@ func replaceOrAppendEnvValues(defaults, overrides []string) []string {
|
|||||||
|
|
||||||
return defaults
|
return defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func objectWithLabelArgs(clicontext *cli.Context) (string, map[string]string) {
|
||||||
|
var (
|
||||||
|
namespace = clicontext.Args().First()
|
||||||
|
labelStrings = clicontext.Args().Tail()
|
||||||
|
)
|
||||||
|
|
||||||
|
return namespace, labelArgs(labelStrings)
|
||||||
|
}
|
||||||
|
|
||||||
|
func labelArgs(labelStrings []string) map[string]string {
|
||||||
|
labels := make(map[string]string, len(labelStrings))
|
||||||
|
for _, label := range labelStrings {
|
||||||
|
parts := strings.SplitN(label, "=", 2)
|
||||||
|
key := parts[0]
|
||||||
|
value := "true"
|
||||||
|
if len(parts) > 1 {
|
||||||
|
value = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
labels[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels
|
||||||
|
}
|
||||||
|
51
container.go
51
container.go
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@ -12,6 +13,7 @@ import (
|
|||||||
"github.com/containerd/containerd/api/services/containers/v1"
|
"github.com/containerd/containerd/api/services/containers/v1"
|
||||||
"github.com/containerd/containerd/api/services/tasks/v1"
|
"github.com/containerd/containerd/api/services/tasks/v1"
|
||||||
"github.com/containerd/containerd/api/types"
|
"github.com/containerd/containerd/api/types"
|
||||||
|
ptypes "github.com/gogo/protobuf/types"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -33,6 +35,8 @@ type Container interface {
|
|||||||
Spec() (*specs.Spec, error)
|
Spec() (*specs.Spec, error)
|
||||||
Task(context.Context, IOAttach) (Task, error)
|
Task(context.Context, IOAttach) (Task, error)
|
||||||
Image(context.Context) (Image, error)
|
Image(context.Context) (Image, error)
|
||||||
|
Labels(context.Context) (map[string]string, error)
|
||||||
|
SetLabels(context.Context, map[string]string) (map[string]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func containerFromProto(client *Client, c containers.Container) *container {
|
func containerFromProto(client *Client, c containers.Container) *container {
|
||||||
@ -60,6 +64,53 @@ func (c *container) Proto() containers.Container {
|
|||||||
return c.c
|
return c.c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *container) Labels(ctx context.Context) (map[string]string, error) {
|
||||||
|
resp, err := c.client.ContainerService().Get(ctx, &containers.GetContainerRequest{
|
||||||
|
ID: c.ID(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.c = resp.Container
|
||||||
|
|
||||||
|
m := make(map[string]string, len(resp.Container.Labels))
|
||||||
|
for k, v := range c.c.Labels {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *container) SetLabels(ctx context.Context, labels map[string]string) (map[string]string, error) {
|
||||||
|
var req containers.UpdateContainerRequest
|
||||||
|
|
||||||
|
req.Container.ID = c.ID()
|
||||||
|
req.Container.Labels = labels
|
||||||
|
|
||||||
|
req.UpdateMask = &ptypes.FieldMask{
|
||||||
|
Paths: make([]string, 0, len(labels)),
|
||||||
|
}
|
||||||
|
// mask off paths so we only muck with the labels encountered in labels.
|
||||||
|
// Labels not in the passed in argument will be left alone.
|
||||||
|
for k := range labels {
|
||||||
|
req.UpdateMask.Paths = append(req.UpdateMask.Paths, strings.Join([]string{"labels", k}, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.client.ContainerService().Update(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.c = resp.Container // update our local container
|
||||||
|
|
||||||
|
m := make(map[string]string, len(resp.Container.Labels))
|
||||||
|
for k, v := range c.c.Labels {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Spec returns the current OCI specification for the container
|
// Spec returns the current OCI specification for the container
|
||||||
func (c *container) Spec() (*specs.Spec, error) {
|
func (c *container) Spec() (*specs.Spec, error) {
|
||||||
var s specs.Spec
|
var s specs.Spec
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/filters"
|
||||||
"github.com/gogo/protobuf/types"
|
"github.com/gogo/protobuf/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,7 +30,10 @@ type RuntimeInfo struct {
|
|||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
Get(ctx context.Context, id string) (Container, error)
|
Get(ctx context.Context, id string) (Container, error)
|
||||||
List(ctx context.Context, filter string) ([]Container, error)
|
|
||||||
|
// List returns containers that match one or more of the provided filters.
|
||||||
|
List(ctx context.Context, filters ...filters.Filter) ([]Container, error)
|
||||||
|
|
||||||
Create(ctx context.Context, container Container) (Container, error)
|
Create(ctx context.Context, container Container) (Container, error)
|
||||||
Update(ctx context.Context, container Container) (Container, error)
|
Update(ctx context.Context, container Container) (Container, error)
|
||||||
Delete(ctx context.Context, id string) error
|
Delete(ctx context.Context, id string) error
|
||||||
|
@ -2,11 +2,13 @@ package metadata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
"github.com/containerd/containerd/filters"
|
||||||
"github.com/containerd/containerd/identifiers"
|
"github.com/containerd/containerd/identifiers"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
@ -43,7 +45,7 @@ func (s *containerStore) Get(ctx context.Context, id string) (containers.Contain
|
|||||||
return container, nil
|
return container, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *containerStore) List(ctx context.Context, filter string) ([]containers.Container, error) {
|
func (s *containerStore) List(ctx context.Context, fs ...filters.Filter) ([]containers.Container, error) {
|
||||||
namespace, err := namespaces.NamespaceRequired(ctx)
|
namespace, err := namespaces.NamespaceRequired(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -51,8 +53,14 @@ func (s *containerStore) List(ctx context.Context, filter string) ([]containers.
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
m []containers.Container
|
m []containers.Container
|
||||||
|
filter = filters.Filter(filters.Any(fs))
|
||||||
bkt = getContainersBucket(s.tx, namespace)
|
bkt = getContainersBucket(s.tx, namespace)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if len(fs) == 0 {
|
||||||
|
filter = filters.Always
|
||||||
|
}
|
||||||
|
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
@ -66,7 +74,10 @@ func (s *containerStore) List(ctx context.Context, filter string) ([]containers.
|
|||||||
if err := readContainer(&container, cbkt); err != nil {
|
if err := readContainer(&container, cbkt); err != nil {
|
||||||
return errors.Wrap(err, "failed to read container")
|
return errors.Wrap(err, "failed to read container")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if filter.Match(adaptContainer(container)) {
|
||||||
m = append(m, container)
|
m = append(m, container)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -75,6 +86,46 @@ func (s *containerStore) List(ctx context.Context, filter string) ([]containers.
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func adaptContainer(o interface{}) filters.Adaptor {
|
||||||
|
obj := o.(containers.Container)
|
||||||
|
return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
|
||||||
|
if len(fieldpath) == 0 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fieldpath[0] {
|
||||||
|
case "id":
|
||||||
|
return obj.ID, len(obj.ID) > 0
|
||||||
|
case "runtime":
|
||||||
|
if len(fieldpath) <= 1 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fieldpath[1] {
|
||||||
|
case "name":
|
||||||
|
return obj.Runtime.Name, len(obj.Runtime.Name) > 0
|
||||||
|
default:
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
case "image":
|
||||||
|
return obj.Image, len(obj.Image) > 0
|
||||||
|
case "labels":
|
||||||
|
return checkMap(fieldpath[1:], obj.Labels)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkMap(fieldpath []string, m map[string]string) (string, bool) {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
value, ok := m[strings.Join(fieldpath, ".")]
|
||||||
|
return value, ok
|
||||||
|
}
|
||||||
|
|
||||||
func (s *containerStore) Create(ctx context.Context, container containers.Container) (containers.Container, error) {
|
func (s *containerStore) Create(ctx context.Context, container containers.Container) (containers.Container, error) {
|
||||||
namespace, err := namespaces.NamespaceRequired(ctx)
|
namespace, err := namespaces.NamespaceRequired(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -268,14 +319,22 @@ func writeContainer(container *containers.Container, bkt *bolt.Bucket) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lbkt, err := bkt.CreateBucket(bucketKeyLabels)
|
lbkt, err := bkt.CreateBucket(bucketKeyLabels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range container.Labels {
|
for k, v := range container.Labels {
|
||||||
|
if v == "" {
|
||||||
|
delete(container.Labels, k) // remove since we don't actually set it
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if err := lbkt.Put([]byte(k), []byte(v)); err != nil {
|
if err := lbkt.Put([]byte(k), []byte(v)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ func (s *namespaceStore) namespaceEmpty(ctx context.Context, namespace string) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
containerStore := NewContainerStore(s.tx)
|
containerStore := NewContainerStore(s.tx)
|
||||||
containers, err := containerStore.List(ctx, "")
|
containers, err := containerStore.List(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -35,15 +35,25 @@ func containerToProto(container *containers.Container) api.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func containerFromProto(containerpb *api.Container) containers.Container {
|
func containerFromProto(containerpb *api.Container) containers.Container {
|
||||||
|
var runtime containers.RuntimeInfo
|
||||||
|
if containerpb.Runtime != nil {
|
||||||
|
runtime = containers.RuntimeInfo{
|
||||||
|
Name: containerpb.Runtime.Name,
|
||||||
|
Options: containerpb.Runtime.Options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var spec []byte
|
||||||
|
if containerpb.Spec != nil {
|
||||||
|
spec = containerpb.Spec.Value
|
||||||
|
}
|
||||||
|
|
||||||
return containers.Container{
|
return containers.Container{
|
||||||
ID: containerpb.ID,
|
ID: containerpb.ID,
|
||||||
Labels: containerpb.Labels,
|
Labels: containerpb.Labels,
|
||||||
Image: containerpb.Image,
|
Image: containerpb.Image,
|
||||||
Runtime: containers.RuntimeInfo{
|
Runtime: runtime,
|
||||||
Name: containerpb.Runtime.Name,
|
Spec: spec,
|
||||||
Options: containerpb.Runtime.Options,
|
|
||||||
},
|
|
||||||
Spec: containerpb.Spec.Value,
|
|
||||||
RootFS: containerpb.RootFS,
|
RootFS: containerpb.RootFS,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package containers
|
package containers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
api "github.com/containerd/containerd/api/services/containers/v1"
|
api "github.com/containerd/containerd/api/services/containers/v1"
|
||||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/events"
|
"github.com/containerd/containerd/events"
|
||||||
|
"github.com/containerd/containerd/filters"
|
||||||
"github.com/containerd/containerd/metadata"
|
"github.com/containerd/containerd/metadata"
|
||||||
"github.com/containerd/containerd/plugin"
|
"github.com/containerd/containerd/plugin"
|
||||||
"github.com/golang/protobuf/ptypes/empty"
|
"github.com/golang/protobuf/ptypes/empty"
|
||||||
@ -65,8 +68,18 @@ func (s *Service) Get(ctx context.Context, req *api.GetContainerRequest) (*api.G
|
|||||||
func (s *Service) List(ctx context.Context, req *api.ListContainersRequest) (*api.ListContainersResponse, error) {
|
func (s *Service) List(ctx context.Context, req *api.ListContainersRequest) (*api.ListContainersResponse, error) {
|
||||||
var resp api.ListContainersResponse
|
var resp api.ListContainersResponse
|
||||||
|
|
||||||
|
var fs []filters.Filter
|
||||||
|
for _, s := range req.Filters {
|
||||||
|
f, err := filters.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, grpc.Errorf(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = append(fs, f)
|
||||||
|
}
|
||||||
|
|
||||||
return &resp, errdefs.ToGRPC(s.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
return &resp, errdefs.ToGRPC(s.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
||||||
containers, err := store.List(ctx, req.Filter)
|
containers, err := store.List(ctx, fs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -108,18 +121,20 @@ func (s *Service) Create(ctx context.Context, req *api.CreateContainerRequest) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Update(ctx context.Context, req *api.UpdateContainerRequest) (*api.UpdateContainerResponse, error) {
|
func (s *Service) Update(ctx context.Context, req *api.UpdateContainerRequest) (*api.UpdateContainerResponse, error) {
|
||||||
var resp api.UpdateContainerResponse
|
var (
|
||||||
|
resp api.UpdateContainerResponse
|
||||||
|
incoming = containerFromProto(&req.Container)
|
||||||
|
)
|
||||||
|
|
||||||
if err := s.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error {
|
if err := s.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error {
|
||||||
container := containerFromProto(&req.Container)
|
|
||||||
|
|
||||||
current, err := store.Get(ctx, container.ID)
|
container, err := store.Get(ctx, incoming.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if current.ID != container.ID {
|
if container.ID != incoming.ID {
|
||||||
return grpc.Errorf(codes.InvalidArgument, "container ids must match: %v != %v", current.ID, container.ID)
|
return grpc.Errorf(codes.InvalidArgument, "container ids must match: %v != %v", container.ID, incoming.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply the field mask. If you update this code, you better follow the
|
// apply the field mask. If you update this code, you better follow the
|
||||||
@ -127,34 +142,39 @@ func (s *Service) Update(ctx context.Context, req *api.UpdateContainerRequest) (
|
|||||||
// is, do not update this code.
|
// is, do not update this code.
|
||||||
if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
|
if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
|
||||||
for _, path := range req.UpdateMask.Paths {
|
for _, path := range req.UpdateMask.Paths {
|
||||||
|
if strings.HasPrefix(path, "labels.") {
|
||||||
|
key := strings.TrimPrefix(path, "labels.")
|
||||||
|
container.Labels[key] = incoming.Labels[key]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch path {
|
switch path {
|
||||||
case "labels":
|
case "labels":
|
||||||
current.Labels = container.Labels
|
container.Labels = incoming.Labels
|
||||||
case "image":
|
case "image":
|
||||||
current.Image = container.Image
|
container.Image = incoming.Image
|
||||||
case "runtime":
|
case "runtime":
|
||||||
// TODO(stevvooe): Should this actually be allowed?
|
// TODO(stevvooe): Should this actually be allowed?
|
||||||
current.Runtime = container.Runtime
|
container.Runtime = incoming.Runtime
|
||||||
case "spec":
|
case "spec":
|
||||||
current.Spec = container.Spec
|
container.Spec = incoming.Spec
|
||||||
case "rootfs":
|
case "rootfs":
|
||||||
current.RootFS = container.RootFS
|
container.RootFS = incoming.RootFS
|
||||||
default:
|
default:
|
||||||
return grpc.Errorf(codes.InvalidArgument, "cannot update %q field", path)
|
return grpc.Errorf(codes.InvalidArgument, "cannot update %q field", path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no field mask present, just replace everything
|
// no field mask present, just replace everything
|
||||||
current = container
|
container = incoming
|
||||||
}
|
}
|
||||||
|
|
||||||
created, err := store.Update(ctx, container)
|
updated, err := store.Update(ctx, container)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Container = containerToProto(&created)
|
resp.Container = containerToProto(&updated)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return &resp, errdefs.ToGRPC(err)
|
return &resp, errdefs.ToGRPC(err)
|
||||||
|
Loading…
Reference in New Issue
Block a user