...

Source file src/edge-infra.dev/pkg/f8n/warehouse/pallet/resolve/resolve.go

Documentation: edge-infra.dev/pkg/f8n/warehouse/pallet/resolve

     1  package resolve
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/google/go-containerregistry/pkg/name"
     7  	v1 "github.com/google/go-containerregistry/pkg/v1"
     8  	"github.com/google/go-containerregistry/pkg/v1/remote"
     9  
    10  	"edge-infra.dev/pkg/f8n/warehouse/oci"
    11  	"edge-infra.dev/pkg/f8n/warehouse/oci/walk"
    12  	"edge-infra.dev/pkg/f8n/warehouse/pallet"
    13  )
    14  
    15  // Ref calls Resolve based on the input reference to an artifact. ResolveRef
    16  // retrieves a *remote.Descriptor, converts that to an artifact based on its
    17  // MediaType and passes that artifact to Resolve.
    18  func Ref(ref name.Reference) (map[string]pallet.Pallet, error) {
    19  	desc, err := remote.Get(ref)
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  	switch {
    24  	case desc.MediaType.IsIndex():
    25  		oart, err := desc.ImageIndex()
    26  		if err != nil {
    27  			return nil, fmt.Errorf("Invalid descriptor, failed conversion to ImageIndex")
    28  		}
    29  		return Resolve(oart)
    30  	case desc.MediaType.IsImage():
    31  		oart, err := desc.Image()
    32  		if err != nil {
    33  			return nil, fmt.Errorf("Invalid descriptor, failed conversion to Image")
    34  		}
    35  		return Resolve(oart)
    36  	}
    37  	return nil, fmt.Errorf("Invalid descriptor, MediaType must be Image or ImageIndex")
    38  }
    39  
    40  // Resolve is used for handling and retrieving dependencies from the input
    41  // OCI artifact. Image Indexes are walked first, retrieving the digest from each
    42  // Image Index. Images are checked to confirm that they do not have a parent of
    43  // the same name, preventing redundant dependency retrieval. A map of all digests
    44  // is returned for use.
    45  func Resolve(a oci.Artifact, opts ...Option) (map[string]pallet.Pallet, error) {
    46  	options := makeOptions(opts...)
    47  	resolved := map[string]pallet.Pallet{}
    48  	walker := &walk.Fns{
    49  		Index: func(imgIdx v1.ImageIndex, _ v1.ImageIndex) error {
    50  			p, err := pallet.New(imgIdx)
    51  			if err != nil {
    52  				return err
    53  			}
    54  			digest, err := p.Digest()
    55  			if err != nil {
    56  				return err
    57  			}
    58  			// Check if the artifact already exists in the map and address
    59  			// potential conflicts between digests.
    60  			if existing, ok := resolved[p.Name()]; ok {
    61  				if err := checkForConflicts(existing, digest, options); err != nil {
    62  					return err
    63  				}
    64  			}
    65  			resolved[p.Name()] = p
    66  			return nil
    67  		},
    68  		Image: func(img v1.Image, parent v1.ImageIndex) error {
    69  			// if the image isn't a standalone package or we encounter an error
    70  			// determining if it is, exit early.
    71  			isPkg, err := oci.IsPackage(img, parent)
    72  			if !isPkg || err != nil {
    73  				return err
    74  			}
    75  
    76  			p, err := pallet.New(img)
    77  			if err != nil {
    78  				return err
    79  			}
    80  			digest, err := p.Digest()
    81  			if err != nil {
    82  				return err
    83  			}
    84  			// Check if the artifact already exists in the map and address
    85  			// potential conflicts between digests.
    86  			if existing, ok := resolved[p.Name()]; ok {
    87  				if err := checkForConflicts(existing, digest, options); err != nil {
    88  					return err
    89  				}
    90  			}
    91  			resolved[p.Name()] = p
    92  			return nil
    93  		},
    94  	}
    95  
    96  	if err := walk.Walk(a, walker); err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	return resolved, nil
   101  }
   102  
   103  func checkForConflicts(p pallet.Pallet, d v1.Hash, o options) error {
   104  	palletD, err := p.Digest()
   105  	if err != nil {
   106  		return err
   107  	}
   108  
   109  	switch {
   110  	case palletD == d:
   111  		return nil
   112  	case o.acceptFirst:
   113  		return nil
   114  	case o.strict:
   115  		return fmt.Errorf("resolve: %w", oci.NewConflictErr(p.Name(), palletD, d))
   116  	default:
   117  		return nil
   118  	}
   119  }
   120  

View as plain text