github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/containerstore.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package containerd 18 19 import ( 20 "context" 21 "errors" 22 "io" 23 24 containersapi "github.com/containerd/containerd/api/services/containers/v1" 25 "github.com/containerd/containerd/containers" 26 "github.com/containerd/containerd/errdefs" 27 ptypes "github.com/gogo/protobuf/types" 28 "google.golang.org/grpc/codes" 29 "google.golang.org/grpc/status" 30 ) 31 32 type remoteContainers struct { 33 client containersapi.ContainersClient 34 } 35 36 var _ containers.Store = &remoteContainers{} 37 38 // NewRemoteContainerStore returns the container Store connected with the provided client 39 func NewRemoteContainerStore(client containersapi.ContainersClient) containers.Store { 40 return &remoteContainers{ 41 client: client, 42 } 43 } 44 45 func (r *remoteContainers) Get(ctx context.Context, id string) (containers.Container, error) { 46 resp, err := r.client.Get(ctx, &containersapi.GetContainerRequest{ 47 ID: id, 48 }) 49 if err != nil { 50 return containers.Container{}, errdefs.FromGRPC(err) 51 } 52 53 return containerFromProto(&resp.Container), nil 54 } 55 56 func (r *remoteContainers) List(ctx context.Context, filters ...string) ([]containers.Container, error) { 57 containers, err := r.stream(ctx, filters...) 58 if err != nil { 59 if err == errStreamNotAvailable { 60 return r.list(ctx, filters...) 61 } 62 return nil, err 63 } 64 return containers, nil 65 } 66 67 func (r *remoteContainers) list(ctx context.Context, filters ...string) ([]containers.Container, error) { 68 resp, err := r.client.List(ctx, &containersapi.ListContainersRequest{ 69 Filters: filters, 70 }) 71 if err != nil { 72 return nil, errdefs.FromGRPC(err) 73 } 74 return containersFromProto(resp.Containers), nil 75 } 76 77 var errStreamNotAvailable = errors.New("streaming api not available") 78 79 func (r *remoteContainers) stream(ctx context.Context, filters ...string) ([]containers.Container, error) { 80 session, err := r.client.ListStream(ctx, &containersapi.ListContainersRequest{ 81 Filters: filters, 82 }) 83 if err != nil { 84 return nil, errdefs.FromGRPC(err) 85 } 86 var containers []containers.Container 87 for { 88 c, err := session.Recv() 89 if err != nil { 90 if err == io.EOF { 91 return containers, nil 92 } 93 if s, ok := status.FromError(err); ok { 94 if s.Code() == codes.Unimplemented { 95 return nil, errStreamNotAvailable 96 } 97 } 98 return nil, errdefs.FromGRPC(err) 99 } 100 select { 101 case <-ctx.Done(): 102 return containers, ctx.Err() 103 default: 104 containers = append(containers, containerFromProto(c.Container)) 105 } 106 } 107 } 108 109 func (r *remoteContainers) Create(ctx context.Context, container containers.Container) (containers.Container, error) { 110 created, err := r.client.Create(ctx, &containersapi.CreateContainerRequest{ 111 Container: containerToProto(&container), 112 }) 113 if err != nil { 114 return containers.Container{}, errdefs.FromGRPC(err) 115 } 116 117 return containerFromProto(&created.Container), nil 118 119 } 120 121 func (r *remoteContainers) Update(ctx context.Context, container containers.Container, fieldpaths ...string) (containers.Container, error) { 122 var updateMask *ptypes.FieldMask 123 if len(fieldpaths) > 0 { 124 updateMask = &ptypes.FieldMask{ 125 Paths: fieldpaths, 126 } 127 } 128 129 updated, err := r.client.Update(ctx, &containersapi.UpdateContainerRequest{ 130 Container: containerToProto(&container), 131 UpdateMask: updateMask, 132 }) 133 if err != nil { 134 return containers.Container{}, errdefs.FromGRPC(err) 135 } 136 137 return containerFromProto(&updated.Container), nil 138 139 } 140 141 func (r *remoteContainers) Delete(ctx context.Context, id string) error { 142 _, err := r.client.Delete(ctx, &containersapi.DeleteContainerRequest{ 143 ID: id, 144 }) 145 146 return errdefs.FromGRPC(err) 147 148 } 149 150 func containerToProto(container *containers.Container) containersapi.Container { 151 return containersapi.Container{ 152 ID: container.ID, 153 Labels: container.Labels, 154 Image: container.Image, 155 Runtime: &containersapi.Container_Runtime{ 156 Name: container.Runtime.Name, 157 Options: container.Runtime.Options, 158 }, 159 Spec: container.Spec, 160 Snapshotter: container.Snapshotter, 161 SnapshotKey: container.SnapshotKey, 162 Extensions: container.Extensions, 163 } 164 } 165 166 func containerFromProto(containerpb *containersapi.Container) containers.Container { 167 var runtime containers.RuntimeInfo 168 if containerpb.Runtime != nil { 169 runtime = containers.RuntimeInfo{ 170 Name: containerpb.Runtime.Name, 171 Options: containerpb.Runtime.Options, 172 } 173 } 174 return containers.Container{ 175 ID: containerpb.ID, 176 Labels: containerpb.Labels, 177 Image: containerpb.Image, 178 Runtime: runtime, 179 Spec: containerpb.Spec, 180 Snapshotter: containerpb.Snapshotter, 181 SnapshotKey: containerpb.SnapshotKey, 182 CreatedAt: containerpb.CreatedAt, 183 UpdatedAt: containerpb.UpdatedAt, 184 Extensions: containerpb.Extensions, 185 } 186 } 187 188 func containersFromProto(containerspb []containersapi.Container) []containers.Container { 189 var containers []containers.Container 190 191 for _, container := range containerspb { 192 containers = append(containers, containerFromProto(&container)) 193 } 194 195 return containers 196 }