diff --git a/src/internal/packager/helm/zarf.go b/src/internal/packager/helm/zarf.go index 8706fe2711..cad946986c 100644 --- a/src/internal/packager/helm/zarf.go +++ b/src/internal/packager/helm/zarf.go @@ -113,7 +113,7 @@ func (h *Helm) UpdateZarfAgentValues(ctx context.Context) error { Value: agentImage.Tag, }, }) - applicationTemplates, err := template.GetZarfTemplates("zarf-agent", h.state) + applicationTemplates, err := template.GetZarfTemplates("zarf-agent", h.state.RegistryInfo, h.state.GitServer, h.state.AgentTLS, h.state.StorageClass) if err != nil { return fmt.Errorf("error setting up the templates: %w", err) } diff --git a/src/internal/packager/template/template.go b/src/internal/packager/template/template.go index 645982865e..97d6a953b4 100644 --- a/src/internal/packager/template/template.go +++ b/src/internal/packager/template/template.go @@ -40,62 +40,56 @@ func GetZarfVariableConfig() *variables.VariableConfig { } // GetZarfTemplates returns the template keys and values to be used for templating. -func GetZarfTemplates(componentName string, state *types.ZarfState) (templateMap map[string]*variables.TextTemplate, err error) { +func GetZarfTemplates(componentName string, regInfo types.RegistryInfo, gitInfo types.GitServerInfo, agentTLS types.GeneratedPKI, storageClass string) (templateMap map[string]*variables.TextTemplate, err error) { templateMap = make(map[string]*variables.TextTemplate) - if state != nil { - regInfo := state.RegistryInfo - gitInfo := state.GitServer + builtinMap := map[string]string{ + "STORAGE_CLASS": storageClass, - builtinMap := map[string]string{ - "STORAGE_CLASS": state.StorageClass, + // Registry info + "REGISTRY": regInfo.Address, + "NODEPORT": fmt.Sprintf("%d", regInfo.NodePort), + "REGISTRY_AUTH_PUSH": regInfo.PushPassword, + "REGISTRY_AUTH_PULL": regInfo.PullPassword, - // Registry info - "REGISTRY": regInfo.Address, - "NODEPORT": fmt.Sprintf("%d", regInfo.NodePort), - "REGISTRY_AUTH_PUSH": regInfo.PushPassword, - "REGISTRY_AUTH_PULL": regInfo.PullPassword, + // Git server info + "GIT_PUSH": gitInfo.PushUsername, + "GIT_AUTH_PUSH": gitInfo.PushPassword, + "GIT_PULL": gitInfo.PullUsername, + "GIT_AUTH_PULL": gitInfo.PullPassword, + } + + builtinMap[depMarker] = config.GetDataInjectionMarker() + + // Don't template component-specific variables for every component + switch componentName { + case "zarf-agent": + builtinMap["AGENT_CRT"] = base64.StdEncoding.EncodeToString(agentTLS.Cert) + builtinMap["AGENT_KEY"] = base64.StdEncoding.EncodeToString(agentTLS.Key) + builtinMap["AGENT_CA"] = base64.StdEncoding.EncodeToString(agentTLS.CA) - // Git server info - "GIT_PUSH": gitInfo.PushUsername, - "GIT_AUTH_PUSH": gitInfo.PushPassword, - "GIT_PULL": gitInfo.PullUsername, - "GIT_AUTH_PULL": gitInfo.PullPassword, + case "zarf-seed-registry", "zarf-registry": + builtinMap["SEED_REGISTRY"] = fmt.Sprintf("%s:%s", helpers.IPV4Localhost, config.ZarfSeedPort) + htpasswd, err := generateHtpasswd(®Info) + if err != nil { + return templateMap, err } + builtinMap["HTPASSWD"] = htpasswd + builtinMap["REGISTRY_SECRET"] = regInfo.Secret + } - builtinMap[depMarker] = config.GetDataInjectionMarker() - - // Don't template component-specific variables for every component - switch componentName { - case "zarf-agent": - agentTLS := state.AgentTLS - builtinMap["AGENT_CRT"] = base64.StdEncoding.EncodeToString(agentTLS.Cert) - builtinMap["AGENT_KEY"] = base64.StdEncoding.EncodeToString(agentTLS.Key) - builtinMap["AGENT_CA"] = base64.StdEncoding.EncodeToString(agentTLS.CA) - - case "zarf-seed-registry", "zarf-registry": - builtinMap["SEED_REGISTRY"] = fmt.Sprintf("%s:%s", helpers.IPV4Localhost, config.ZarfSeedPort) - htpasswd, err := generateHtpasswd(®Info) - if err != nil { - return templateMap, err - } - builtinMap["HTPASSWD"] = htpasswd - builtinMap["REGISTRY_SECRET"] = regInfo.Secret + // Iterate over any custom variables and add them to the mappings for templating + for key, value := range builtinMap { + // Builtin keys are always uppercase in the format ###ZARF_KEY### + templateMap[strings.ToUpper(fmt.Sprintf("###ZARF_%s###", key))] = &variables.TextTemplate{ + Value: value, } - // Iterate over any custom variables and add them to the mappings for templating - for key, value := range builtinMap { - // Builtin keys are always uppercase in the format ###ZARF_KEY### - templateMap[strings.ToUpper(fmt.Sprintf("###ZARF_%s###", key))] = &variables.TextTemplate{ - Value: value, - } - - if key == "REGISTRY_SECRET" || key == "HTPASSWD" || - key == "AGENT_CA" || key == "AGENT_KEY" || key == "AGENT_CRT" || key == "GIT_AUTH_PULL" || - key == "GIT_AUTH_PUSH" || key == "REGISTRY_AUTH_PULL" || key == "REGISTRY_AUTH_PUSH" { - // Sanitize any builtin templates that are sensitive - templateMap[strings.ToUpper(fmt.Sprintf("###ZARF_%s###", key))].Sensitive = true - } + if key == "REGISTRY_SECRET" || key == "HTPASSWD" || + key == "AGENT_CA" || key == "AGENT_KEY" || key == "AGENT_CRT" || key == "GIT_AUTH_PULL" || + key == "GIT_AUTH_PUSH" || key == "REGISTRY_AUTH_PULL" || key == "REGISTRY_AUTH_PUSH" { + // Sanitize any builtin templates that are sensitive + templateMap[strings.ToUpper(fmt.Sprintf("###ZARF_%s###", key))].Sensitive = true } } diff --git a/src/pkg/cluster/namespace.go b/src/pkg/cluster/namespace.go index 6d4256ef83..d24e9cd44f 100644 --- a/src/pkg/cluster/namespace.go +++ b/src/pkg/cluster/namespace.go @@ -6,6 +6,7 @@ package cluster import ( "context" + "fmt" "time" corev1 "k8s.io/api/core/v1" @@ -15,6 +16,60 @@ import ( "github.com/zarf-dev/zarf/src/pkg/message" ) +// CreateZarfNamespace creates the Zarf namespace. +func (c *Cluster) CreateZarfNamespace(ctx context.Context) error { + // Try to create the zarf namespace. + zarfNamespace := NewZarfManagedNamespace(ZarfNamespaceName) + err := func() error { + _, err := c.Clientset.CoreV1().Namespaces().Create(ctx, zarfNamespace, metav1.CreateOptions{}) + if err != nil && !kerrors.IsAlreadyExists(err) { + return fmt.Errorf("unable to create the Zarf namespace: %w", err) + } + if err == nil { + return nil + } + _, err = c.Clientset.CoreV1().Namespaces().Update(ctx, zarfNamespace, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("unable to update the Zarf namespace: %w", err) + } + return nil + }() + if err != nil { + return err + } + + // Wait up to 2 minutes for the default service account to be created. + // Some clusters seem to take a while to create this, see https://github.com/kubernetes/kubernetes/issues/66689. + // The default SA is required for pods to start properly. + saCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() + err = func(ctx context.Context, ns, name string) error { + timer := time.NewTimer(0) + defer timer.Stop() + for { + select { + case <-ctx.Done(): + return fmt.Errorf("failed to get service account %s/%s: %w", ns, name, ctx.Err()) + case <-timer.C: + _, err := c.Clientset.CoreV1().ServiceAccounts(ns).Get(ctx, name, metav1.GetOptions{}) + if err != nil && !kerrors.IsNotFound(err) { + return err + } + if kerrors.IsNotFound(err) { + message.Debug("Service account %s/%s not found, retrying...", ns, name) + timer.Reset(1 * time.Second) + continue + } + return nil + } + } + }(saCtx, ZarfNamespaceName, "default") + if err != nil { + return fmt.Errorf("unable get default Zarf service account: %w", err) + } + return nil +} + // DeleteZarfNamespace deletes the Zarf namespace from the connected cluster. func (c *Cluster) DeleteZarfNamespace(ctx context.Context) error { spinner := message.NewProgressSpinner("Deleting the zarf namespace from this cluster") diff --git a/src/pkg/cluster/state.go b/src/pkg/cluster/state.go index 7ce8a3fa6d..fa15eb4bfa 100644 --- a/src/pkg/cluster/state.go +++ b/src/pkg/cluster/state.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "slices" - "time" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" @@ -34,7 +33,7 @@ const ( ) // InitZarfState initializes the Zarf state with the given temporary directory and init configs. -func (c *Cluster) InitZarfState(ctx context.Context, initOptions types.ZarfInitOptions) error { +func (c *Cluster) InitZarfState(ctx context.Context, initOptions types.ZarfInitOptions) (*types.ZarfState, error) { spinner := message.NewProgressSpinner("Gathering cluster state information") defer spinner.Stop() @@ -43,7 +42,7 @@ func (c *Cluster) InitZarfState(ctx context.Context, initOptions types.ZarfInitO spinner.Updatef("Checking cluster for existing Zarf deployment") state, err := c.LoadZarfState(ctx) if err != nil && !kerrors.IsNotFound(err) { - return fmt.Errorf("failed to check for existing state: %w", err) + return nil, fmt.Errorf("failed to check for existing state: %w", err) } // If state is nil, this is a new cluster. @@ -59,14 +58,14 @@ func (c *Cluster) InitZarfState(ctx context.Context, initOptions types.ZarfInitO // Otherwise, trying to detect the K8s distro type. nodeList, err := c.Clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{}) if err != nil { - return err + return nil, err } if len(nodeList.Items) == 0 { - return fmt.Errorf("cannot init Zarf state in empty cluster") + return nil, fmt.Errorf("cannot init Zarf state in empty cluster") } namespaceList, err := c.Clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) if err != nil { - return err + return nil, err } state.Distro = detectDistro(nodeList.Items[0], namespaceList.Items) } @@ -78,13 +77,13 @@ func (c *Cluster) InitZarfState(ctx context.Context, initOptions types.ZarfInitO // Setup zarf agent PKI agentTLS, err := pki.GeneratePKI(config.ZarfAgentHost) if err != nil { - return err + return nil, err } state.AgentTLS = agentTLS namespaceList, err := c.Clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) if err != nil { - return fmt.Errorf("unable to get the Kubernetes namespaces: %w", err) + return nil, fmt.Errorf("unable to get the Kubernetes namespaces: %w", err) } // Mark existing namespaces as ignored for the zarf agent to prevent mutating resources we don't own. for _, namespace := range namespaceList.Items { @@ -98,69 +97,18 @@ func (c *Cluster) InitZarfState(ctx context.Context, initOptions types.ZarfInitO namespaceCopy := namespace _, err := c.Clientset.CoreV1().Namespaces().Update(ctx, &namespaceCopy, metav1.UpdateOptions{}) if err != nil { - return fmt.Errorf("unable to mark the namespace %s as ignored by Zarf Agent: %w", namespace.Name, err) - } - } - - // Try to create the zarf namespace. - spinner.Updatef("Creating the Zarf namespace") - zarfNamespace := NewZarfManagedNamespace(ZarfNamespaceName) - err = func() error { - _, err := c.Clientset.CoreV1().Namespaces().Create(ctx, zarfNamespace, metav1.CreateOptions{}) - if err != nil && !kerrors.IsAlreadyExists(err) { - return fmt.Errorf("unable to create the Zarf namespace: %w", err) - } - if err == nil { - return nil - } - _, err = c.Clientset.CoreV1().Namespaces().Update(ctx, zarfNamespace, metav1.UpdateOptions{}) - if err != nil { - return fmt.Errorf("unable to update the Zarf namespace: %w", err) - } - return nil - }() - if err != nil { - return err - } - - // Wait up to 2 minutes for the default service account to be created. - // Some clusters seem to take a while to create this, see https://github.com/kubernetes/kubernetes/issues/66689. - // The default SA is required for pods to start properly. - saCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - err = func(ctx context.Context, ns, name string) error { - timer := time.NewTimer(0) - defer timer.Stop() - for { - select { - case <-ctx.Done(): - return fmt.Errorf("failed to get service account %s/%s: %w", ns, name, ctx.Err()) - case <-timer.C: - _, err := c.Clientset.CoreV1().ServiceAccounts(ns).Get(ctx, name, metav1.GetOptions{}) - if err != nil && !kerrors.IsNotFound(err) { - return err - } - if kerrors.IsNotFound(err) { - message.Debug("Service account %s/%s not found, retrying...", ns, name) - timer.Reset(1 * time.Second) - continue - } - return nil - } + return nil, fmt.Errorf("unable to mark the namespace %s as ignored by Zarf Agent: %w", namespace.Name, err) } - }(saCtx, ZarfNamespaceName, "default") - if err != nil { - return fmt.Errorf("unable get default Zarf service account: %w", err) } err = initOptions.GitServer.FillInEmptyValues() if err != nil { - return err + return nil, err } state.GitServer = initOptions.GitServer err = initOptions.RegistryInfo.FillInEmptyValues() if err != nil { - return err + return nil, err } state.RegistryInfo = initOptions.RegistryInfo initOptions.ArtifactServer.FillInEmptyValues() @@ -199,10 +147,10 @@ func (c *Cluster) InitZarfState(ctx context.Context, initOptions types.ZarfInitO // Save the state back to K8s if err := c.SaveZarfState(ctx, state); err != nil { - return fmt.Errorf("unable to save the Zarf state: %w", err) + return nil, fmt.Errorf("unable to save the Zarf state: %w", err) } - return nil + return state, nil } // LoadZarfState returns the current zarf/zarf-state secret data or an empty ZarfState. diff --git a/src/pkg/cluster/state_test.go b/src/pkg/cluster/state_test.go index 1575528f4a..24af90d8a2 100644 --- a/src/pkg/cluster/state_test.go +++ b/src/pkg/cluster/state_test.go @@ -202,7 +202,7 @@ func TestInitZarfState(t *testing.T) { } }() - err := c.InitZarfState(ctx, tt.initOpts) + _, err := c.InitZarfState(ctx, tt.initOpts) if tt.expectedErr != "" { require.EqualError(t, err, tt.expectedErr) return diff --git a/src/pkg/packager/common.go b/src/pkg/packager/common.go index dd4588a193..7d8a62f6fe 100644 --- a/src/pkg/packager/common.go +++ b/src/pkg/packager/common.go @@ -32,7 +32,6 @@ import ( type Packager struct { cfg *types.PackagerConfig variableConfig *variables.VariableConfig - state *types.ZarfState cluster *cluster.Cluster layout *layout.PackagePaths hpaModified bool diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 612fa5eb10..197b7faf04 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -20,7 +20,6 @@ import ( corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/defenseunicorns/pkg/helpers/v2" @@ -44,6 +43,37 @@ var ( localClusterServiceRegex = regexp.MustCompile(`^(?P[^\.]+)\.(?P[^\.]+)\.svc\.cluster\.local$`) ) +func (p *Packager) getZarfState(ctx context.Context) (*types.ZarfState, error) { + err := p.cluster.CreateZarfNamespace(ctx) + if err != nil { + return nil, err + } + if p.cfg.Pkg.IsInitConfig() { + state, err := p.cluster.InitZarfState(ctx, p.cfg.InitOpts) + if err != nil { + return nil, fmt.Errorf("unable to initialize Zarf state: %w", err) + } + return state, nil + } + state, err := p.cluster.LoadZarfState(ctx) + // State does not have to exist when running in YOLO mode. + if kerrors.IsNotFound(err) && p.cfg.Pkg.Metadata.YOLO { + state := &types.ZarfState{ + Distro: "YOLO", + } + return state, nil + } + if err != nil && !p.cfg.Pkg.Metadata.YOLO { + return nil, err + } + if p.cfg.Pkg.Metadata.YOLO && state.Distro != "YOLO" { + message.Warn("This package is in YOLO mode, but the cluster was already initialized with 'zarf init'. " + + "This may cause issues if the package does not exclude any charts or manifests from the Zarf Agent using " + + "the pod or namespace label `zarf.dev/agent: ignore'.") + } + return state, nil +} + func (p *Packager) resetRegistryHPA(ctx context.Context) { if p.isConnectedToCluster() && p.hpaModified { if err := p.cluster.EnableRegHPAScaleDown(ctx); err != nil { @@ -143,6 +173,11 @@ func (p *Packager) deployComponents(ctx context.Context) (deployedComponents []t p.generation = 1 // If this is the first deployment, set the generation to 1 } + state, err := p.getZarfState(ctx) + if err != nil { + return nil, err + } + // Process all the components we are deploying for _, component := range p.cfg.Pkg.Components { deployedComponent := types.DeployedComponent{ @@ -186,9 +221,9 @@ func (p *Packager) deployComponents(ctx context.Context) (deployedComponents []t var charts []types.InstalledChart var deployErr error if p.cfg.Pkg.IsInitConfig() { - charts, deployErr = p.deployInitComponent(ctx, component) + charts, deployErr = p.deployInitComponent(ctx, state, component) } else { - charts, deployErr = p.deployComponent(ctx, component, false /* keep img checksum */, false /* always push images */) + charts, deployErr = p.deployComponent(ctx, state, component, false, false) } onDeploy := component.Actions.OnDeploy @@ -231,7 +266,7 @@ func (p *Packager) deployComponents(ctx context.Context) (deployedComponents []t return deployedComponents, nil } -func (p *Packager) deployInitComponent(ctx context.Context, component types.ZarfComponent) (charts []types.InstalledChart, err error) { +func (p *Packager) deployInitComponent(ctx context.Context, state *types.ZarfState, component types.ZarfComponent) (charts []types.InstalledChart, err error) { hasExternalRegistry := p.cfg.InitOpts.RegistryInfo.Address != "" isSeedRegistry := component.Name == "zarf-seed-registry" isRegistry := component.Name == "zarf-registry" @@ -243,14 +278,6 @@ func (p *Packager) deployInitComponent(ctx context.Context, component types.Zarf p.cfg.InitOpts.ApplianceMode = true } - // Always init the state before the first component that requires the cluster (on most deployments, the zarf-seed-registry) - if component.RequiresCluster() && p.state == nil { - err = p.cluster.InitZarfState(ctx, p.cfg.InitOpts) - if err != nil { - return nil, fmt.Errorf("unable to initialize Zarf state: %w", err) - } - } - if hasExternalRegistry && (isSeedRegistry || isInjector || isRegistry) { message.Notef("Not deploying the component (%s) since external registry information was provided during `zarf init`", component.Name) return nil, nil @@ -269,7 +296,7 @@ func (p *Packager) deployInitComponent(ctx context.Context, component types.Zarf } } - charts, err = p.deployComponent(ctx, component, isAgent /* skip img checksum if isAgent */, isSeedRegistry /* skip image push if isSeedRegistry */) + charts, err = p.deployComponent(ctx, state, component, isAgent, isSeedRegistry) if err != nil { return nil, err } @@ -285,7 +312,7 @@ func (p *Packager) deployInitComponent(ctx context.Context, component types.Zarf } // Deploy a Zarf Component. -func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComponent, noImgChecksum bool, noImgPush bool) (charts []types.InstalledChart, err error) { +func (p *Packager) deployComponent(ctx context.Context, state *types.ZarfState, component types.ZarfComponent, noImgChecksum bool, noImgPush bool) (charts []types.InstalledChart, err error) { // Toggles for general deploy operations componentPath := p.layout.Components.Dirs[component.Name] @@ -301,16 +328,8 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp onDeploy := component.Actions.OnDeploy if component.RequiresCluster() { - // Setup the state in the config - if p.state == nil { - err = p.setupState(ctx) - if err != nil { - return charts, err - } - } - // Disable the registry HPA scale down if we are deploying images and it is not already disabled - if hasImages && !p.hpaModified && p.state.RegistryInfo.IsInternal() { + if hasImages && !p.hpaModified && state.RegistryInfo.IsInternal() { if err := p.cluster.DisableRegHPAScaleDown(ctx); err != nil { message.Debugf("unable to disable the registry HPA scale down: %s", err.Error()) } else { @@ -319,7 +338,7 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp } } - err = p.populateComponentAndStateTemplates(component.Name) + err = p.populateComponentAndStateTemplates(component.Name, state.RegistryInfo, state.GitServer, state.AgentTLS, state.StorageClass) if err != nil { return charts, err } @@ -335,13 +354,13 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp } if hasImages { - if err := p.pushImagesToRegistry(ctx, component.Images, noImgChecksum); err != nil { + if err := p.pushImagesToRegistry(ctx, state.RegistryInfo, component.Images, noImgChecksum); err != nil { return charts, fmt.Errorf("unable to push images to the registry: %w", err) } } if hasRepos { - if err = p.pushReposToRepository(ctx, componentPath.Repos, component.Repos); err != nil { + if err = p.pushReposToRepository(ctx, state.GitServer, componentPath.Repos, component.Repos); err != nil { return charts, fmt.Errorf("unable to push the repos to the repository: %w", err) } } @@ -354,7 +373,7 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp } if hasCharts || hasManifests { - if charts, err = p.installChartAndManifests(ctx, componentPath, component); err != nil { + if charts, err = p.installChartAndManifests(ctx, state, componentPath, component); err != nil { return charts, err } } @@ -449,62 +468,8 @@ func (p *Packager) processComponentFiles(component types.ZarfComponent, pkgLocat return nil } -// setupState fetches the current ZarfState from the k8s cluster and sets the packager to use it -func (p *Packager) setupState(ctx context.Context) (err error) { - // If we are touching K8s, make sure we can talk to it once per deployment - spinner := message.NewProgressSpinner("Loading the Zarf State from the Kubernetes cluster") - defer spinner.Stop() - - state, err := p.cluster.LoadZarfState(ctx) - // We ignore the error if in YOLO mode because Zarf should not be initiated. - if err != nil && !p.cfg.Pkg.Metadata.YOLO { - return err - } - // Only ignore state load error in yolo mode when secret could not be found. - if err != nil && !kerrors.IsNotFound(err) && p.cfg.Pkg.Metadata.YOLO { - return err - } - if state == nil && p.cfg.Pkg.Metadata.YOLO { - state = &types.ZarfState{} - // YOLO mode, so minimal state needed - state.Distro = "YOLO" - - // Try to create the zarf namespace - spinner.Updatef("Creating the Zarf namespace") - zarfNamespace := cluster.NewZarfManagedNamespace(cluster.ZarfNamespaceName) - err := func() error { - _, err := p.cluster.Clientset.CoreV1().Namespaces().Create(ctx, zarfNamespace, metav1.CreateOptions{}) - if err != nil && !kerrors.IsAlreadyExists(err) { - return err - } - if err == nil { - return nil - } - _, err = p.cluster.Clientset.CoreV1().Namespaces().Update(ctx, zarfNamespace, metav1.UpdateOptions{}) - if err != nil { - return err - } - return nil - }() - if err != nil { - return fmt.Errorf("unable to create the Zarf namespace: %w", err) - } - } - - if p.cfg.Pkg.Metadata.YOLO && state.Distro != "YOLO" { - message.Warn("This package is in YOLO mode, but the cluster was already initialized with 'zarf init'. " + - "This may cause issues if the package does not exclude any charts or manifests from the Zarf Agent using " + - "the pod or namespace label `zarf.dev/agent: ignore'.") - } - - p.state = state - - spinner.Success() - return nil -} - -func (p *Packager) populateComponentAndStateTemplates(componentName string) error { - applicationTemplates, err := template.GetZarfTemplates(componentName, p.state) +func (p *Packager) populateComponentAndStateTemplates(componentName string, regInfo types.RegistryInfo, gitInfo types.GitServerInfo, agentTLS types.GeneratedPKI, storageClass string) error { + applicationTemplates, err := template.GetZarfTemplates(componentName, regInfo, gitInfo, agentTLS, storageClass) if err != nil { return err } @@ -518,7 +483,7 @@ func (p *Packager) populatePackageVariableConfig() error { } // Push all of the components images to the configured container registry. -func (p *Packager) pushImagesToRegistry(ctx context.Context, componentImages []string, noImgChecksum bool) error { +func (p *Packager) pushImagesToRegistry(ctx context.Context, regInfo types.RegistryInfo, componentImages []string, noImgChecksum bool) error { var combinedImageList []transform.Image for _, src := range componentImages { ref, err := transform.ParseImageRef(src) @@ -533,7 +498,7 @@ func (p *Packager) pushImagesToRegistry(ctx context.Context, componentImages []s pushCfg := images.PushConfig{ SourceDirectory: p.layout.Images.Base, ImageList: imageList, - RegInfo: p.state.RegistryInfo, + RegInfo: regInfo, NoChecksum: noImgChecksum, Arch: p.cfg.Pkg.Build.Architecture, Retries: p.cfg.PkgOpts.Retries, @@ -543,7 +508,7 @@ func (p *Packager) pushImagesToRegistry(ctx context.Context, componentImages []s } // Push all of the components git repos to the configured git server. -func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, repos []string) error { +func (p *Packager) pushReposToRepository(ctx context.Context, gitInfo types.GitServerInfo, reposPath string, repos []string) error { for _, repoURL := range repos { repository, err := git.Open(reposPath, repoURL) if err != nil { @@ -552,7 +517,7 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, // Create an anonymous function to push the repo to the Zarf git server tryPush := func() error { - namespace, name, port, err := serviceInfoFromServiceURL(p.state.GitServer.Address) + namespace, name, port, err := serviceInfoFromServiceURL(gitInfo.Address) // If this is a service (svcInfo is not nil), create a port-forward tunnel to that resource // TODO: Find a better way as ignoring the error is not a good solution to decide to port forward. @@ -574,12 +539,12 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, return err } defer tunnel.Close() - giteaClient, err := gitea.NewClient(tunnel.HTTPEndpoint(), p.state.GitServer.PushUsername, p.state.GitServer.PushPassword) + giteaClient, err := gitea.NewClient(tunnel.HTTPEndpoint(), gitInfo.PushUsername, gitInfo.PushPassword) if err != nil { return err } return tunnel.Wrap(func() error { - err = repository.Push(ctx, tunnel.HTTPEndpoint(), p.state.GitServer.PushUsername, p.state.GitServer.PushPassword) + err = repository.Push(ctx, tunnel.HTTPEndpoint(), gitInfo.PushUsername, gitInfo.PushPassword) if err != nil { return err } @@ -588,7 +553,7 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, if err != nil { return err } - err = giteaClient.AddReadOnlyUserToRepository(ctx, repoName, p.state.GitServer.PullUsername) + err = giteaClient.AddReadOnlyUserToRepository(ctx, repoName, gitInfo.PullUsername) if err != nil { return fmt.Errorf("unable to add the read only user to the repo %s: %w", repoName, err) } @@ -596,7 +561,7 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, }) } - err = repository.Push(ctx, p.state.GitServer.Address, p.state.GitServer.PushUsername, p.state.GitServer.PushPassword) + err = repository.Push(ctx, gitInfo.Address, gitInfo.PushUsername, gitInfo.PushPassword) if err != nil { return err } @@ -639,7 +604,7 @@ func (p *Packager) generateValuesOverrides(chart types.ZarfChart, componentName } // Install all Helm charts and raw k8s manifests into the k8s cluster. -func (p *Packager) installChartAndManifests(ctx context.Context, componentPaths *layout.ComponentPaths, component types.ZarfComponent) (installedCharts []types.InstalledChart, err error) { +func (p *Packager) installChartAndManifests(ctx context.Context, state *types.ZarfState, componentPaths *layout.ComponentPaths, component types.ZarfComponent) (installedCharts []types.InstalledChart, err error) { for _, chart := range component.Charts { // Do not wait for the chart to be ready if data injections are present. if len(component.DataInjections) > 0 { @@ -668,7 +633,7 @@ func (p *Packager) installChartAndManifests(ctx context.Context, componentPaths helm.WithDeployInfo( p.cfg, p.variableConfig, - p.state, + state, p.cluster, valuesOverrides, p.cfg.DeployOpts.Timeout, @@ -717,7 +682,7 @@ func (p *Packager) installChartAndManifests(ctx context.Context, componentPaths helm.WithDeployInfo( p.cfg, p.variableConfig, - p.state, + state, p.cluster, nil, p.cfg.DeployOpts.Timeout, diff --git a/src/pkg/packager/mirror.go b/src/pkg/packager/mirror.go index 9cafe38f58..1a13c6a277 100644 --- a/src/pkg/packager/mirror.go +++ b/src/pkg/packager/mirror.go @@ -13,7 +13,6 @@ import ( "github.com/zarf-dev/zarf/src/config" "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/pkg/packager/filters" - "github.com/zarf-dev/zarf/src/types" ) // Mirror pulls resources from a package (images, git repositories, etc) and pushes them to remotes in the air gap without deploying them @@ -40,40 +39,24 @@ func (p *Packager) Mirror(ctx context.Context) error { return fmt.Errorf("mirror cancelled") } - p.state = &types.ZarfState{ - RegistryInfo: p.cfg.InitOpts.RegistryInfo, - GitServer: p.cfg.InitOpts.GitServer, - } - for _, component := range p.cfg.Pkg.Components { - if err := p.mirrorComponent(ctx, component); err != nil { - return err - } - } - return nil -} + componentPaths := p.layout.Components.Dirs[component.Name] -// mirrorComponent mirrors a Zarf Component. -func (p *Packager) mirrorComponent(ctx context.Context, component types.ZarfComponent) error { - componentPaths := p.layout.Components.Dirs[component.Name] + // All components now require a name + message.HeaderInfof("📦 %s COMPONENT", strings.ToUpper(component.Name)) - // All components now require a name - message.HeaderInfof("📦 %s COMPONENT", strings.ToUpper(component.Name)) - - hasImages := len(component.Images) > 0 - hasRepos := len(component.Repos) > 0 - - if hasImages { - if err := p.pushImagesToRegistry(ctx, component.Images, p.cfg.MirrorOpts.NoImgChecksum); err != nil { - return fmt.Errorf("unable to push images to the registry: %w", err) + if len(component.Images) > 0 { + err := p.pushImagesToRegistry(ctx, p.cfg.InitOpts.RegistryInfo, component.Images, p.cfg.MirrorOpts.NoImgChecksum) + if err != nil { + return fmt.Errorf("unable to push images to the registry: %w", err) + } } - } - - if hasRepos { - if err := p.pushReposToRepository(ctx, componentPaths.Repos, component.Repos); err != nil { - return fmt.Errorf("unable to push the repos to the repository: %w", err) + if len(component.Repos) > 0 { + err := p.pushReposToRepository(ctx, p.cfg.InitOpts.GitServer, componentPaths.Repos, component.Repos) + if err != nil { + return fmt.Errorf("unable to push the repos to the repository: %w", err) + } } } - return nil } diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go index a52cc9c0f4..ad809d679a 100644 --- a/src/pkg/packager/prepare.go +++ b/src/pkg/packager/prepare.go @@ -109,13 +109,6 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, if err != nil { return nil, err } - artifactServer := types.ArtifactServerInfo{} - artifactServer.FillInEmptyValues() - p.state = &types.ZarfState{ - RegistryInfo: registryInfo, - GitServer: gitServer, - ArtifactServer: artifactServer, - } for _, component := range p.cfg.Pkg.Components { if len(component.Charts)+len(component.Manifests)+len(component.Repos) < 1 { @@ -156,7 +149,7 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, if err != nil { return nil, err } - err = p.populateComponentAndStateTemplates(component.Name) + err = p.populateComponentAndStateTemplates(component.Name, registryInfo, gitServer, types.GeneratedPKI{}, "") if err != nil { return nil, err } diff --git a/src/pkg/packager/remove.go b/src/pkg/packager/remove.go index 59583cee28..30ad5bc82d 100644 --- a/src/pkg/packager/remove.go +++ b/src/pkg/packager/remove.go @@ -12,12 +12,13 @@ import ( "runtime" "slices" - "github.com/defenseunicorns/pkg/helpers/v2" "helm.sh/helm/v3/pkg/storage/driver" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/defenseunicorns/pkg/helpers/v2" + "github.com/zarf-dev/zarf/src/config" "github.com/zarf-dev/zarf/src/internal/packager/helm" "github.com/zarf-dev/zarf/src/pkg/cluster" @@ -182,7 +183,7 @@ func (p *Packager) removeComponent(ctx context.Context, deployedPackage *types.D for _, chart := range helpers.Reverse(deployedComponent.InstalledCharts) { spinner.Updatef("Uninstalling chart '%s' from the '%s' component", chart.ChartName, deployedComponent.Name) - helmCfg := helm.NewClusterOnly(p.cfg, p.variableConfig, p.state, p.cluster) + helmCfg := helm.NewClusterOnly(p.cfg, p.variableConfig, nil, p.cluster) if err := helmCfg.RemoveChart(chart.Namespace, chart.ChartName, spinner); err != nil { if !errors.Is(err, driver.ErrReleaseNotFound) { onFailure()