...

Source file src/edge-infra.dev/pkg/edge/component/build/image/image.go

Documentation: edge-infra.dev/pkg/edge/component/build/image

     1  // Package image provides utilities for defining container image structs and working
     2  // with them.
     3  package image
     4  
     5  import (
     6  	"fmt"
     7  	"strings"
     8  
     9  	"edge-infra.dev/pkg/lib/errors"
    10  
    11  	"github.com/google/go-containerregistry/pkg/crane"
    12  )
    13  
    14  // Image defines information we care about for a given container image.
    15  // `yaml` tags used so the struct can be correctly marshaled by Kpt
    16  type Image struct {
    17  	// Digest is the sha256 digest for the image
    18  	Digest string `yaml:"digest"`
    19  	// Registry is the container registry string, e.g., us.gcr.io,
    20  	// ncr-emeraldedge-docker-dev.jfrog.io.
    21  	// https://docs.microsoft.com/en-us/azure/container-registry/container-registry-concepts#registry
    22  	Registry string `yaml:"registry,omitempty"`
    23  	// Repository is the container name, e.g., talaria.  They can also contain slashes,
    24  	// used to implement namespacing in some registries, such as GCR.
    25  	// For GCR, the repository would be $project-id/talaria by default, but they
    26  	// can be more deeply nested.
    27  	// Multiple namespaces can also be used:
    28  	// https://docs.microsoft.com/en-us/azure/container-registry/container-registry-concepts#repository
    29  	Repository string `yaml:"repository"`
    30  }
    31  
    32  // Reference creates the fully qualified image reference string for an Image based
    33  // on the digest, e.g. us-east1-docker.pkg.dev/ret-edge-pltf-infra/workloads/talaria@sha256:...
    34  func (img *Image) Reference() string {
    35  	return fmt.Sprintf("%s/%s@%s", img.Registry, img.Repository, img.Digest)
    36  }
    37  
    38  // Name returns the colloquial container image name, e.g., `talaria`.
    39  //
    40  // Useful for pulling out a consistent image identifier regardless of the
    41  // repository.
    42  // For example, say we need to identify container image references for the same
    43  // container image across multiple registries, GCR and JFrog.  Since GCR
    44  // supports repository namespacing (and enforces you namespace by your $project-id),
    45  // simply comparing the repository will not work ($project-id/talaria wont match talaria).
    46  //
    47  // Note that the name is a substring of the Image.Repository.  If the
    48  // registry implementation supports repository namespacing, then it will
    49  // be the last token after splitting on `/` and removing the tag/digest.
    50  // If the registry implementation does _not_ support repository namespacing,
    51  // the repository is the container image name.
    52  func (img *Image) Name() string {
    53  	if strings.Contains(img.Repository, "/") {
    54  		return NameFromRef(img.Repository)
    55  	}
    56  	return img.Repository
    57  }
    58  
    59  // NameFromRef takes in a full container image reference string, such as
    60  // us-east1-docker.pkg.dev/ret-edge-pltf-infra/workloads/talaria:dev or gcr.io/edge/talaria@sha256:...
    61  // and returns the image name.  A very generous function which will return "" if
    62  // it cannot find a match.
    63  func NameFromRef(ref string) string {
    64  	if strings.Contains(ref, "@") {
    65  		tokens := strings.Split(ref, "@")
    66  		tokens = strings.Split(tokens[0], "/")
    67  		return tokens[len(tokens)-1]
    68  	}
    69  	if strings.Contains(ref, ":") {
    70  		// no @ means we are dealing with vanilla tag, can split on ':'
    71  		tokens := strings.Split(ref, ":")
    72  		tokens = strings.Split(tokens[0], "/")
    73  		return tokens[len(tokens)-1]
    74  	}
    75  
    76  	// no @ or : means its not really a ref, we'll try anyway and return
    77  	// the string after the final '/'
    78  	tokens := strings.Split(ref, "/")
    79  	// return empty string if we can't even do that
    80  	if len(tokens) == 0 {
    81  		return ""
    82  	}
    83  	return tokens[len(tokens)-1]
    84  }
    85  
    86  // TagImage tags an individual image with all passed in tags
    87  func TagImage(img Image, tags []string) error {
    88  	for _, tag := range tags {
    89  		ref := img.Reference()
    90  		if err := crane.Tag(ref, tag); err != nil {
    91  			return errors.New(fmt.Sprintf("failed to tag %s with %s", ref, tag), err)
    92  		}
    93  	}
    94  	return nil
    95  }
    96  

View as plain text