github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/image/utils.go (about)

     1  package image
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/url"
     7  	"regexp"
     8  	"strings"
     9  
    10  	cp "github.com/containers/image/v5/copy"
    11  	"github.com/containers/image/v5/docker/reference"
    12  	"github.com/containers/image/v5/signature"
    13  	"github.com/containers/image/v5/types"
    14  	"github.com/containers/podman/v2/libpod/define"
    15  	"github.com/containers/storage"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // findImageInRepotags takes an imageParts struct and searches images' repotags for
    20  // a match on name:tag
    21  func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, error) {
    22  	_, searchName, searchSuspiciousTagValueForSearch := search.suspiciousRefNameTagValuesForSearch()
    23  	var results []*storage.Image
    24  	for _, image := range images {
    25  		for _, name := range image.Names() {
    26  			d, err := decompose(name)
    27  			// if we get an error, ignore and keep going
    28  			if err != nil {
    29  				continue
    30  			}
    31  			_, dName, dSuspiciousTagValueForSearch := d.suspiciousRefNameTagValuesForSearch()
    32  			if dName == searchName && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch {
    33  				results = append(results, image.image)
    34  				continue
    35  			}
    36  			// account for registry:/somedir/image
    37  			if strings.HasSuffix(dName, "/"+searchName) && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch {
    38  				results = append(results, image.image)
    39  				continue
    40  			}
    41  		}
    42  	}
    43  	if len(results) == 0 {
    44  		return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName)
    45  	} else if len(results) > 1 {
    46  		return &storage.Image{}, errors.Wrapf(define.ErrMultipleImages, searchName)
    47  	}
    48  	return results[0], nil
    49  }
    50  
    51  // getCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters, inheriting some from sc.
    52  func getCopyOptions(sc *types.SystemContext, reportWriter io.Writer, srcDockerRegistry, destDockerRegistry *DockerRegistryOptions, signing SigningOptions, manifestType string, additionalDockerArchiveTags []reference.NamedTagged) *cp.Options {
    53  	if srcDockerRegistry == nil {
    54  		srcDockerRegistry = &DockerRegistryOptions{}
    55  	}
    56  	if destDockerRegistry == nil {
    57  		destDockerRegistry = &DockerRegistryOptions{}
    58  	}
    59  	srcContext := srcDockerRegistry.GetSystemContext(sc, additionalDockerArchiveTags)
    60  	destContext := destDockerRegistry.GetSystemContext(sc, additionalDockerArchiveTags)
    61  	return &cp.Options{
    62  		RemoveSignatures:      signing.RemoveSignatures,
    63  		SignBy:                signing.SignBy,
    64  		ReportWriter:          reportWriter,
    65  		SourceCtx:             srcContext,
    66  		DestinationCtx:        destContext,
    67  		ForceManifestMIMEType: manifestType,
    68  	}
    69  }
    70  
    71  // getPolicyContext sets up, initializes and returns a new context for the specified policy
    72  func getPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error) {
    73  	policy, err := signature.DefaultPolicy(ctx)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	policyContext, err := signature.NewPolicyContext(policy)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	return policyContext, nil
    83  }
    84  
    85  // hasTransport determines if the image string contains '://', returns bool
    86  func hasTransport(image string) bool {
    87  	return strings.Contains(image, "://")
    88  }
    89  
    90  // GetAdditionalTags returns a list of reference.NamedTagged for the
    91  // additional tags given in images
    92  func GetAdditionalTags(images []string) ([]reference.NamedTagged, error) {
    93  	var allTags []reference.NamedTagged
    94  	for _, img := range images {
    95  		ref, err := reference.ParseNormalizedNamed(img)
    96  		if err != nil {
    97  			return nil, errors.Wrapf(err, "error parsing additional tags")
    98  		}
    99  		refTagged, isTagged := ref.(reference.NamedTagged)
   100  		if isTagged {
   101  			allTags = append(allTags, refTagged)
   102  		}
   103  	}
   104  	return allTags, nil
   105  }
   106  
   107  // IsValidImageURI checks if image name has valid format
   108  func IsValidImageURI(imguri string) (bool, error) {
   109  	uri := "http://" + imguri
   110  	u, err := url.Parse(uri)
   111  	if err != nil {
   112  		return false, errors.Wrapf(err, "invalid image uri: %s", imguri)
   113  	}
   114  	reg := regexp.MustCompile(`^[a-zA-Z0-9-_\.]+\/?:?[0-9]*[a-z0-9-\/:]*$`)
   115  	ret := reg.FindAllString(u.Host, -1)
   116  	if len(ret) == 0 {
   117  		return false, errors.Wrapf(err, "invalid image uri: %s", imguri)
   118  	}
   119  	reg = regexp.MustCompile(`^[a-z0-9-:\./]*$`)
   120  	ret = reg.FindAllString(u.Fragment, -1)
   121  	if len(ret) == 0 {
   122  		return false, errors.Wrapf(err, "invalid image uri: %s", imguri)
   123  	}
   124  	return true, nil
   125  }
   126  
   127  // imageNameForSaveDestination returns a Docker-like reference appropriate for saving img,
   128  // which the user referred to as imgUserInput; or an empty string, if there is no appropriate
   129  // reference.
   130  func imageNameForSaveDestination(img *Image, imgUserInput string) string {
   131  	if strings.Contains(img.ID(), imgUserInput) {
   132  		return ""
   133  	}
   134  
   135  	prepend := ""
   136  	localRegistryPrefix := fmt.Sprintf("%s/", DefaultLocalRegistry)
   137  	if !strings.HasPrefix(imgUserInput, localRegistryPrefix) {
   138  		// we need to check if localhost was added to the image name in NewFromLocal
   139  		for _, name := range img.Names() {
   140  			// If the user is saving an image in the localhost registry,  getLocalImage need
   141  			// a name that matches the format localhost/<tag1>:<tag2> or localhost/<tag>:latest to correctly
   142  			// set up the manifest and save.
   143  			if strings.HasPrefix(name, localRegistryPrefix) && (strings.HasSuffix(name, imgUserInput) || strings.HasSuffix(name, fmt.Sprintf("%s:latest", imgUserInput))) {
   144  				prepend = localRegistryPrefix
   145  				break
   146  			}
   147  		}
   148  	}
   149  	return fmt.Sprintf("%s%s", prepend, imgUserInput)
   150  }