github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/internal/packager/images/push.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // SPDX-FileCopyrightText: 2021-Present The Jackal Authors
     3  
     4  // Package images provides functions for building and pushing images.
     5  package images
     6  
     7  import (
     8  	"fmt"
     9  	"net/http"
    10  	"time"
    11  
    12  	"github.com/Racer159/jackal/src/config"
    13  	"github.com/Racer159/jackal/src/pkg/cluster"
    14  	"github.com/Racer159/jackal/src/pkg/k8s"
    15  	"github.com/Racer159/jackal/src/pkg/message"
    16  	"github.com/Racer159/jackal/src/pkg/transform"
    17  	"github.com/Racer159/jackal/src/pkg/utils"
    18  	"github.com/defenseunicorns/pkg/helpers"
    19  	"github.com/google/go-containerregistry/pkg/crane"
    20  	"github.com/google/go-containerregistry/pkg/logs"
    21  	v1 "github.com/google/go-containerregistry/pkg/v1"
    22  )
    23  
    24  // PushToJackalRegistry pushes a provided image into the configured Jackal registry
    25  // This function will optionally shorten the image name while appending a checksum of the original image name.
    26  func (i *ImageConfig) PushToJackalRegistry() error {
    27  	message.Debug("images.PushToJackalRegistry()")
    28  
    29  	logs.Warn.SetOutput(&message.DebugWriter{})
    30  	logs.Progress.SetOutput(&message.DebugWriter{})
    31  
    32  	refInfoToImage := map[transform.Image]v1.Image{}
    33  	var totalSize int64
    34  	// Build an image list from the references
    35  	for _, refInfo := range i.ImageList {
    36  		img, err := utils.LoadOCIImage(i.ImagesPath, refInfo)
    37  		if err != nil {
    38  			return err
    39  		}
    40  		refInfoToImage[refInfo] = img
    41  		imgSize, err := calcImgSize(img)
    42  		if err != nil {
    43  			return err
    44  		}
    45  		totalSize += imgSize
    46  	}
    47  
    48  	// If this is not a no checksum image push we will be pushing two images (the second will go faster as it checks the same layers)
    49  	if !i.NoChecksum {
    50  		totalSize = totalSize * 2
    51  	}
    52  
    53  	httpTransport := http.DefaultTransport.(*http.Transport).Clone()
    54  	httpTransport.TLSClientConfig.InsecureSkipVerify = i.Insecure
    55  	// TODO (@WSTARR) This is set to match the TLSHandshakeTimeout to potentially mitigate effects of https://github.com/Racer159/jackal/issues/1444
    56  	httpTransport.ResponseHeaderTimeout = 10 * time.Second
    57  	progressBar := message.NewProgressBar(totalSize, fmt.Sprintf("Pushing %d images to the jackal registry", len(i.ImageList)))
    58  	defer progressBar.Stop()
    59  	craneTransport := helpers.NewTransport(httpTransport, progressBar)
    60  
    61  	pushOptions := config.GetCraneOptions(i.Insecure, i.Architectures...)
    62  	pushOptions = append(pushOptions, config.GetCraneAuthOption(i.RegInfo.PushUsername, i.RegInfo.PushPassword))
    63  	pushOptions = append(pushOptions, crane.WithTransport(craneTransport))
    64  
    65  	var (
    66  		err         error
    67  		tunnel      *k8s.Tunnel
    68  		registryURL string
    69  	)
    70  
    71  	registryURL = i.RegInfo.Address
    72  
    73  	c, _ := cluster.NewCluster()
    74  	if c != nil {
    75  		registryURL, tunnel, err = c.ConnectToJackalRegistryEndpoint(i.RegInfo)
    76  		if err != nil {
    77  			return err
    78  		}
    79  	}
    80  
    81  	if tunnel != nil {
    82  		defer tunnel.Close()
    83  	}
    84  
    85  	pushImage := func(img v1.Image, name string) error {
    86  		if tunnel != nil {
    87  			return tunnel.Wrap(func() error { return crane.Push(img, name, pushOptions...) })
    88  		}
    89  
    90  		return crane.Push(img, name, pushOptions...)
    91  	}
    92  
    93  	for refInfo, img := range refInfoToImage {
    94  		refTruncated := message.Truncate(refInfo.Reference, 55, true)
    95  		progressBar.UpdateTitle(fmt.Sprintf("Pushing %s", refTruncated))
    96  
    97  		// If this is not a no checksum image push it for use with the Jackal agent
    98  		if !i.NoChecksum {
    99  			offlineNameCRC, err := transform.ImageTransformHost(registryURL, refInfo.Reference)
   100  			if err != nil {
   101  				return err
   102  			}
   103  
   104  			message.Debugf("crane.Push() %s:%s -> %s)", i.ImagesPath, refInfo.Reference, offlineNameCRC)
   105  
   106  			err = pushImage(img, offlineNameCRC)
   107  			if err != nil {
   108  				return err
   109  			}
   110  		}
   111  
   112  		// To allow for other non-jackal workloads to easily see the images upload a non-checksum version
   113  		// (this may result in collisions but this is acceptable for this use case)
   114  		offlineName, err := transform.ImageTransformHostWithoutChecksum(registryURL, refInfo.Reference)
   115  		if err != nil {
   116  			return err
   117  		}
   118  
   119  		message.Debugf("crane.Push() %s:%s -> %s)", i.ImagesPath, refInfo.Reference, offlineName)
   120  
   121  		err = pushImage(img, offlineName)
   122  		if err != nil {
   123  			return err
   124  		}
   125  	}
   126  
   127  	progressBar.Successf("Pushed %d images to the jackal registry", len(i.ImageList))
   128  
   129  	return nil
   130  }
   131  
   132  func calcImgSize(img v1.Image) (int64, error) {
   133  	size, err := img.Size()
   134  	if err != nil {
   135  		return size, err
   136  	}
   137  
   138  	layers, err := img.Layers()
   139  	if err != nil {
   140  		return size, err
   141  	}
   142  
   143  	for _, layer := range layers {
   144  		ls, err := layer.Size()
   145  		if err != nil {
   146  			return size, err
   147  		}
   148  		size += ls
   149  	}
   150  
   151  	return size, nil
   152  }