containerstore.go 5.9 KB

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