github.com/lalkh/containerd@v1.4.3/services/containers/local.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 containers
    18  
    19  import (
    20  	"context"
    21  	"io"
    22  
    23  	eventstypes "github.com/containerd/containerd/api/events"
    24  	api "github.com/containerd/containerd/api/services/containers/v1"
    25  	"github.com/containerd/containerd/containers"
    26  	"github.com/containerd/containerd/errdefs"
    27  	"github.com/containerd/containerd/events"
    28  	"github.com/containerd/containerd/metadata"
    29  	"github.com/containerd/containerd/plugin"
    30  	"github.com/containerd/containerd/services"
    31  	ptypes "github.com/gogo/protobuf/types"
    32  	bolt "go.etcd.io/bbolt"
    33  	"google.golang.org/grpc"
    34  	"google.golang.org/grpc/codes"
    35  	grpcm "google.golang.org/grpc/metadata"
    36  	"google.golang.org/grpc/status"
    37  )
    38  
    39  func init() {
    40  	plugin.Register(&plugin.Registration{
    41  		Type: plugin.ServicePlugin,
    42  		ID:   services.ContainersService,
    43  		Requires: []plugin.Type{
    44  			plugin.MetadataPlugin,
    45  		},
    46  		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
    47  			m, err := ic.Get(plugin.MetadataPlugin)
    48  			if err != nil {
    49  				return nil, err
    50  			}
    51  
    52  			db := m.(*metadata.DB)
    53  			return &local{
    54  				Store:     metadata.NewContainerStore(db),
    55  				db:        db,
    56  				publisher: ic.Events,
    57  			}, nil
    58  		},
    59  	})
    60  }
    61  
    62  type local struct {
    63  	containers.Store
    64  	db        *metadata.DB
    65  	publisher events.Publisher
    66  }
    67  
    68  var _ api.ContainersClient = &local{}
    69  
    70  func (l *local) Get(ctx context.Context, req *api.GetContainerRequest, _ ...grpc.CallOption) (*api.GetContainerResponse, error) {
    71  	var resp api.GetContainerResponse
    72  
    73  	return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error {
    74  		container, err := l.Store.Get(ctx, req.ID)
    75  		if err != nil {
    76  			return err
    77  		}
    78  		containerpb := containerToProto(&container)
    79  		resp.Container = containerpb
    80  
    81  		return nil
    82  	}))
    83  }
    84  
    85  func (l *local) List(ctx context.Context, req *api.ListContainersRequest, _ ...grpc.CallOption) (*api.ListContainersResponse, error) {
    86  	var resp api.ListContainersResponse
    87  	return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error {
    88  		containers, err := l.Store.List(ctx, req.Filters...)
    89  		if err != nil {
    90  			return err
    91  		}
    92  		resp.Containers = containersToProto(containers)
    93  		return nil
    94  	}))
    95  }
    96  
    97  func (l *local) ListStream(ctx context.Context, req *api.ListContainersRequest, _ ...grpc.CallOption) (api.Containers_ListStreamClient, error) {
    98  	stream := &localStream{
    99  		ctx: ctx,
   100  	}
   101  	return stream, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error {
   102  		containers, err := l.Store.List(ctx, req.Filters...)
   103  		if err != nil {
   104  			return err
   105  		}
   106  		stream.containers = containersToProto(containers)
   107  		return nil
   108  	}))
   109  }
   110  
   111  func (l *local) Create(ctx context.Context, req *api.CreateContainerRequest, _ ...grpc.CallOption) (*api.CreateContainerResponse, error) {
   112  	var resp api.CreateContainerResponse
   113  
   114  	if err := l.withStoreUpdate(ctx, func(ctx context.Context) error {
   115  		container := containerFromProto(&req.Container)
   116  
   117  		created, err := l.Store.Create(ctx, container)
   118  		if err != nil {
   119  			return err
   120  		}
   121  
   122  		resp.Container = containerToProto(&created)
   123  
   124  		return nil
   125  	}); err != nil {
   126  		return &resp, errdefs.ToGRPC(err)
   127  	}
   128  	if err := l.publisher.Publish(ctx, "/containers/create", &eventstypes.ContainerCreate{
   129  		ID:    resp.Container.ID,
   130  		Image: resp.Container.Image,
   131  		Runtime: &eventstypes.ContainerCreate_Runtime{
   132  			Name:    resp.Container.Runtime.Name,
   133  			Options: resp.Container.Runtime.Options,
   134  		},
   135  	}); err != nil {
   136  		return &resp, err
   137  	}
   138  
   139  	return &resp, nil
   140  }
   141  
   142  func (l *local) Update(ctx context.Context, req *api.UpdateContainerRequest, _ ...grpc.CallOption) (*api.UpdateContainerResponse, error) {
   143  	if req.Container.ID == "" {
   144  		return nil, status.Errorf(codes.InvalidArgument, "Container.ID required")
   145  	}
   146  	var (
   147  		resp      api.UpdateContainerResponse
   148  		container = containerFromProto(&req.Container)
   149  	)
   150  
   151  	if err := l.withStoreUpdate(ctx, func(ctx context.Context) error {
   152  		var fieldpaths []string
   153  		if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
   154  			fieldpaths = append(fieldpaths, req.UpdateMask.Paths...)
   155  		}
   156  
   157  		updated, err := l.Store.Update(ctx, container, fieldpaths...)
   158  		if err != nil {
   159  			return err
   160  		}
   161  
   162  		resp.Container = containerToProto(&updated)
   163  		return nil
   164  	}); err != nil {
   165  		return &resp, errdefs.ToGRPC(err)
   166  	}
   167  
   168  	if err := l.publisher.Publish(ctx, "/containers/update", &eventstypes.ContainerUpdate{
   169  		ID:          resp.Container.ID,
   170  		Image:       resp.Container.Image,
   171  		Labels:      resp.Container.Labels,
   172  		SnapshotKey: resp.Container.SnapshotKey,
   173  	}); err != nil {
   174  		return &resp, err
   175  	}
   176  
   177  	return &resp, nil
   178  }
   179  
   180  func (l *local) Delete(ctx context.Context, req *api.DeleteContainerRequest, _ ...grpc.CallOption) (*ptypes.Empty, error) {
   181  	if err := l.withStoreUpdate(ctx, func(ctx context.Context) error {
   182  		return l.Store.Delete(ctx, req.ID)
   183  	}); err != nil {
   184  		return &ptypes.Empty{}, errdefs.ToGRPC(err)
   185  	}
   186  
   187  	if err := l.publisher.Publish(ctx, "/containers/delete", &eventstypes.ContainerDelete{
   188  		ID: req.ID,
   189  	}); err != nil {
   190  		return &ptypes.Empty{}, err
   191  	}
   192  
   193  	return &ptypes.Empty{}, nil
   194  }
   195  
   196  func (l *local) withStore(ctx context.Context, fn func(ctx context.Context) error) func(tx *bolt.Tx) error {
   197  	return func(tx *bolt.Tx) error {
   198  		return fn(metadata.WithTransactionContext(ctx, tx))
   199  	}
   200  }
   201  
   202  func (l *local) withStoreView(ctx context.Context, fn func(ctx context.Context) error) error {
   203  	return l.db.View(l.withStore(ctx, fn))
   204  }
   205  
   206  func (l *local) withStoreUpdate(ctx context.Context, fn func(ctx context.Context) error) error {
   207  	return l.db.Update(l.withStore(ctx, fn))
   208  }
   209  
   210  type localStream struct {
   211  	ctx        context.Context
   212  	containers []api.Container
   213  	i          int
   214  }
   215  
   216  func (s *localStream) Recv() (*api.ListContainerMessage, error) {
   217  	if s.i >= len(s.containers) {
   218  		return nil, io.EOF
   219  	}
   220  	c := s.containers[s.i]
   221  	s.i++
   222  	return &api.ListContainerMessage{
   223  		Container: &c,
   224  	}, nil
   225  }
   226  
   227  func (s *localStream) Context() context.Context {
   228  	return s.ctx
   229  }
   230  
   231  func (s *localStream) CloseSend() error {
   232  	return nil
   233  }
   234  
   235  func (s *localStream) Header() (grpcm.MD, error) {
   236  	return nil, nil
   237  }
   238  
   239  func (s *localStream) Trailer() grpcm.MD {
   240  	return nil
   241  }
   242  
   243  func (s *localStream) SendMsg(m interface{}) error {
   244  	return nil
   245  }
   246  
   247  func (s *localStream) RecvMsg(m interface{}) error {
   248  	return nil
   249  }