diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9758e718af..6cc11776cd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,8 +55,8 @@ jobs: # Builds init packages since GoReleaser won't handle this for us - name: Build init-packages For Release run: | - make release-init-package ARCH=amd64 AGENT_IMAGE=agent:$GITHUB_REF_NAME - make release-init-package ARCH=arm64 AGENT_IMAGE=agent:$GITHUB_REF_NAME + make release-init-package ARCH=amd64 AGENT_IMAGE_TAG=$GITHUB_REF_NAME + make release-init-package ARCH=arm64 AGENT_IMAGE_TAG=$GITHUB_REF_NAME - name: Run Tests run: | diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index a80ff1af0d..5a144dcdba 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -44,7 +44,7 @@ jobs: # the tests this workflow runs do not use the agent at all! - name: Build init-package run: | - make release-init-package ARCH=amd64 AGENT_IMAGE=agent:v0.23.6 + make release-init-package ARCH=amd64 AGENT_IMAGE_TAG=v0.25.2 - name: Build zarf packages run: make build-examples ARCH=amd64 diff --git a/Makefile b/Makefile index 1fe763e78c..55dcd7b333 100644 --- a/Makefile +++ b/Makefile @@ -106,7 +106,7 @@ dev: ensure-ui-build-dir ## Start a Dev Server for the Zarf UI # INTERNAL: a shim used to build the agent image only if needed on Windows using the `test` command init-package-local-agent: - @test "$(AGENT_IMAGE)" != "agent:local" || $(MAKE) build-local-agent-image + @test "$(AGENT_IMAGE_TAG)" != "local" || $(MAKE) build-local-agent-image build-local-agent-image: ## Build the Zarf agent image to be used in a locally built init package @ if [ "$(ARCH)" = "amd64" ] && [ ! -s ./build/zarf ]; then $(MAKE) build-cli-linux-amd; fi @@ -121,7 +121,7 @@ init-package: ## Create the zarf init package (must `brew install coreutils` on # INTERNAL: used to build a release version of the init package with a specific agent image release-init-package: - $(ZARF_BIN) package create -o build -a $(ARCH) --set AGENT_IMAGE=$(AGENT_IMAGE) --confirm . + $(ZARF_BIN) package create -o build -a $(ARCH) --set AGENT_IMAGE_TAG=$(AGENT_IMAGE_TAG) --confirm . build-examples: ## Build all of the example packages @test -s $(ZARF_BIN) || $(MAKE) build-cli diff --git a/docs-website/static/docs/walkthroughs/logging_init.html b/docs-website/static/docs/walkthroughs/logging_init.html index 5d5b095054..2e57e07450 100644 --- a/docs-website/static/docs/walkthroughs/logging_init.html +++ b/docs-website/static/docs/walkthroughs/logging_init.html @@ -126,7 +126,7 @@ actions: onCreate: before: - - cmd: make init-package-local-agent AGENT_IMAGE="agent:v0.24.3" + - cmd: make init-package-local-agent AGENT_IMAGE_TAG="v0.24.3" manifests: - name: zarf-agent namespace: zarf @@ -234,7 +234,13 @@ default: 2Gi constants: - name: AGENT_IMAGE - value: agent:v0.24.3 + value: defenseunicorns/zarf/agent +- name: AGENT_IMAGE_TAG + value: v0.24.3 +- name: REGISTRY_IMAGE + value: registry +- name: REGISTRY_IMAGE_TAG + value: 2.8.1 This package has 9 artifacts with software bill-of-materials (SBOM) included. You can view them now in the zarf-sbom folder in this directory or to go directly to one, open this in your browser: /Users/jason/src/github.com/jasonvanbrackel/zarf/docs/.examples/walkthroughs/zarf-sbom/sbom-viewer-docker.io_grafana_promtail_2.7.0.html @@ -331,7 +337,7 @@ Application | Username | Password | Connect Registry | zarf-push | Tka7dWq4GEit5G3GDX2dQwdh | zarf connect registry - Logging | zarf-admin | ysC9TEWsSm37pBmA3hvqrLN3 | zarf connect logging + Logging | zarf-admin | ysC9TEWsSm37pBmA3hvqrLN3 | zarf connect logging diff --git a/docs-website/static/docs/walkthroughs/logging_init_manual.html b/docs-website/static/docs/walkthroughs/logging_init_manual.html index 573cace9cb..e4a8fa5197 100644 --- a/docs-website/static/docs/walkthroughs/logging_init_manual.html +++ b/docs-website/static/docs/walkthroughs/logging_init_manual.html @@ -122,7 +122,7 @@ actions: onCreate: before: - - cmd: make init-package-local-agent AGENT_IMAGE="agent:v0.24.3" + - cmd: make init-package-local-agent AGENT_IMAGE_TAG="v0.24.3" manifests: - name: zarf-agent namespace: zarf @@ -230,7 +230,13 @@ default: 2Gi constants: - name: AGENT_IMAGE - value: agent:v0.24.3 + value: defenseunicorns/zarf/agent +- name: AGENT_IMAGE_TAG + value: v0.24.3 +- name: REGISTRY_IMAGE + value: registry +- name: REGISTRY_IMAGE_TAG + value: 2.8.1 This package has 9 artifacts with software bill-of-materials (SBOM) included. You can view them now in the zarf-sbom folder in this directory or to go directly to one, open this in your browser: /Users/jason/src/github.com/jasonvanbrackel/zarf/docs-website/zarf-sbom/sbom-viewer-docker.io_grafana_promtail_2.7.0.html diff --git a/docs-website/static/docs/walkthroughs/zarf_init.html b/docs-website/static/docs/walkthroughs/zarf_init.html index 25f24d1afd..b2d65f9149 100644 --- a/docs-website/static/docs/walkthroughs/zarf_init.html +++ b/docs-website/static/docs/walkthroughs/zarf_init.html @@ -127,7 +127,7 @@ actions: onCreate: before: - - cmd: make init-package-local-agent AGENT_IMAGE="agent:v0.25.0" + - cmd: make init-package-local-agent AGENT_IMAGE_TAG="v0.25.0" manifests: - name: zarf-agent namespace: zarf @@ -235,7 +235,13 @@ default: 2Gi constants: - name: AGENT_IMAGE - value: agent:v0.25.0 + value: defenseunicorns/zarf/agent +- name: AGENT_IMAGE_TAG + value: v0.25.0 +- name: REGISTRY_IMAGE + value: registry +- name: REGISTRY_IMAGE_TAG + value: 2.8.1 This package has 9 artifacts with software bill-of-materials (SBOM) included. You can view them now in the zarf-sbom folder in this directory or to go directly to one, open this in your browser: /Users/josimoore/Desktop/projects/zarf/zarf-sbom/sbom-viewer-docker.io_grafana_promtail_2.7.2.html @@ -350,33 +356,33 @@ - + • Copying 1 filesCopying 1 filesGathering cluster informationGathering cluster informationAttempting to bootstrap the seed image into the clusterAttempting to bootstrap the seed image into the cluster - +
📦 ZARF-SEED-REGISTRY COMPONENT
- + • Loading the Zarf State from the Kubernetes clusterLoading the Zarf State from the Kubernetes clusterProcessing helm chart docker-registry:1.0.0 from Zarf-generated helm chartProcessing helm chart docker-registry:1.0.0 from Zarf-generated helm chart - +
📦 ZARF-REGISTRY COMPONENT
- + • Opening tunnel 62270 -> 5000 for svc/zarf-docker-registry in namespace zarfCreating port forwarding tunnel at http://127.0.0.1:62270/v2/_catalogStoring images in the zarf registry @@ -395,14 +401,14 @@ Zarf-generated helm chartProcessing helm chart raw-init-zarf-registry-kep-1755-registry-annotation:0.1.1680014363 from Zarf-generated helm chart - +
📦 ZARF-AGENT COMPONENT
- + • Opening tunnel 62284 -> 5000 for svc/zarf-docker-registry in namespace zarfCreating port forwarding tunnel at http://127.0.0.1:62284/v2/_catalogStoring images in the zarf registry @@ -412,12 +418,12 @@ • Processing helm chart raw-init-zarf-agent-zarf-agent:0.1.1680014363 from Zarf-generated helm chartProcessing helm chart raw-init-zarf-agent-zarf-agent:0.1.1680014363 from Zarf-generated helm chart Zarf deployment complete - - + + Application | Username | Password | Connect Registry | zarf-push | DdarrzTahz6oclGTUAUOfbsY | zarf connect registry - + - \ No newline at end of file + diff --git a/docs/4-user-guide/1-the-zarf-cli/index.md b/docs/4-user-guide/1-the-zarf-cli/index.md index d976e14350..f4f9e76afd 100644 --- a/docs/4-user-guide/1-the-zarf-cli/index.md +++ b/docs/4-user-guide/1-the-zarf-cli/index.md @@ -111,7 +111,7 @@ cd build If you installed Zarf through Homebrew, Zarf will already be on your $PATH and you can skip this section. ::: -To simplify the usage of the Zarf CLI, you may add it to your $PATH. This configuration will allow you to use `zarf` without having to specify the binary’s precise location and your computer will automatically find the binary for you to execute. The directories listed in your $PATH can be viewed by executing the command `echo $PATH` in your terminal. If you move your CLI to any of these directories, you will be able to execute it without the need to specify its full path. A typical $PATH you can use is: `mv ./path/to/cli/file/zarf /usr/local/bin/zarf` +To simplify the usage of the Zarf CLI, you may add it to your $PATH. This configuration will allow you to use `zarf` without having to specify the binary's precise location and your computer will automatically find the binary for you to execute. The directories listed in your $PATH can be viewed by executing the command `echo $PATH` in your terminal. If you move your CLI to any of these directories, you will be able to execute it without the need to specify its full path. A typical $PATH you can use is: `mv ./path/to/cli/file/zarf /usr/local/bin/zarf` :::note Throughout the rest of the documentation, we will often be describing commands as `zarf {command}`. This assumes that the CLI is on your $PATH. @@ -132,7 +132,7 @@ The `zarf init` command is utilized to configure a K8s cluster in preparation fo ### zarf package deploy - + The `zarf package deploy` command is used to deploy an already built tar.zst package onto a machine, typically within a K8s cluster. Generally, it is presumed that the `zarf init` command has already been executed on the target machine. However, there are a few exceptional cases where this assumption does not apply. diff --git a/packages/zarf-agent/manifests/deployment.yaml b/packages/zarf-agent/manifests/deployment.yaml index 6db7c3c08a..2d4767ba56 100644 --- a/packages/zarf-agent/manifests/deployment.yaml +++ b/packages/zarf-agent/manifests/deployment.yaml @@ -22,7 +22,7 @@ spec: priorityClassName: system-node-critical containers: - name: server - image: "###ZARF_REGISTRY###/defenseunicorns/zarf/###ZARF_CONST_AGENT_IMAGE###" + image: "###ZARF_REGISTRY###/###ZARF_CONST_AGENT_IMAGE###:###ZARF_CONST_AGENT_IMAGE_TAG###" imagePullPolicy: IfNotPresent livenessProbe: httpGet: diff --git a/packages/zarf-agent/zarf.yaml b/packages/zarf-agent/zarf.yaml index 5a86bcf02c..1c9d3d12c1 100644 --- a/packages/zarf-agent/zarf.yaml +++ b/packages/zarf-agent/zarf.yaml @@ -6,6 +6,8 @@ metadata: constants: - name: AGENT_IMAGE value: "###ZARF_PKG_TMPL_AGENT_IMAGE###" + - name: AGENT_IMAGE_TAG + value: "###ZARF_PKG_TMPL_AGENT_IMAGE_TAG###" components: - name: zarf-agent @@ -16,7 +18,7 @@ components: docker registry and git server. required: true images: - - "ghcr.io/defenseunicorns/zarf/###ZARF_PKG_TMPL_AGENT_IMAGE###" + - "###ZARF_PKG_TMPL_AGENT_IMAGE_DOMAIN######ZARF_PKG_TMPL_AGENT_IMAGE###:###ZARF_PKG_TMPL_AGENT_IMAGE_TAG###" manifests: - name: zarf-agent namespace: zarf @@ -28,4 +30,4 @@ components: actions: onCreate: before: - - cmd: "make init-package-local-agent AGENT_IMAGE=\"###ZARF_PKG_TMPL_AGENT_IMAGE###\"" + - cmd: "make init-package-local-agent AGENT_IMAGE_TAG=\"###ZARF_PKG_TMPL_AGENT_IMAGE_TAG###\"" diff --git a/packages/zarf-injector/zarf.yaml b/packages/zarf-injector/zarf.yaml deleted file mode 100644 index d13e4532ac..0000000000 --- a/packages/zarf-injector/zarf.yaml +++ /dev/null @@ -1,16 +0,0 @@ -kind: ZarfPackageConfig -metadata: - name: "init-package-zarf-injector" - -components: - - name: zarf-injector - description: | - Bootstraps a Kubernetes cluster by cloning a running pod in the cluster and hosting the registry image. - Removed and destroyed after the Zarf Registry is self-hosting the registry image. - required: true - cosignKeyPath: ../../cosign.pub - files: - # Rust Injector Binary - - source: sget://defenseunicorns/zarf-injector:###ZARF_PKG_ARCH###-###ZARF_PKG_TMPL_INJECTOR_VERSION### - target: "###ZARF_TEMP###/zarf-injector" - executable: true diff --git a/packages/zarf-registry/chart/values.yaml b/packages/zarf-registry/chart/values.yaml index 21bc048815..4021519942 100644 --- a/packages/zarf-registry/chart/values.yaml +++ b/packages/zarf-registry/chart/values.yaml @@ -18,8 +18,6 @@ persistence: enabled: true size: 20Gi -storage: filesystem - secrets: htpasswd: "" configData: diff --git a/packages/zarf-registry/registry-values-seed.yaml b/packages/zarf-registry/registry-values-seed.yaml index 88c6586c46..d80d1b1e8b 100644 --- a/packages/zarf-registry/registry-values-seed.yaml +++ b/packages/zarf-registry/registry-values-seed.yaml @@ -1,2 +1,3 @@ image: - repository: "###ZARF_SEED_REGISTRY###/library/registry" + repository: "###ZARF_SEED_REGISTRY###/###ZARF_CONST_REGISTRY_IMAGE###" + tag: "###ZARF_CONST_REGISTRY_IMAGE_TAG###" diff --git a/packages/zarf-registry/registry-values.yaml b/packages/zarf-registry/registry-values.yaml index 050debb97a..03fcba3d2d 100644 --- a/packages/zarf-registry/registry-values.yaml +++ b/packages/zarf-registry/registry-values.yaml @@ -4,7 +4,8 @@ persistence: existingClaim: "###ZARF_VAR_REGISTRY_EXISTING_PVC###" image: - repository: "###ZARF_REGISTRY###/library/registry" + repository: "###ZARF_REGISTRY###/###ZARF_CONST_REGISTRY_IMAGE###" + tag: "###ZARF_CONST_REGISTRY_IMAGE_TAG###" imagePullSecrets: - name: private-registry diff --git a/packages/zarf-registry/zarf.yaml b/packages/zarf-registry/zarf.yaml index 609dd3c06f..f251654b4b 100644 --- a/packages/zarf-registry/zarf.yaml +++ b/packages/zarf-registry/zarf.yaml @@ -39,7 +39,26 @@ variables: description: "Enable the Horizontal Pod Autoscaler for the registry" default: "true" +constants: + - name: REGISTRY_IMAGE + value: "###ZARF_PKG_TMPL_REGISTRY_IMAGE###" + + - name: REGISTRY_IMAGE_TAG + value: "###ZARF_PKG_TMPL_REGISTRY_IMAGE_TAG###" + components: + - name: zarf-injector + description: | + Bootstraps a Kubernetes cluster by cloning a running pod in the cluster and hosting the registry image. + Removed and destroyed after the Zarf Registry is self-hosting the registry image. + required: true + cosignKeyPath: ../../cosign.pub + files: + # Rust Injector Binary + - source: sget://defenseunicorns/zarf-injector:###ZARF_PKG_ARCH###-###ZARF_PKG_TMPL_INJECTOR_VERSION### + target: "###ZARF_TEMP###/zarf-injector" + executable: true + - name: zarf-seed-registry description: | Deploys the Zarf Registry using the registry image provided by the Zarf Injector. @@ -52,10 +71,13 @@ components: valuesFiles: - registry-values.yaml - registry-values-seed.yaml + images: + # The seed image (or images) that will be injected (see zarf-config.toml) + - "###ZARF_PKG_TMPL_REGISTRY_IMAGE_DOMAIN######ZARF_PKG_TMPL_REGISTRY_IMAGE###:###ZARF_PKG_TMPL_REGISTRY_IMAGE_TAG###" - name: zarf-registry description: | - Updates the Zarf Registry to use the self-hosted registry image. + Updates the Zarf Registry to use the self-hosted registry image. Serves as the primary docker registry for the cluster. manifests: - name: registry-connect @@ -74,3 +96,6 @@ components: namespace: zarf valuesFiles: - registry-values.yaml + images: + # This image (or images) must match that used for injection (see zarf-config.toml) + - "###ZARF_PKG_TMPL_REGISTRY_IMAGE_DOMAIN######ZARF_PKG_TMPL_REGISTRY_IMAGE###:###ZARF_PKG_TMPL_REGISTRY_IMAGE_TAG###" diff --git a/src/config/config.go b/src/config/config.go index e536792541..f87d0b1514 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -58,9 +58,6 @@ const ( ZarfInClusterGitServiceURL = "http://zarf-gitea-http.zarf.svc.cluster.local:3000" ZarfInClusterArtifactServiceURL = ZarfInClusterGitServiceURL + "/api/packages/" + ZarfGitPushUser - - ZarfSeedImage = "registry" - ZarfSeedTag = "2.8.1" ) // Zarf Global Configuration Variables. diff --git a/src/internal/cluster/injector.go b/src/internal/cluster/injector.go index b0aca683d7..3b8b11135c 100644 --- a/src/internal/cluster/injector.go +++ b/src/internal/cluster/injector.go @@ -15,8 +15,10 @@ import ( "github.com/defenseunicorns/zarf/src/config" "github.com/defenseunicorns/zarf/src/pkg/k8s" "github.com/defenseunicorns/zarf/src/pkg/message" + "github.com/defenseunicorns/zarf/src/pkg/transform" "github.com/defenseunicorns/zarf/src/pkg/utils" "github.com/defenseunicorns/zarf/src/types" + "github.com/google/go-containerregistry/pkg/crane" "github.com/mholt/archiver/v3" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -27,7 +29,7 @@ import ( var payloadChunkSize = 1024 * 768 // StartInjectionMadness initializes a Zarf injection into the cluster. -func (c *Cluster) StartInjectionMadness(tempPath types.TempPaths) { +func (c *Cluster) StartInjectionMadness(tempPath types.TempPaths, injectorSeedTags []string) { message.Debugf("packager.runInjectionMadness(%#v)", tempPath) spinner := message.NewProgressSpinner("Attempting to bootstrap the seed image into the cluster") @@ -37,6 +39,7 @@ func (c *Cluster) StartInjectionMadness(tempPath types.TempPaths) { var images k8s.ImageNodeMap var payloadConfigmaps []string var sha256sum string + var seedImages []transform.Image // Get all the images from the cluster spinner.Updatef("Getting the list of existing cluster images") @@ -56,6 +59,11 @@ func (c *Cluster) StartInjectionMadness(tempPath types.TempPaths) { config.ZarfSeedPort = fmt.Sprintf("%d", service.Spec.Ports[0].NodePort) } + spinner.Updatef("Loading the seed image from the package") + if seedImages, err = c.loadSeedImages(tempPath, injectorSeedTags, spinner); err != nil { + spinner.Fatalf(err, "Unable to load the injector seed image from the package") + } + spinner.Updatef("Loading the seed registry configmaps") if payloadConfigmaps, sha256sum, err = c.createPayloadConfigmaps(tempPath, spinner); err != nil { spinner.Fatalf(err, "Unable to generate the injector payload configmaps") @@ -93,7 +101,7 @@ func (c *Cluster) StartInjectionMadness(tempPath types.TempPaths) { } // if no error, try and wait for a seed image to be present, return if successful - if c.injectorIsReady(spinner) { + if c.injectorIsReady(seedImages, spinner) { return } @@ -121,13 +129,37 @@ func (c *Cluster) StopInjectionMadness() error { return c.Kube.DeleteService(ZarfNamespace, "zarf-injector") } +func (c *Cluster) loadSeedImages(tempPath types.TempPaths, injectorSeedTags []string, spinner *message.Spinner) ([]transform.Image, error) { + var seedImages []transform.Image + + // Load the injector-specific images and save them as seed-images + for _, src := range injectorSeedTags { + spinner.Updatef("Loading the seed image '%s' from the package", src) + + img, err := utils.LoadOCIImage(tempPath.Images, src) + if err != nil { + return seedImages, err + } + + crane.SaveOCI(img, tempPath.SeedImages) + + imgRef, err := transform.ParseImageRef(src) + if err != nil { + return seedImages, err + } + seedImages = append(seedImages, imgRef) + } + + return seedImages, nil +} + func (c *Cluster) createPayloadConfigmaps(tempPath types.TempPaths, spinner *message.Spinner) ([]string, string, error) { message.Debugf("packager.tryInjectorPayloadDeploy(%#v)", tempPath) var configMaps []string // Chunk size has to accommodate base64 encoding & etcd 1MB limit tarPath := filepath.Join(tempPath.Base, "payload.tgz") - tarFileList, err := filepath.Glob(filepath.Join(tempPath.Base, "seed-image", "*")) + tarFileList, err := filepath.Glob(filepath.Join(tempPath.SeedImages, "*")) if err != nil { return configMaps, "", err } @@ -175,7 +207,7 @@ func (c *Cluster) createPayloadConfigmaps(tempPath types.TempPaths, spinner *mes } // Test for pod readiness and seed image presence. -func (c *Cluster) injectorIsReady(spinner *message.Spinner) bool { +func (c *Cluster) injectorIsReady(seedImages []transform.Image, spinner *message.Spinner) bool { message.Debugf("packager.injectorIsReady()") // Establish the zarf connect tunnel @@ -190,11 +222,13 @@ func (c *Cluster) injectorIsReady(spinner *message.Spinner) bool { spinner.Updatef("Testing the injector for seed image availability") - seedRegistry := fmt.Sprintf("%s/v2/library/%s/manifests/%s", tunnel.HTTPEndpoint(), config.ZarfSeedImage, config.ZarfSeedTag) - if resp, err := http.Get(seedRegistry); err != nil || resp.StatusCode != 200 { - // Just debug log the output because failures just result in trying the next image - message.Debug(resp, err) - return false + for _, seedImage := range seedImages { + seedRegistry := fmt.Sprintf("%s/v2/%s/manifests/%s", tunnel.HTTPEndpoint(), seedImage.Path, seedImage.Tag) + if resp, err := http.Get(seedRegistry); err != nil || resp.StatusCode != 200 { + // Just debug log the output because failures just result in trying the next image + message.Debug(resp, err) + return false + } } spinner.Updatef("Seed image found, injector is ready") diff --git a/src/internal/packager/images/common.go b/src/internal/packager/images/common.go index e3c403f436..3a9a1a1824 100644 --- a/src/internal/packager/images/common.go +++ b/src/internal/packager/images/common.go @@ -9,11 +9,10 @@ import ( "os" "github.com/defenseunicorns/zarf/src/config" + "github.com/defenseunicorns/zarf/src/pkg/utils" "github.com/defenseunicorns/zarf/src/types" "github.com/google/go-containerregistry/pkg/crane" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/layout" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // ImgConfig is the main struct for managing container images. @@ -44,29 +43,5 @@ func (i ImgConfig) LoadImageFromPackage(imgTag string) (v1.Image, error) { } // Load the image from the OCI formatted images directory - return LoadImage(i.ImagesPath, imgTag) -} - -// LoadImage returns a v1.Image with the image tag specified from a location provided, or an error if the image cannot be found. -func LoadImage(imgPath, imgTag string) (v1.Image, error) { - // Use the manifest within the index.json to load the specific image we want - layoutPath := layout.Path(imgPath) - imgIdx, err := layoutPath.ImageIndex() - if err != nil { - return nil, err - } - idxManifest, err := imgIdx.IndexManifest() - if err != nil { - return nil, err - } - - // Search through all the manifests within this package until we find the annotation that matches our tag - for _, manifest := range idxManifest.Manifests { - if manifest.Annotations[ocispec.AnnotationBaseImageName] == imgTag { - // This is the image we are looking for, load it and then return - return layoutPath.Image(manifest.Digest) - } - } - - return nil, fmt.Errorf("unable to find image (%s) at the path (%s)", imgTag, imgPath) + return utils.LoadOCIImage(i.ImagesPath, imgTag) } diff --git a/src/internal/packager/sbom/catalog.go b/src/internal/packager/sbom/catalog.go index 16b13fb4e4..3f26cad23c 100755 --- a/src/internal/packager/sbom/catalog.go +++ b/src/internal/packager/sbom/catalog.go @@ -21,7 +21,6 @@ import ( "github.com/anchore/syft/syft/sbom" "github.com/anchore/syft/syft/source" "github.com/defenseunicorns/zarf/src/config" - "github.com/defenseunicorns/zarf/src/internal/packager/images" "github.com/defenseunicorns/zarf/src/pkg/message" "github.com/defenseunicorns/zarf/src/pkg/utils" "github.com/defenseunicorns/zarf/src/types" @@ -77,7 +76,7 @@ func Catalog(componentSBOMs map[string]*types.ComponentSBOM, imgList []string, t builder.spinner.Updatef("Creating image SBOMs (%d of %d): %s", currImage, imageCount, tag) // Get the image that we are creating an SBOM for - img, err := images.LoadImage(tmpPaths.Images, tag) + img, err := utils.LoadOCIImage(tmpPaths.Images, tag) if err != nil { builder.spinner.Errorf(err, "Unable to load the image to generate an SBOM") return err diff --git a/src/pkg/packager/common.go b/src/pkg/packager/common.go index 3945c5878e..4ed230daf7 100644 --- a/src/pkg/packager/common.go +++ b/src/pkg/packager/common.go @@ -168,7 +168,7 @@ func createPaths() (paths types.TempPaths, err error) { Base: basePath, InjectBinary: filepath.Join(basePath, "zarf-injector"), - SeedImage: filepath.Join(basePath, "seed-image"), + SeedImages: filepath.Join(basePath, "seed-images"), Images: filepath.Join(basePath, "images"), Components: filepath.Join(basePath, "components"), SbomTar: filepath.Join(basePath, "sboms.tar"), diff --git a/src/pkg/packager/create.go b/src/pkg/packager/create.go index 22ed3d10b1..539da3d5ac 100755 --- a/src/pkg/packager/create.go +++ b/src/pkg/packager/create.go @@ -26,7 +26,6 @@ import ( "github.com/defenseunicorns/zarf/src/pkg/message" "github.com/defenseunicorns/zarf/src/pkg/utils" "github.com/defenseunicorns/zarf/src/types" - "github.com/google/go-containerregistry/pkg/crane" "github.com/mholt/archiver/v3" ) @@ -75,17 +74,6 @@ func (p *Packager) Create(baseDir string) error { } } - seedImage := fmt.Sprintf("%s:%s", config.ZarfSeedImage, config.ZarfSeedTag) - - // Add the seed image to the registry component if this is an init config. - if p.cfg.IsInitConfig { - for idx, c := range p.cfg.Pkg.Components { - if c.Name == "zarf-registry" { - p.cfg.Pkg.Components[idx].Images = append(c.Images, seedImage) - } - } - } - // Perform early package validation. if err := validate.Run(p.cfg.Pkg); err != nil { return fmt.Errorf("unable to validate package: %w", err) @@ -95,29 +83,6 @@ func (p *Packager) Create(baseDir string) error { return fmt.Errorf("package creation canceled") } - // Save the seed image as an OCI image if this is an init config. - if p.cfg.IsInitConfig { - spinner := message.NewProgressSpinner("Loading Zarf Registry Seed Image") - defer spinner.Stop() - - ociPath := path.Join(p.tmp.Base, "seed-image") - imgConfig := images.ImgConfig{ - Insecure: config.CommonOptions.Insecure, - Architectures: []string{p.cfg.Pkg.Metadata.Architecture, p.cfg.Pkg.Build.Architecture}, - } - - image, err := imgConfig.PullImage(seedImage, spinner) - if err != nil { - return fmt.Errorf("unable to pull seed image: %w", err) - } - - if err := crane.SaveOCI(image, ociPath); err != nil { - return fmt.Errorf("unable to save image %s as OCI: %w", image, err) - } - - spinner.Success() - } - var combinedImageList []string componentSBOMs := map[string]*types.ComponentSBOM{} for _, component := range p.cfg.Pkg.Components { diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 028c8b2808..e1ea4e43aa 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -103,7 +103,7 @@ func (p *Packager) deployComponents() (deployedComponents []types.DeployedCompon if p.cfg.IsInitConfig { charts, err = p.deployInitComponent(component) } else { - charts, err = p.deployComponent(component, false /* keep img checksum */) + charts, err = p.deployComponent(component, false /* keep img checksum */, false /* always push images */) } deployedComponent := types.DeployedComponent{Name: component.Name} @@ -158,10 +158,10 @@ func (p *Packager) deployInitComponent(component types.ZarfComponent) (charts [] // Before deploying the seed registry, start the injector if isSeedRegistry { - p.cluster.StartInjectionMadness(p.tmp) + p.cluster.StartInjectionMadness(p.tmp, component.Images) } - charts, err = p.deployComponent(component, isAgent /* skip img checksum if isAgent */) + charts, err = p.deployComponent(component, isAgent /* skip img checksum if isAgent */, isSeedRegistry /* skip image push if isSeedRegistry */) if err != nil { return charts, fmt.Errorf("unable to deploy component %s: %w", component.Name, err) } @@ -177,7 +177,7 @@ func (p *Packager) deployInitComponent(component types.ZarfComponent) (charts [] } // Deploy a Zarf Component. -func (p *Packager) deployComponent(component types.ZarfComponent, noImgChecksum bool) (charts []types.InstalledChart, err error) { +func (p *Packager) deployComponent(component types.ZarfComponent, noImgChecksum bool, noImgPush bool) (charts []types.InstalledChart, err error) { message.Debugf("packager.deployComponent(%#v, %#v", p.tmp, component) // Toggles for general deploy operations @@ -189,7 +189,7 @@ func (p *Packager) deployComponent(component types.ZarfComponent, noImgChecksum // All components now require a name message.HeaderInfof("📦 %s COMPONENT", strings.ToUpper(component.Name)) - hasImages := len(component.Images) > 0 + hasImages := len(component.Images) > 0 && !noImgPush hasCharts := len(component.Charts) > 0 hasManifests := len(component.Manifests) > 0 hasRepos := len(component.Repos) > 0 diff --git a/src/pkg/transform/image.go b/src/pkg/transform/image.go index 127fd91a63..7b7825f608 100644 --- a/src/pkg/transform/image.go +++ b/src/pkg/transform/image.go @@ -24,7 +24,7 @@ type Image struct { // ImageTransformHost replaces the base url for an image and adds a crc32 of the original url to the end of the src (note image refs are not full URLs). func ImageTransformHost(targetHost, srcReference string) (string, error) { - image, err := parseImageURL(srcReference) + image, err := ParseImageRef(srcReference) if err != nil { return "", err } @@ -37,14 +37,15 @@ func ImageTransformHost(targetHost, srcReference string) (string, error) { // ImageTransformHostWithoutChecksum replaces the base url for an image but avoids adding a checksum of the original url (note image refs are not full URLs). func ImageTransformHostWithoutChecksum(targetHost, srcReference string) (string, error) { - image, err := parseImageURL(srcReference) + image, err := ParseImageRef(srcReference) if err != nil { return "", err } return fmt.Sprintf("%s/%s%s", targetHost, image.Path, image.TagOrDigest), nil } -func parseImageURL(srcReference string) (out Image, err error) { +// ParseImageRef parses a source reference into an Image struct +func ParseImageRef(srcReference string) (out Image, err error) { ref, err := reference.ParseAnyReference(srcReference) if err != nil { return out, err diff --git a/src/pkg/transform/image_test.go b/src/pkg/transform/image_test.go index b8d017d39c..196a0ab0db 100644 --- a/src/pkg/transform/image_test.go +++ b/src/pkg/transform/image_test.go @@ -12,6 +12,8 @@ import ( var imageRefs = []string{ "nginx:1.23.3", + "defenseunicorns/zarf-agent:v0.22.1", + "defenseunicorns/zarf-agent@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de", "ghcr.io/stefanprodan/podinfo:6.3.3", "registry1.dso.mil/ironbank/opensource/defenseunicorns/zarf/zarf-agent:v0.25.0", } @@ -26,6 +28,8 @@ func TestImageTransformHost(t *testing.T) { var expectedResult = []string{ // Normal git repos and references for pushing/pulling "gitlab.com/project/library/nginx-3793515731:1.23.3", + "gitlab.com/project/defenseunicorns/zarf-agent-4283503412:v0.22.1", + "gitlab.com/project/defenseunicorns/zarf-agent-4283503412@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de", "gitlab.com/project/stefanprodan/podinfo-2985051089:6.3.3", "gitlab.com/project/ironbank/opensource/defenseunicorns/zarf/zarf-agent-2003217571:v0.25.0", } @@ -45,6 +49,8 @@ func TestImageTransformHost(t *testing.T) { func TestImageTransformHostWithoutChecksum(t *testing.T) { var expectedResult = []string{ "gitlab.com/project/library/nginx:1.23.3", + "gitlab.com/project/defenseunicorns/zarf-agent:v0.22.1", + "gitlab.com/project/defenseunicorns/zarf-agent@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de", "gitlab.com/project/stefanprodan/podinfo:6.3.3", "gitlab.com/project/ironbank/opensource/defenseunicorns/zarf/zarf-agent:v0.25.0", } @@ -60,3 +66,39 @@ func TestImageTransformHostWithoutChecksum(t *testing.T) { assert.Error(t, err) } } + +func TestParseImageRef(t *testing.T) { + var expectedResult = [][]string{ + {"docker.io/", "library/nginx", "1.23.3", ""}, + {"docker.io/", "defenseunicorns/zarf-agent", "v0.22.1", ""}, + {"docker.io/", "defenseunicorns/zarf-agent", "", "sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de"}, + {"ghcr.io/", "stefanprodan/podinfo", "6.3.3", ""}, + {"registry1.dso.mil/", "ironbank/opensource/defenseunicorns/zarf/zarf-agent", "v0.25.0", ""}, + } + + for idx, ref := range imageRefs { + img, err := ParseImageRef(ref) + assert.NoError(t, err) + tag := expectedResult[idx][2] + digest := expectedResult[idx][3] + tagOrDigest := ":" + tag + if tag == "" { + tagOrDigest = "@" + digest + } + path := expectedResult[idx][1] + name := expectedResult[idx][0] + path + reference := name + tagOrDigest + + assert.Equal(t, reference, img.Reference) + assert.Equal(t, name, img.Name) + assert.Equal(t, path, img.Path) + assert.Equal(t, tag, img.Tag) + assert.Equal(t, digest, img.Digest) + assert.Equal(t, tagOrDigest, img.TagOrDigest) + } + + for _, ref := range badImageRefs { + _, err := ParseImageRef(ref) + assert.Error(t, err) + } +} diff --git a/src/pkg/utils/image.go b/src/pkg/utils/image.go new file mode 100644 index 0000000000..0060d6a458 --- /dev/null +++ b/src/pkg/utils/image.go @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package utils provides generic helper functions. +package utils + +import ( + "fmt" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/layout" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// LoadOCIImage returns a v1.Image with the image tag specified from a location provided, or an error if the image cannot be found. +func LoadOCIImage(imgPath, imgTag string) (v1.Image, error) { + // Use the manifest within the index.json to load the specific image we want + layoutPath := layout.Path(imgPath) + imgIdx, err := layoutPath.ImageIndex() + if err != nil { + return nil, err + } + idxManifest, err := imgIdx.IndexManifest() + if err != nil { + return nil, err + } + + // Search through all the manifests within this package until we find the annotation that matches our tag + for _, manifest := range idxManifest.Manifests { + if manifest.Annotations[ocispec.AnnotationBaseImageName] == imgTag { + // This is the image we are looking for, load it and then return + return layoutPath.Image(manifest.Digest) + } + } + + return nil, fmt.Errorf("unable to find image (%s) at the path (%s)", imgTag, imgPath) +} diff --git a/src/test/e2e/50_oci_package_test.go b/src/test/e2e/50_oci_package_test.go index fd85faff3a..ad0db4300d 100644 --- a/src/test/e2e/50_oci_package_test.go +++ b/src/test/e2e/50_oci_package_test.go @@ -9,7 +9,6 @@ import ( "path/filepath" "testing" - "github.com/defenseunicorns/zarf/src/config" "github.com/defenseunicorns/zarf/src/pkg/utils" "github.com/defenseunicorns/zarf/src/pkg/utils/exec" dconfig "github.com/docker/cli/cli/config" @@ -31,10 +30,8 @@ var badRef = registry.Reference{ } func (suite *RegistryClientTestSuite) SetupSuite() { - image := fmt.Sprintf("%s:%s", config.ZarfSeedImage, config.ZarfSeedTag) - // spin up a local registry - err := exec.CmdWithPrint("docker", "run", "-d", "--restart=always", "-p", "5000:5000", "--name", "registry", image) + err := exec.CmdWithPrint("docker", "run", "-d", "--restart=always", "-p", "5000:5000", "--name", "registry", "registry:2.8.1") suite.NoError(err) // docker config folder diff --git a/src/types/runtime.go b/src/types/runtime.go index 9149aeeec8..750165b25f 100644 --- a/src/types/runtime.go +++ b/src/types/runtime.go @@ -117,7 +117,7 @@ type ComponentPaths struct { type TempPaths struct { Base string InjectBinary string - SeedImage string + SeedImages string Images string Components string SbomTar string diff --git a/zarf-config.toml b/zarf-config.toml index 04d95f2586..27263843d2 100644 --- a/zarf-config.toml +++ b/zarf-config.toml @@ -1,6 +1,13 @@ [package.create.set] -# The image tag used for the zarf agent, defaults to a dev image tag -agent_image = 'agent:local' +# The image reference to use for the Zarf agent, defaults to a locally built image +agent_image_domain = 'ghcr.io/' +agent_image = 'defenseunicorns/zarf/agent' +agent_image_tag = 'local' # Tag for the zarf injector binary to use injector_version = '2023-02-09' + +# The image reference to use for the registry that Zarf deploys into the cluster +registry_image_domain = '' +registry_image = 'library/registry' +registry_image_tag = '2.8.1' diff --git a/zarf.yaml b/zarf.yaml index 7f2e48c98c..c22d6435a4 100644 --- a/zarf.yaml +++ b/zarf.yaml @@ -12,7 +12,7 @@ components: - name: zarf-injector required: true import: - path: packages/zarf-injector + path: packages/zarf-registry # Creates the temporary seed-registry - name: zarf-seed-registry @@ -26,15 +26,18 @@ components: import: path: packages/zarf-registry + # Creates the pod+git mutating webhook - name: zarf-agent required: true import: path: packages/zarf-agent + # (Optional) Adds logging to the cluster - name: logging import: path: packages/logging-pgl + # (Optional) Adds a git server to the cluster - name: git-server import: path: packages/gitea