github.com/containerd/Containerd@v1.4.13/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  }