diff --git a/common/pkg/libartifact/store/store.go b/common/pkg/libartifact/store/store.go index 0665cbe73c..d2c187c47d 100644 --- a/common/pkg/libartifact/store/store.go +++ b/common/pkg/libartifact/store/store.go @@ -39,15 +39,28 @@ var ErrEmptyArtifactName = errors.New("artifact name cannot be empty") const ManifestSchemaVersion = 2 +type EventStatus string + +const ( + EventStatusAdd EventStatus = "add" + EventStatusExtract EventStatus = "extract" + EventStatusPull EventStatus = "pull" + EventStatusPush EventStatus = "push" + EventStatusRemove EventStatus = "remove" +) + +type EventCallback func(status EventStatus, name, digest string) + type ArtifactStore struct { SystemContext *types.SystemContext storePath string lock *lockfile.LockFile + eventCallback EventCallback } // NewArtifactStore is a constructor for artifact stores. Most artifact dealings depend on this. Store path is // the filesystem location. -func NewArtifactStore(storePath string, sc *types.SystemContext) (*ArtifactStore, error) { +func NewArtifactStore(storePath string, sc *types.SystemContext, eventCallback EventCallback) (*ArtifactStore, error) { if storePath == "" { return nil, errors.New("store path cannot be empty") } @@ -60,6 +73,7 @@ func NewArtifactStore(storePath string, sc *types.SystemContext) (*ArtifactStore artifactStore := &ArtifactStore{ storePath: storePath, SystemContext: sc, + eventCallback: eventCallback, } // if the storage dir does not exist, we need to create it. @@ -113,7 +127,13 @@ func (as ArtifactStore) Remove(ctx context.Context, name string) (*digest.Digest if err != nil { return nil, err } - return artifactDigest, ir.DeleteImage(ctx, as.SystemContext) + if err := ir.DeleteImage(ctx, as.SystemContext); err != nil { + return artifactDigest, err + } + if as.eventCallback != nil { + as.eventCallback(EventStatusRemove, name, artifactDigest.String()) + } + return artifactDigest, nil } // Inspect an artifact in a local store. @@ -170,7 +190,11 @@ func (as ArtifactStore) Pull(ctx context.Context, name string, opts libimage.Cop if err != nil { return "", err } - return digest.FromBytes(artifactBytes), nil + artifactDigest := digest.FromBytes(artifactBytes) + if as.eventCallback != nil { + as.eventCallback(EventStatusPull, name, artifactDigest.String()) + } + return artifactDigest, nil } // Push an artifact to an image registry. @@ -204,6 +228,9 @@ func (as ArtifactStore) Push(ctx context.Context, src, dest string, opts libimag return "", err } artifactDigest := digest.FromBytes(artifactBytes) + if as.eventCallback != nil { + as.eventCallback(EventStatusPush, src, artifactDigest.String()) + } return artifactDigest, nil } @@ -400,6 +427,9 @@ func (as ArtifactStore) Add(ctx context.Context, dest string, artifactBlobs []li } } } + if as.eventCallback != nil { + as.eventCallback(EventStatusAdd, dest, artifactManifestDigest.String()) + } return &artifactManifestDigest, nil } @@ -525,10 +555,10 @@ func (as ArtifactStore) Extract(ctx context.Context, nameOrDigest string, target digest = arty.Manifest.Layers[0].Digest } - return copyTrustedImageBlobToFile(ctx, imgSrc, digest, target) - } - - if len(options.Digest) > 0 || len(options.Title) > 0 { + if err := copyTrustedImageBlobToFile(ctx, imgSrc, digest, target); err != nil { + return err + } + } else if len(options.Digest) > 0 || len(options.Title) > 0 { digest, err := findDigest(arty, &options.FilterBlobOptions) if err != nil { return err @@ -542,22 +572,28 @@ func (as ArtifactStore) Extract(ctx context.Context, nameOrDigest string, target return err } - return copyTrustedImageBlobToFile(ctx, imgSrc, digest, filepath.Join(target, filename)) - } - - for _, l := range arty.Manifest.Layers { - title := l.Annotations[specV1.AnnotationTitle] - filename, err := generateArtifactBlobName(title, l.Digest) - if err != nil { + if err := copyTrustedImageBlobToFile(ctx, imgSrc, digest, filepath.Join(target, filename)); err != nil { return err } + } else { + for _, l := range arty.Manifest.Layers { + title := l.Annotations[specV1.AnnotationTitle] + filename, err := generateArtifactBlobName(title, l.Digest) + if err != nil { + return err + } - err = copyTrustedImageBlobToFile(ctx, imgSrc, l.Digest, filepath.Join(target, filename)) - if err != nil { - return err + err = copyTrustedImageBlobToFile(ctx, imgSrc, l.Digest, filepath.Join(target, filename)) + if err != nil { + return err + } } } + if as.eventCallback != nil { + as.eventCallback(EventStatusExtract, arty.Name, options.Digest) + } + return nil } @@ -599,47 +635,50 @@ func (as ArtifactStore) ExtractTarStream(ctx context.Context, w io.Writer, nameO if err != nil { return err } + } else { - return nil - } + artifactBlobCount := len(arty.Manifest.Layers) - artifactBlobCount := len(arty.Manifest.Layers) + type blob struct { + name string + digest digest.Digest + } + blobs := make([]blob, 0, artifactBlobCount) - type blob struct { - name string - digest digest.Digest - } - blobs := make([]blob, 0, artifactBlobCount) + // Gather blob details and return error on any illegal names + for _, l := range arty.Manifest.Layers { + title := l.Annotations[specV1.AnnotationTitle] + digest := l.Digest + var name string - // Gather blob details and return error on any illegal names - for _, l := range arty.Manifest.Layers { - title := l.Annotations[specV1.AnnotationTitle] - digest := l.Digest - var name string + if artifactBlobCount != 1 || !options.ExcludeTitle { + name, err = generateArtifactBlobName(title, digest) + if err != nil { + return err + } + } + + blobs = append(blobs, blob{ + name: name, + digest: digest, + }) + } + + // Wrap io.Writer in a tar.Writer + tw := tar.NewWriter(w) + defer tw.Close() - if artifactBlobCount != 1 || !options.ExcludeTitle { - name, err = generateArtifactBlobName(title, digest) + // Write each blob to tar.Writer then close + for _, b := range blobs { + err := copyTrustedImageBlobToTarStream(ctx, imgSrc, b.digest, b.name, tw) if err != nil { return err } } - - blobs = append(blobs, blob{ - name: name, - digest: digest, - }) } - // Wrap io.Writer in a tar.Writer - tw := tar.NewWriter(w) - defer tw.Close() - - // Write each blob to tar.Writer then close - for _, b := range blobs { - err := copyTrustedImageBlobToTarStream(ctx, imgSrc, b.digest, b.name, tw) - if err != nil { - return err - } + if as.eventCallback != nil { + as.eventCallback(EventStatusExtract, arty.Name, options.Digest) } return nil