diff --git a/pkg/cri/sbserver/images/service.go b/pkg/cri/sbserver/images/service.go index 54321ad9f..32865362d 100644 --- a/pkg/cri/sbserver/images/service.go +++ b/pkg/cri/sbserver/images/service.go @@ -27,6 +27,7 @@ import ( imagestore "github.com/containerd/containerd/pkg/cri/store/image" snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot" "github.com/containerd/containerd/pkg/kmutex" + "github.com/containerd/containerd/platforms" docker "github.com/distribution/reference" imagedigest "github.com/opencontainers/go-digest" ) @@ -52,7 +53,7 @@ func NewService(config criconfig.Config, imageFSPath string, client *containerd. svc := CRIImageService{ config: config, client: client, - imageStore: imagestore.NewStore(client), + imageStore: imagestore.NewStore(client.ImageService(), client.ContentStore(), platforms.Default()), imageFSPath: imageFSPath, snapshotStore: snapshotstore.NewStore(), unpackDuplicationSuppressor: kmutex.New(), diff --git a/pkg/cri/sbserver/images/service_test.go b/pkg/cri/sbserver/images/service_test.go index 6420e45f5..e1208169b 100644 --- a/pkg/cri/sbserver/images/service_test.go +++ b/pkg/cri/sbserver/images/service_test.go @@ -24,6 +24,7 @@ import ( criconfig "github.com/containerd/containerd/pkg/cri/config" imagestore "github.com/containerd/containerd/pkg/cri/store/image" snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot" + "github.com/containerd/containerd/platforms" "github.com/stretchr/testify/assert" ) @@ -42,7 +43,7 @@ func newTestCRIService() *CRIImageService { return &CRIImageService{ config: testConfig, imageFSPath: testImageFSPath, - imageStore: imagestore.NewStore(nil), + imageStore: imagestore.NewStore(nil, nil, platforms.Default()), snapshotStore: snapshotstore.NewStore(), } } diff --git a/pkg/cri/server/service.go b/pkg/cri/server/service.go index 259b6cfce..ef154e648 100644 --- a/pkg/cri/server/service.go +++ b/pkg/cri/server/service.go @@ -34,6 +34,7 @@ import ( "github.com/containerd/containerd/pkg/cri/nri" "github.com/containerd/containerd/pkg/cri/streaming" "github.com/containerd/containerd/pkg/kmutex" + "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" cni "github.com/containerd/go-cni" "google.golang.org/grpc" @@ -128,7 +129,7 @@ func NewCRIService(config criconfig.Config, client *containerd.Client, nri *nri. os: osinterface.RealOS{}, sandboxStore: sandboxstore.NewStore(labels), containerStore: containerstore.NewStore(labels), - imageStore: imagestore.NewStore(client), + imageStore: imagestore.NewStore(client.ImageService(), client.ContentStore(), platforms.Default()), snapshotStore: snapshotstore.NewStore(), sandboxNameIndex: registrar.NewRegistrar(), containerNameIndex: registrar.NewRegistrar(), diff --git a/pkg/cri/server/service_test.go b/pkg/cri/server/service_test.go index 3143cedf6..1a715092c 100644 --- a/pkg/cri/server/service_test.go +++ b/pkg/cri/server/service_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/platforms" "github.com/containerd/go-cni" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -45,7 +46,7 @@ func newTestCRIService() *criService { imageFSPath: testImageFSPath, os: ostesting.NewFakeOS(), sandboxStore: sandboxstore.NewStore(labels), - imageStore: imagestore.NewStore(nil), + imageStore: imagestore.NewStore(nil, nil, platforms.Default()), snapshotStore: snapshotstore.NewStore(), sandboxNameIndex: registrar.NewRegistrar(), containerStore: containerstore.NewStore(labels), diff --git a/pkg/cri/store/image/fake_image.go b/pkg/cri/store/image/fake_image.go index 4b4636004..96532aa93 100644 --- a/pkg/cri/store/image/fake_image.go +++ b/pkg/cri/store/image/fake_image.go @@ -16,12 +16,16 @@ package image -import "fmt" +import ( + "fmt" + + "github.com/containerd/containerd/platforms" +) // NewFakeStore returns an image store with predefined images. // Update is not allowed for this fake store. func NewFakeStore(images []Image) (*Store, error) { - s := NewStore(nil) + s := NewStore(nil, nil, platforms.Default()) for _, i := range images { for _, ref := range i.References { s.refCache[ref] = i.ID diff --git a/pkg/cri/store/image/image.go b/pkg/cri/store/image/image.go index 12e8e1188..71b22a0e4 100644 --- a/pkg/cri/store/image/image.go +++ b/pkg/cri/store/image/image.go @@ -18,15 +18,20 @@ package image import ( "context" + "encoding/json" "fmt" "sync" - "github.com/containerd/containerd" + "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/images/usage" "github.com/containerd/containerd/pkg/cri/labels" "github.com/containerd/containerd/pkg/cri/util" + "github.com/containerd/containerd/platforms" docker "github.com/distribution/reference" + "github.com/opencontainers/go-digest" imagedigest "github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest/digestset" imageidentity "github.com/opencontainers/image-spec/identity" @@ -50,22 +55,39 @@ type Image struct { Pinned bool } +// InfoProvider provides both content and info about content +type InfoProvider interface { + content.Provider + Info(ctx context.Context, dgst digest.Digest) (content.Info, error) +} + // Store stores all images. type Store struct { lock sync.RWMutex // refCache is a containerd image reference to image id cache. refCache map[string]string - // client is the containerd client. - client *containerd.Client + + // images is the local image store + images images.Store + + // content provider + provider InfoProvider + + // platform represents the currently supported platform for images + // TODO: Make this store multi-platform + platform platforms.MatchComparer + // store is the internal image store indexed by image id. store *store } // NewStore creates an image store. -func NewStore(client *containerd.Client) *Store { +func NewStore(img images.Store, provider InfoProvider, platform platforms.MatchComparer) *Store { return &Store{ refCache: make(map[string]string), - client: client, + images: img, + provider: provider, + platform: platform, store: &store{ images: make(map[string]Image), digestSet: digestset.NewSet(), @@ -77,13 +99,15 @@ func NewStore(client *containerd.Client) *Store { func (s *Store) Update(ctx context.Context, ref string) error { s.lock.Lock() defer s.lock.Unlock() - i, err := s.client.GetImage(ctx, ref) + + i, err := s.images.Get(ctx, ref) if err != nil && !errdefs.IsNotFound(err) { return fmt.Errorf("get image from containerd: %w", err) } + var img *Image if err == nil { - img, err = getImage(ctx, i) + img, err = s.getImage(ctx, i) if err != nil { return fmt.Errorf("get image info from containerd: %w", err) } @@ -116,36 +140,40 @@ func (s *Store) update(ref string, img *Image) error { return s.store.add(*img) } -// getImage gets image information from containerd. -func getImage(ctx context.Context, i containerd.Image) (*Image, error) { - // Get image information. - diffIDs, err := i.RootFS(ctx) +// getImage gets image information from containerd for current platform. +func (s *Store) getImage(ctx context.Context, i images.Image) (*Image, error) { + diffIDs, err := i.RootFS(ctx, s.provider, s.platform) if err != nil { return nil, fmt.Errorf("get image diffIDs: %w", err) } chainID := imageidentity.ChainID(diffIDs) - size, err := i.Size(ctx) + size, err := usage.CalculateImageUsage(ctx, i, s.provider, usage.WithManifestLimit(s.platform, 1), usage.WithManifestUsage()) if err != nil { return nil, fmt.Errorf("get image compressed resource size: %w", err) } - desc, err := i.Config(ctx) + desc, err := i.Config(ctx, s.provider, s.platform) if err != nil { return nil, fmt.Errorf("get image config descriptor: %w", err) } id := desc.Digest.String() - spec, err := i.Spec(ctx) + blob, err := content.ReadBlob(ctx, s.provider, desc) if err != nil { - return nil, fmt.Errorf("failed to get OCI image spec: %w", err) + return nil, fmt.Errorf("read image config from content store: %w", err) } - pinned := i.Labels()[labels.PinnedImageLabelKey] == labels.PinnedImageLabelValue + var spec imagespec.Image + if err := json.Unmarshal(blob, &spec); err != nil { + return nil, fmt.Errorf("unmarshal image config %s: %w", blob, err) + } + + pinned := i.Labels[labels.PinnedImageLabelKey] == labels.PinnedImageLabelValue return &Image{ ID: id, - References: []string{i.Name()}, + References: []string{i.Name}, ChainID: chainID.String(), Size: size, ImageSpec: spec,