Move image event publishing to metadata store
The metadata store is in the best place to handle events directly after the database has been updated. This prevents every user of the image store interface from having to know whether or not they are responsible for publishing events and avoid double events if the grpc local service is used. Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
parent
2f807b606a
commit
86530c0afb
@ -25,6 +25,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
eventstypes "github.com/containerd/containerd/v2/api/events"
|
||||||
"github.com/containerd/containerd/v2/core/images"
|
"github.com/containerd/containerd/v2/core/images"
|
||||||
"github.com/containerd/containerd/v2/core/metadata/boltutil"
|
"github.com/containerd/containerd/v2/core/metadata/boltutil"
|
||||||
"github.com/containerd/containerd/v2/pkg/epoch"
|
"github.com/containerd/containerd/v2/pkg/epoch"
|
||||||
@ -164,6 +165,15 @@ func (s *imageStore) Create(ctx context.Context, image images.Image) (images.Ima
|
|||||||
return images.Image{}, err
|
return images.Image{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.db.dbopts.publisher != nil {
|
||||||
|
if err := s.db.dbopts.publisher.Publish(ctx, "/images/create", &eventstypes.ImageCreate{
|
||||||
|
Name: image.Name,
|
||||||
|
Labels: image.Labels,
|
||||||
|
}); err != nil {
|
||||||
|
return images.Image{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return image, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,6 +266,15 @@ func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths
|
|||||||
return images.Image{}, err
|
return images.Image{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.db.dbopts.publisher != nil {
|
||||||
|
if err := s.db.dbopts.publisher.Publish(ctx, "/images/update", &eventstypes.ImageUpdate{
|
||||||
|
Name: updated.Name,
|
||||||
|
Labels: updated.Labels,
|
||||||
|
}); err != nil {
|
||||||
|
return images.Image{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return updated, nil
|
return updated, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -273,7 +292,7 @@ func (s *imageStore) Delete(ctx context.Context, name string, opts ...images.Del
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return update(ctx, s.db, func(tx *bolt.Tx) error {
|
err = update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||||
bkt := getImagesBucket(tx, namespace)
|
bkt := getImagesBucket(tx, namespace)
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
return fmt.Errorf("image %q: %w", name, errdefs.ErrNotFound)
|
return fmt.Errorf("image %q: %w", name, errdefs.ErrNotFound)
|
||||||
@ -310,6 +329,19 @@ func (s *imageStore) Delete(ctx context.Context, name string, opts ...images.Del
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.db.dbopts.publisher != nil {
|
||||||
|
if err := s.db.dbopts.publisher.Publish(ctx, "/images/delete", &eventstypes.ImageDelete{
|
||||||
|
Name: name,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateImage(image *images.Image) error {
|
func validateImage(image *images.Image) error {
|
||||||
|
@ -38,7 +38,6 @@ import (
|
|||||||
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
|
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
|
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||||
|
|
||||||
eventstypes "github.com/containerd/containerd/v2/api/events"
|
|
||||||
containerd "github.com/containerd/containerd/v2/client"
|
containerd "github.com/containerd/containerd/v2/client"
|
||||||
"github.com/containerd/containerd/v2/core/diff"
|
"github.com/containerd/containerd/v2/core/diff"
|
||||||
containerdimages "github.com/containerd/containerd/v2/core/images"
|
containerdimages "github.com/containerd/containerd/v2/core/images"
|
||||||
@ -322,14 +321,6 @@ func (c *CRIImageService) createImageReference(ctx context.Context, name string,
|
|||||||
// TODO: Call CRIImageService directly
|
// TODO: Call CRIImageService directly
|
||||||
oldImg, err := c.images.Create(ctx, img)
|
oldImg, err := c.images.Create(ctx, img)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if c.publisher != nil {
|
|
||||||
if err := c.publisher.Publish(ctx, "/images/create", &eventstypes.ImageCreate{
|
|
||||||
Name: img.Name,
|
|
||||||
Labels: img.Labels,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
} else if !errdefs.IsAlreadyExists(err) {
|
} else if !errdefs.IsAlreadyExists(err) {
|
||||||
return err
|
return err
|
||||||
@ -338,16 +329,6 @@ func (c *CRIImageService) createImageReference(ctx context.Context, name string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err = c.images.Update(ctx, img, "target", "labels."+crilabels.ImageLabelKey)
|
_, err = c.images.Update(ctx, img, "target", "labels."+crilabels.ImageLabelKey)
|
||||||
if err == nil && c.publisher != nil {
|
|
||||||
if c.publisher != nil {
|
|
||||||
if err := c.publisher.Publish(ctx, "/images/update", &eventstypes.ImageUpdate{
|
|
||||||
Name: img.Name,
|
|
||||||
Labels: img.Labels,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
eventstypes "github.com/containerd/containerd/v2/api/events"
|
|
||||||
"github.com/containerd/containerd/v2/core/images"
|
"github.com/containerd/containerd/v2/core/images"
|
||||||
"github.com/containerd/containerd/v2/pkg/tracing"
|
"github.com/containerd/containerd/v2/pkg/tracing"
|
||||||
"github.com/containerd/errdefs"
|
"github.com/containerd/errdefs"
|
||||||
@ -63,14 +62,6 @@ func (c *GRPCCRIImageService) RemoveImage(ctx context.Context, r *runtime.Remove
|
|||||||
if err := c.imageStore.Update(ctx, ref); err != nil {
|
if err := c.imageStore.Update(ctx, ref); err != nil {
|
||||||
return nil, fmt.Errorf("failed to update image reference %q for %q: %w", ref, image.ID, err)
|
return nil, fmt.Errorf("failed to update image reference %q for %q: %w", ref, image.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.publisher != nil {
|
|
||||||
if err := c.publisher.Publish(ctx, "/images/delete", &eventstypes.ImageDelete{
|
|
||||||
Name: ref,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("failed to delete image reference %q for %q: %w", ref, image.ID, err)
|
return nil, fmt.Errorf("failed to delete image reference %q for %q: %w", ref, image.ID, err)
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
imagestore "github.com/containerd/containerd/v2/internal/cri/store/image"
|
imagestore "github.com/containerd/containerd/v2/internal/cri/store/image"
|
||||||
snapshotstore "github.com/containerd/containerd/v2/internal/cri/store/snapshot"
|
snapshotstore "github.com/containerd/containerd/v2/internal/cri/store/snapshot"
|
||||||
"github.com/containerd/containerd/v2/internal/kmutex"
|
"github.com/containerd/containerd/v2/internal/kmutex"
|
||||||
"github.com/containerd/containerd/v2/pkg/events"
|
|
||||||
"github.com/containerd/log"
|
"github.com/containerd/log"
|
||||||
"github.com/containerd/platforms"
|
"github.com/containerd/platforms"
|
||||||
docker "github.com/distribution/reference"
|
docker "github.com/distribution/reference"
|
||||||
@ -54,8 +53,6 @@ type CRIImageService struct {
|
|||||||
// images is the lower level image store used for raw storage,
|
// images is the lower level image store used for raw storage,
|
||||||
// no event publishing should currently be assumed
|
// no event publishing should currently be assumed
|
||||||
images images.Store
|
images images.Store
|
||||||
// publisher is the events publisher
|
|
||||||
publisher events.Publisher
|
|
||||||
// client is a subset of the containerd client
|
// client is a subset of the containerd client
|
||||||
// and will be replaced by image store and transfer service
|
// and will be replaced by image store and transfer service
|
||||||
client imageClient
|
client imageClient
|
||||||
@ -88,8 +85,6 @@ type CRIImageServiceOptions struct {
|
|||||||
|
|
||||||
Snapshotters map[string]snapshots.Snapshotter
|
Snapshotters map[string]snapshots.Snapshotter
|
||||||
|
|
||||||
Publisher events.Publisher
|
|
||||||
|
|
||||||
Client imageClient
|
Client imageClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
criconfig "github.com/containerd/containerd/v2/internal/cri/config"
|
criconfig "github.com/containerd/containerd/v2/internal/cri/config"
|
||||||
"github.com/containerd/containerd/v2/internal/cri/constants"
|
"github.com/containerd/containerd/v2/internal/cri/constants"
|
||||||
"github.com/containerd/containerd/v2/internal/cri/server/images"
|
"github.com/containerd/containerd/v2/internal/cri/server/images"
|
||||||
"github.com/containerd/containerd/v2/pkg/events"
|
|
||||||
"github.com/containerd/containerd/v2/plugins"
|
"github.com/containerd/containerd/v2/plugins"
|
||||||
"github.com/containerd/containerd/v2/plugins/services/warning"
|
"github.com/containerd/containerd/v2/plugins/services/warning"
|
||||||
"github.com/containerd/log"
|
"github.com/containerd/log"
|
||||||
@ -46,7 +45,6 @@ func init() {
|
|||||||
Config: &config,
|
Config: &config,
|
||||||
Requires: []plugin.Type{
|
Requires: []plugin.Type{
|
||||||
plugins.LeasePlugin,
|
plugins.LeasePlugin,
|
||||||
plugins.EventPlugin,
|
|
||||||
plugins.MetadataPlugin,
|
plugins.MetadataPlugin,
|
||||||
plugins.SandboxStorePlugin,
|
plugins.SandboxStorePlugin,
|
||||||
plugins.ServicePlugin, // For client
|
plugins.ServicePlugin, // For client
|
||||||
@ -60,11 +58,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
mdb := m.(*metadata.DB)
|
mdb := m.(*metadata.DB)
|
||||||
|
|
||||||
ep, err := ic.GetSingle(plugins.EventPlugin)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if warnings, err := criconfig.ValidateImageConfig(ic.Context, &config); err != nil {
|
if warnings, err := criconfig.ValidateImageConfig(ic.Context, &config); err != nil {
|
||||||
return nil, fmt.Errorf("invalid cri image config: %w", err)
|
return nil, fmt.Errorf("invalid cri image config: %w", err)
|
||||||
} else if len(warnings) > 0 {
|
} else if len(warnings) > 0 {
|
||||||
@ -84,7 +77,6 @@ func init() {
|
|||||||
RuntimePlatforms: map[string]images.ImagePlatform{},
|
RuntimePlatforms: map[string]images.ImagePlatform{},
|
||||||
Snapshotters: map[string]snapshots.Snapshotter{},
|
Snapshotters: map[string]snapshots.Snapshotter{},
|
||||||
ImageFSPaths: map[string]string{},
|
ImageFSPaths: map[string]string{},
|
||||||
Publisher: ep.(events.Publisher),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
options.Client, err = containerd.New(
|
options.Client, err = containerd.New(
|
||||||
|
@ -24,13 +24,11 @@ import (
|
|||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
eventstypes "github.com/containerd/containerd/v2/api/events"
|
|
||||||
imagesapi "github.com/containerd/containerd/v2/api/services/images/v1"
|
imagesapi "github.com/containerd/containerd/v2/api/services/images/v1"
|
||||||
"github.com/containerd/containerd/v2/core/images"
|
"github.com/containerd/containerd/v2/core/images"
|
||||||
"github.com/containerd/containerd/v2/core/metadata"
|
"github.com/containerd/containerd/v2/core/metadata"
|
||||||
"github.com/containerd/containerd/v2/pkg/deprecation"
|
"github.com/containerd/containerd/v2/pkg/deprecation"
|
||||||
"github.com/containerd/containerd/v2/pkg/epoch"
|
"github.com/containerd/containerd/v2/pkg/epoch"
|
||||||
"github.com/containerd/containerd/v2/pkg/events"
|
|
||||||
"github.com/containerd/containerd/v2/pkg/gc"
|
"github.com/containerd/containerd/v2/pkg/gc"
|
||||||
"github.com/containerd/containerd/v2/plugins"
|
"github.com/containerd/containerd/v2/plugins"
|
||||||
"github.com/containerd/containerd/v2/plugins/services"
|
"github.com/containerd/containerd/v2/plugins/services"
|
||||||
@ -46,7 +44,6 @@ func init() {
|
|||||||
Type: plugins.ServicePlugin,
|
Type: plugins.ServicePlugin,
|
||||||
ID: services.ImagesService,
|
ID: services.ImagesService,
|
||||||
Requires: []plugin.Type{
|
Requires: []plugin.Type{
|
||||||
plugins.EventPlugin,
|
|
||||||
plugins.MetadataPlugin,
|
plugins.MetadataPlugin,
|
||||||
plugins.GCPlugin,
|
plugins.GCPlugin,
|
||||||
plugins.WarningPlugin,
|
plugins.WarningPlugin,
|
||||||
@ -60,20 +57,15 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ep, err := ic.GetSingle(plugins.EventPlugin)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
w, err := ic.GetSingle(plugins.WarningPlugin)
|
w, err := ic.GetSingle(plugins.WarningPlugin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &local{
|
return &local{
|
||||||
store: metadata.NewImageStore(m.(*metadata.DB)),
|
store: metadata.NewImageStore(m.(*metadata.DB)),
|
||||||
publisher: ep.(events.Publisher),
|
gc: g.(gcScheduler),
|
||||||
gc: g.(gcScheduler),
|
warnings: w.(warning.Service),
|
||||||
warnings: w.(warning.Service),
|
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -84,10 +76,9 @@ type gcScheduler interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type local struct {
|
type local struct {
|
||||||
store images.Store
|
store images.Store
|
||||||
gc gcScheduler
|
gc gcScheduler
|
||||||
publisher events.Publisher
|
warnings warning.Service
|
||||||
warnings warning.Service
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ imagesapi.ImagesClient = &local{}
|
var _ imagesapi.ImagesClient = &local{}
|
||||||
@ -136,13 +127,6 @@ func (l *local) Create(ctx context.Context, req *imagesapi.CreateImageRequest, _
|
|||||||
|
|
||||||
resp.Image = imageToProto(&created)
|
resp.Image = imageToProto(&created)
|
||||||
|
|
||||||
if err := l.publisher.Publish(ctx, "/images/create", &eventstypes.ImageCreate{
|
|
||||||
Name: resp.Image.Name,
|
|
||||||
Labels: resp.Image.Labels,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
l.emitSchema1DeprecationWarning(ctx, &image)
|
l.emitSchema1DeprecationWarning(ctx, &image)
|
||||||
return &resp, nil
|
return &resp, nil
|
||||||
|
|
||||||
@ -175,13 +159,6 @@ func (l *local) Update(ctx context.Context, req *imagesapi.UpdateImageRequest, _
|
|||||||
|
|
||||||
resp.Image = imageToProto(&updated)
|
resp.Image = imageToProto(&updated)
|
||||||
|
|
||||||
if err := l.publisher.Publish(ctx, "/images/update", &eventstypes.ImageUpdate{
|
|
||||||
Name: resp.Image.Name,
|
|
||||||
Labels: resp.Image.Labels,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
l.emitSchema1DeprecationWarning(ctx, &image)
|
l.emitSchema1DeprecationWarning(ctx, &image)
|
||||||
return &resp, nil
|
return &resp, nil
|
||||||
}
|
}
|
||||||
@ -200,12 +177,6 @@ func (l *local) Delete(ctx context.Context, req *imagesapi.DeleteImageRequest, _
|
|||||||
return nil, errdefs.ToGRPC(err)
|
return nil, errdefs.ToGRPC(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := l.publisher.Publish(ctx, "/images/delete", &eventstypes.ImageDelete{
|
|
||||||
Name: req.Name,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Sync {
|
if req.Sync {
|
||||||
if _, err := l.gc.ScheduleAndWait(ctx); err != nil {
|
if _, err := l.gc.ScheduleAndWait(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
Loading…
Reference in New Issue
Block a user