Skip to content

Commit

Permalink
1766 - Git Tag and Chart Version assumed to match (#1892)
Browse files Browse the repository at this point in the history
## Description

What we could do (to keep backwards compat in tact and address
#1766) is see if there is
an @ ref on the git URL and if there is, leave it on there, and if not
append the @tag as we do today. Dedup some code in
src/pkg/packager/prepare.go, and src/pkg/packager/create.go.

## Related Issue

Fixes #1766
<!-- or -->
Relates to 

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Other (security config, docs update, etc)

## Checklist before merging

- [x] Test, docs, adr added or updated as needed
- [x] [Contributor Guide
Steps](https://github.com/defenseunicorns/zarf/blob/main/CONTRIBUTING.md#developer-workflow)
followed

---------

Signed-off-by: Case Wylie <cmwylie19@defenseunicorns.com>
Signed-off-by: razzle <harry@razzle.cloud>
Co-authored-by: razzle <harry@razzle.cloud>
Co-authored-by: Wayne Starr <Racer159@users.noreply.github.com>
Co-authored-by: Jon <jonsmith04@hotmail.com>
  • Loading branch information
4 people authored Jul 11, 2023
1 parent f80b4fe commit 12bbda8
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 97 deletions.
6 changes: 4 additions & 2 deletions src/extensions/bigbang/bigbang.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,14 @@ func Run(YOLO bool, tmpPaths types.ComponentPaths, c types.ZarfComponent) (types
}
}

bbRepo := fmt.Sprintf("%s@%s", cfg.Repo, cfg.Version)

// Configure helm to pull down the Big Bang chart.
helmCfg := helm.Helm{
Chart: types.ZarfChart{
Name: bb,
Namespace: bb,
URL: cfg.Repo,
URL: bbRepo,
Version: cfg.Version,
ValuesFiles: cfg.ValuesFiles,
GitPath: "./chart",
Expand Down Expand Up @@ -494,7 +496,7 @@ func findImagesforBBChartRepo(repo string, values chartutil.Values) (images []st

chart := types.ZarfChart{
Name: repo,
URL: matches[0],
URL: repo,
Version: matches[1],
GitPath: "chart",
}
Expand Down
2 changes: 1 addition & 1 deletion src/internal/agent/hooks/flux.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func mutateGitRepo(r *v1.AdmissionRequest) (result *operations.Result, err error
// Mutate the git URL if necessary
if isCreate || (isUpdate && !isPatched) {
// Mutate the git URL so that the hostname matches the hostname in the Zarf state
transformedURL, err := transform.GitTransformURL(zarfState.GitServer.Address, patchedURL, zarfState.GitServer.PushUsername)
transformedURL, err := transform.GitURL(zarfState.GitServer.Address, patchedURL, zarfState.GitServer.PushUsername)
if err != nil {
message.Warnf("Unable to transform the git url, using the original url we have: %s", patchedURL)
}
Expand Down
2 changes: 1 addition & 1 deletion src/internal/agent/http/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func proxyRequestTransform(r *http.Request) error {
} else {
switch {
case isGitUserAgent(r.UserAgent()):
targetURL, err = transform.GitTransformURL(zarfState.GitServer.Address, getTLSScheme(r.TLS)+r.Host+r.URL.String(), zarfState.GitServer.PushUsername)
targetURL, err = transform.GitURL(zarfState.GitServer.Address, getTLSScheme(r.TLS)+r.Host+r.URL.String(), zarfState.GitServer.PushUsername)
case isPipUserAgent(r.UserAgent()):
targetURL, err = transform.PipTransformURL(zarfState.ArtifactServer.Address, getTLSScheme(r.TLS)+r.Host+r.URL.String())
case isNpmUserAgent(r.UserAgent()):
Expand Down
4 changes: 2 additions & 2 deletions src/internal/packager/git/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (g *Git) Pull(gitURL, targetFolder string, shallow bool) error {
g.Spinner.Updatef("Processing git repo %s", gitURL)

// Split the remote url and the zarf reference
gitURLNoRef, refPlain, err := transform.GitTransformURLSplitRef(gitURL)
gitURLNoRef, refPlain, err := transform.GitURLSplitRef(gitURL)
if err != nil {
return err
}
Expand All @@ -51,7 +51,7 @@ func (g *Git) Pull(gitURL, targetFolder string, shallow bool) error {
}

// Construct a path unique to this git repo
repoFolder, err := transform.GitTransformURLtoFolderName(gitURL)
repoFolder, err := transform.GitURLtoFolderName(gitURL)
if err != nil {
return err
}
Expand Down
8 changes: 4 additions & 4 deletions src/internal/packager/git/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (g *Git) PushRepo(srcURL, targetFolder string) error {
defer spinner.Stop()

// Setup git paths, including a unique name for the repo based on the hash of the git URL to avoid conflicts.
repoFolder, err := transform.GitTransformURLtoFolderName(srcURL)
repoFolder, err := transform.GitURLtoFolderName(srcURL)
if err != nil {
return fmt.Errorf("unable to parse git url (%s): %w", srcURL, err)
}
Expand All @@ -34,7 +34,7 @@ func (g *Git) PushRepo(srcURL, targetFolder string) error {
// Check that this package is using the new repo format (if not fallback to the format from <= 0.24.x)
_, err = os.Stat(repoPath)
if os.IsNotExist(err) {
repoFolder, err = transform.GitTransformURLtoRepoName(srcURL)
repoFolder, err = transform.GitURLtoRepoName(srcURL)
if err != nil {
return fmt.Errorf("unable to parse git url (%s): %w", srcURL, err)
}
Expand Down Expand Up @@ -63,7 +63,7 @@ func (g *Git) PushRepo(srcURL, targetFolder string) error {
return err
}
remoteURL := remote.Config().URLs[0]
repoName, err := transform.GitTransformURLtoRepoName(remoteURL)
repoName, err := transform.GitURLtoRepoName(remoteURL)
if err != nil {
message.Warnf("Unable to add the read-only user to the repo: %s\n", repoName)
return err
Expand Down Expand Up @@ -94,7 +94,7 @@ func (g *Git) prepRepoForPush() (*git.Repository, error) {
}

remoteURL := remote.Config().URLs[0]
targetURL, err := transform.GitTransformURL(g.Server.Address, remoteURL, g.Server.PushUsername)
targetURL, err := transform.GitURL(g.Server.Address, remoteURL, g.Server.PushUsername)
if err != nil {
return nil, fmt.Errorf("unable to transform the git url: %w", err)
}
Expand Down
2 changes: 2 additions & 0 deletions src/internal/packager/helm/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/defenseunicorns/zarf/src/types"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/cli"
)

// Helm is a config object for working with helm charts.
Expand All @@ -25,6 +26,7 @@ type Helm struct {
Cluster *cluster.Cluster
Cfg *types.PackagerConfig
KubeVersion string
Settings *cli.EnvSettings

actionConfig *action.Configuration
}
Expand Down
107 changes: 76 additions & 31 deletions src/internal/packager/helm/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/internal/packager/git"
"github.com/defenseunicorns/zarf/src/pkg/message"
"github.com/defenseunicorns/zarf/src/pkg/transform"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/registry"
Expand All @@ -22,65 +24,82 @@ import (
"helm.sh/helm/v3/pkg/repo"
)

// PackageChart creates a chart archive from a path to a chart on the host os and builds chart dependencies
func (h *Helm) PackageChart(destination string) error {
if len(h.Chart.URL) > 0 {
url, refPlain, err := transform.GitURLSplitRef(h.Chart.URL)
// check if the chart is a git url with a ref (if an error is returned url will be empty)
isGitURL := strings.HasSuffix(url, ".git")
if err != nil {
message.Debugf("unable to parse the url, continuing with %s", h.Chart.URL)
}

if isGitURL {
// if it is a git url append chart version as if its a tag
if refPlain == "" {
h.Chart.URL = fmt.Sprintf("%s@%s", h.Chart.URL, h.Chart.Version)
}

_, err = h.PackageChartFromGit(destination)

if err != nil {
return fmt.Errorf("error creating chart archive, unable to pull the chart from git: %s", err.Error())
}
} else {
h.DownloadPublishedChart(destination)
}

} else {
_, err := h.PackageChartFromLocalFiles(destination)
if err != nil {
return fmt.Errorf("error creating chart archive, unable to package the chart: %s", err.Error())
}
}
return nil
}

// PackageChartFromLocalFiles creates a chart archive from a path to a chart on the host os.
func (h *Helm) PackageChartFromLocalFiles(destination string) string {
func (h *Helm) PackageChartFromLocalFiles(destination string) (string, error) {
spinner := message.NewProgressSpinner("Processing helm chart %s:%s from %s", h.Chart.Name, h.Chart.Version, h.Chart.LocalPath)
defer spinner.Stop()

// Validate the chart
_, err := loader.LoadDir(h.Chart.LocalPath)
if err != nil {
spinner.Fatalf(err, "Validation failed for chart from %s (%s)", h.Chart.LocalPath, err.Error())
spinner.Errorf(err, "Validation failed for chart from %s (%s)", h.Chart.LocalPath, err.Error())
return "", err
}

h.buildChartDependencies(spinner)
client := action.NewPackage()

client.Destination = destination
path, err := client.Run(h.Chart.LocalPath, nil)

if err != nil {
spinner.Fatalf(err, "Helm is unable to save the archive and create the package %s", path)
spinner.Errorf(err, "Helm is unable to save the archive and create the package %s", path)
return "", err
}

spinner.Success()

return path
return path, nil
}

// PackageChartFromGit is a special implementation of chart archiving that supports the https://p1.dso.mil/#/products/big-bang/ model.
func (h *Helm) PackageChartFromGit(destination string) (string, error) {
spinner := message.NewProgressSpinner("Processing helm chart %s", h.Chart.Name)
defer spinner.Stop()

client := action.NewPackage()

// Retrieve the repo containing the chart
gitPath, err := h.DownloadChartFromGitToTemp(spinner)
if err != nil {
return "", err
}
defer os.RemoveAll(gitPath)

// Set the directory for the chart
chartPath := filepath.Join(gitPath, h.Chart.GitPath)

// Validate the chart
if _, err := loader.LoadDir(chartPath); err != nil {
spinner.Errorf(err, "Validation failed for chart %s (%s)", h.Chart.Name, err.Error())
return "", err
}

// Tell helm where to save the archive and create the package
client.Destination = destination
name, err := client.Run(chartPath, nil)
if err != nil {
spinner.Errorf(err, "Helm is unable to save the archive and create the package %s", name)
return "", err
}

spinner.Success()

return name, nil
// Set the directory for the chart and package it
h.Chart.LocalPath = filepath.Join(gitPath, h.Chart.GitPath)
return h.PackageChartFromLocalFiles(destination)
}

// DownloadPublishedChart loads a specific chart version from a remote repo.
Expand Down Expand Up @@ -154,14 +173,40 @@ func (h *Helm) DownloadChartFromGitToTemp(spinner *message.Spinner) (string, err
// Create the Git configuration and download the repo
gitCfg := git.NewWithSpinner(h.Cfg.State.GitServer, spinner)

gitRepoWithRef := fmt.Sprintf("%s@%s", h.Chart.URL, h.Chart.Version)

// Download the git repo to a temporary directory
err := gitCfg.DownloadRepoToTemp(gitRepoWithRef)
err := gitCfg.DownloadRepoToTemp(h.Chart.URL)
if err != nil {
spinner.Errorf(err, "Unable to download the git repo %s", gitRepoWithRef)
spinner.Errorf(err, "Unable to download the git repo %s", h.Chart.URL)
return "", err
}

return gitCfg.GitPath, nil
}

// buildChartDependencies builds the helm chart dependencies
func (h *Helm) buildChartDependencies(spinner *message.Spinner) error {
regClient, err := registry.NewClient(registry.ClientOptEnableCache(true))
if err != nil {
spinner.Fatalf(err, "Unable to create a new registry client")
}
h.Settings = cli.New()
man := &downloader.Manager{
Out: os.Stdout,
ChartPath: h.Chart.LocalPath,
Getters: getter.All(h.Settings),
RegistryClient: regClient,

RepositoryConfig: h.Settings.RepositoryConfig,
RepositoryCache: h.Settings.RepositoryCache,
Debug: false,
}
// Verify the chart
man.Verify = downloader.VerifyIfPossible

// Build the deps from the helm chart
err = man.Build()
if e, ok := err.(downloader.ErrRepoNotFound); ok {
return fmt.Errorf("%s. Please add the missing repos via 'helm repo add'", e.Error())
}
return nil
}
7 changes: 4 additions & 3 deletions src/internal/packager/helm/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,14 @@ func (h *Helm) parseChartValues() (map[string]any, error) {
func (h *Helm) createActionConfig(namespace string, spinner *message.Spinner) error {
// Initialize helm SDK
actionConfig := new(action.Configuration)
settings := cli.New()
// Set the setings for the helm SDK
h.Settings = cli.New()

// Set the namespace for helm
settings.SetNamespace(namespace)
h.Settings.SetNamespace(namespace)

// Setup K8s connection
err := actionConfig.Init(settings.RESTClientGetter(), namespace, "", spinner.Updatef)
err := actionConfig.Init(h.Settings.RESTClientGetter(), namespace, "", spinner.Updatef)

// Set the actionConfig is the received Helm pointer
h.actionConfig = actionConfig
Expand Down
20 changes: 5 additions & 15 deletions src/pkg/packager/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -326,8 +325,7 @@ func (p *Packager) addComponent(index int, component types.ZarfComponent, isSkel

// If any helm charts are defined, process them.
for chartIdx, chart := range component.Charts {
re := regexp.MustCompile(`\.git$`)
isGitURL := re.MatchString(chart.URL)

helmCfg := helm.Helm{
Chart: chart,
Cfg: p.cfg,
Expand All @@ -343,18 +341,10 @@ func (p *Packager) addComponent(index int, component types.ZarfComponent, isSkel
}

p.cfg.Pkg.Components[index].Charts[chartIdx].LocalPath = rel
} else if isGitURL {
_, err = helmCfg.PackageChartFromGit(componentPath.Charts)
if err != nil {
return fmt.Errorf("error creating chart archive, unable to pull the chart from git: %s", err.Error())
}
} else if len(chart.URL) > 0 {
helmCfg.DownloadPublishedChart(componentPath.Charts)
} else {
path := helmCfg.PackageChartFromLocalFiles(componentPath.Charts)
zarfFilename := fmt.Sprintf("%s-%s.tgz", chart.Name, chart.Version)
if !strings.HasSuffix(path, zarfFilename) {
return fmt.Errorf("error creating chart archive, user provided chart name and/or version does not match given chart")
err := helmCfg.PackageChart(componentPath.Charts)
if err != nil {
return err
}
}

Expand Down Expand Up @@ -694,7 +684,7 @@ func (p *Packager) removeCopiesFromDifferentialPackage() error {
// Generate a list of all unique repos for this component
for _, repoURL := range component.Repos {
// Split the remote url and the zarf reference
_, refPlain, err := transform.GitTransformURLSplitRef(repoURL)
_, refPlain, err := transform.GitURLSplitRef(repoURL)
if err != nil {
return err
}
Expand Down
18 changes: 5 additions & 13 deletions src/pkg/packager/prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,27 +113,19 @@ func (p *Packager) FindImages(baseDir, repoHelmChartPath string, kubeVersionOver
if len(component.Charts) > 0 {
_ = utils.CreateDirectory(componentPath.Charts, 0700)
_ = utils.CreateDirectory(componentPath.Values, 0700)
re := regexp.MustCompile(`\.git$`)

for _, chart := range component.Charts {
isGitURL := re.MatchString(chart.URL)

helmCfg := helm.Helm{
Chart: chart,
Cfg: p.cfg,
}

helmCfg.Cfg.State = types.ZarfState{}
if isGitURL {
path, err := helmCfg.PackageChartFromGit(componentPath.Charts)
if err != nil {
return fmt.Errorf("unable to download chart from git repo (%s): %w", chart.URL, err)
}
// track the actual chart path
chartOverrides[chart.Name] = path
} else if len(chart.URL) > 0 {
helmCfg.DownloadPublishedChart(componentPath.Charts)
} else {
helmCfg.PackageChartFromLocalFiles(componentPath.Charts)

err := helmCfg.PackageChart(componentPath.Charts)
if err != nil {
return fmt.Errorf("unable to package the chart %s: %s", chart.URL, err.Error())
}

for idx, path := range chart.ValuesFiles {
Expand Down
Loading

0 comments on commit 12bbda8

Please sign in to comment.