...

Source file src/edge-infra.dev/pkg/f8n/warehouse/oci/cache/image.go

Documentation: edge-infra.dev/pkg/f8n/warehouse/oci/cache

     1  package cache
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  
     8  	v1 "github.com/google/go-containerregistry/pkg/v1"
     9  
    10  	"edge-infra.dev/pkg/f8n/warehouse/oci/layer"
    11  )
    12  
    13  // cachingImage wraps access to v1.Image with a [Cache]. Implements v1.Image
    14  type cachingImage struct {
    15  	v1.Image
    16  	cache *LazyCache
    17  }
    18  
    19  // Image returns a new v1.Image backed by a [cachingImage]. OCI interface methods will read
    20  // from a [Cache] if found, falling back to wrapped inner implementation if not. Most likely,
    21  // inner Image will be a remoteImage.
    22  func Image(i v1.Image, c *LazyCache) v1.Image {
    23  	return &cachingImage{
    24  		Image: i,
    25  		cache: c,
    26  	}
    27  }
    28  
    29  func (c *cachingImage) Layers() ([]v1.Layer, error) {
    30  	m, err := c.Image.Manifest()
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	layers := make([]v1.Layer, 0, len(m.Layers))
    35  	for _, desc := range m.Layers {
    36  		l, err := c.LayerByDigest(desc.Digest)
    37  		if err != nil {
    38  			return nil, err
    39  		}
    40  		layers = append(layers, l)
    41  	}
    42  	return layers, nil
    43  }
    44  
    45  func (c *cachingImage) RawConfigFile() ([]byte, error) {
    46  	manifest, err := c.Image.Manifest()
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	h := manifest.Config.Digest
    52  	if cached, err := c.cache.getLayer(h); err == nil {
    53  		rc, err := cached.Uncompressed()
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  		defer rc.Close()
    58  		return io.ReadAll(rc)
    59  	} else if !errors.Is(err, ErrNotFound) {
    60  		return nil, err
    61  	}
    62  
    63  	raw, err := c.Image.RawConfigFile()
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	c.cache.putBlob(h, raw)
    68  	return raw, nil
    69  }
    70  
    71  // LayerByDigest returns a Layer for interacting with a particular layer of
    72  // the image, looking it up by "digest" (the compressed hash).
    73  func (c *cachingImage) LayerByDigest(h v1.Hash) (v1.Layer, error) {
    74  	if cached, err := c.cache.getLayer(h); err == nil {
    75  		return cached, nil
    76  	} else if !errors.Is(err, ErrNotFound) {
    77  		return nil, err
    78  	}
    79  
    80  	l, err := c.Image.LayerByDigest(h)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	ll, err := layer.FromOCILayer(l)
    86  	if err != nil {
    87  		return nil, fmt.Errorf("failed to convert OCI Layer to Warehouse Layer. error: %v", err)
    88  	}
    89  	return c.cache.putLayer(ll)
    90  }
    91  
    92  // TODO(dk185217): make sense of diffid vs digest
    93  func (c *cachingImage) LayerByDiffID(h v1.Hash) (v1.Layer, error) {
    94  	return c.LayerByDigest(h)
    95  }
    96  

View as plain text