From 393accf5207271160c553d00fdb1a40889d214c2 Mon Sep 17 00:00:00 2001 From: Ethan Mosbaugh Date: Tue, 15 Oct 2024 11:35:12 -0500 Subject: [PATCH] fix(ci): buildtools handle helm chart app version change (#1241) --- cmd/buildtools/main.go | 3 --- cmd/buildtools/utils.go | 26 +++++++++++++++++++++++--- pkg/helm/client.go | 10 ++++++++++ pkg/helm/images.go | 24 ++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/cmd/buildtools/main.go b/cmd/buildtools/main.go index 79308897d..ef7235e5a 100644 --- a/cmd/buildtools/main.go +++ b/cmd/buildtools/main.go @@ -15,9 +15,6 @@ This script uses the following environment variables: - CHARTS_REGISTRY_SERVER: the registry server to push the chart to (e.g. index.docker.io) - CHARTS_REGISTRY_USER: the username to authenticate with. - CHARTS_REGISTRY_PASS: the password to authenticate with. -- IMAGES_REGISTRY_SERVER: the registry server to push the images to (e.g. index.docker.io) -- IMAGES_REGISTRY_USER: the username to authenticate with. -- IMAGES_REGISTRY_PASS: the password to authenticate with. - CHARTS_DESTINATION: the destination repository to push the chart to (e.g. ttl.sh/embedded-cluster-charts) ` diff --git a/cmd/buildtools/utils.go b/cmd/buildtools/utils.go index 9be1e3d9e..eb11ef943 100644 --- a/cmd/buildtools/utils.go +++ b/cmd/buildtools/utils.go @@ -23,6 +23,7 @@ import ( "github.com/replicatedhq/embedded-cluster/pkg/helm" "github.com/replicatedhq/embedded-cluster/pkg/release" "github.com/sirupsen/logrus" + "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/repo" ) @@ -442,6 +443,16 @@ func GetImagesFromOCIChart(url, name, version string, values map[string]interfac return helm.ExtractImagesFromOCIChart(hcli, url, name, version, values) } +func GetOCIChartMetadata(url, name, version string) (*chart.Metadata, error) { + hcli, err := NewHelm() + if err != nil { + return nil, fmt.Errorf("create helm client: %w", err) + } + defer hcli.Close() + + return helm.GetOCIChartMetadata(hcli, url, name, version) +} + func MirrorChart(repo *repo.Entry, name, ver string) error { hcli, err := NewHelm() if err != nil { @@ -463,6 +474,11 @@ func MirrorChart(repo *repo.Entry, name, ver string) error { logrus.Infof("downloaded %s chart: %s", name, chpath) defer os.Remove(chpath) + srcMeta, err := hcli.GetChartMetadata(chpath) + if err != nil { + return fmt.Errorf("get source chart metadata: %w", err) + } + if val := os.Getenv("CHARTS_REGISTRY_SERVER"); val != "" { logrus.Infof("authenticating with %q", os.Getenv("CHARTS_REGISTRY_SERVER")) if err := hcli.RegistryAuth( @@ -475,13 +491,17 @@ func MirrorChart(repo *repo.Entry, name, ver string) error { } dst := fmt.Sprintf("oci://%s", os.Getenv("CHARTS_DESTINATION")) + chartURL := fmt.Sprintf("%s/%s", dst, name) logrus.Infof("verifying if destination tag already exists") - tmpf, err := hcli.Pull(dst, name, ver) + dstMeta, err := GetOCIChartMetadata(chartURL, name, ver) if err != nil && !strings.HasSuffix(err.Error(), "not found") { return fmt.Errorf("verify tag exists: %w", err) } else if err == nil { - os.Remove(tmpf) - logrus.Warnf("cowardly refusing to override dst (tag %s already exist)", ver) + if srcMeta.AppVersion == dstMeta.AppVersion { + logrus.Infof("cowardly refusing to override dst (tag %s already exist)", ver) + return nil + } + logrus.Warnf("dst tag exists but app versions do not match (src: %s, dst: %s)", srcMeta.AppVersion, dstMeta.AppVersion) return nil } logrus.Infof("destination tag does not exist") diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 07787f81a..0cd0c40cc 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -11,6 +11,7 @@ import ( "github.com/Masterminds/semver/v3" "gopkg.in/yaml.v2" "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/downloader" @@ -214,6 +215,15 @@ func (h *Helm) Push(path, dst string) error { return up.UploadTo(path, dst) } +func (h *Helm) GetChartMetadata(chartPath string) (*chart.Metadata, error) { + chartRequested, err := loader.Load(chartPath) + if err != nil { + return nil, fmt.Errorf("load chart: %w", err) + } + + return chartRequested.Metadata, nil +} + func (h *Helm) Render(chartName string, chartPath string, vals map[string]interface{}, namespace string) ([][]byte, error) { cfg := &action.Configuration{} diff --git a/pkg/helm/images.go b/pkg/helm/images.go index 69dcb9c2b..26ed9c2b8 100644 --- a/pkg/helm/images.go +++ b/pkg/helm/images.go @@ -2,12 +2,14 @@ package helm import ( "fmt" + "os" "slices" "sort" "github.com/distribution/reference" "github.com/replicatedhq/embedded-cluster/pkg/helpers" "gopkg.in/yaml.v2" + "helm.sh/helm/v3/pkg/chart" ) type reducedResource struct { @@ -39,6 +41,7 @@ func ExtractImagesFromOCIChart(hcli *Helm, url, name, version string, values map if err != nil { return nil, fmt.Errorf("pull oci: %w", err) } + defer os.RemoveAll(chartPath) return ExtractImagesFromLocalChart(hcli, name, chartPath, values) } @@ -48,6 +51,7 @@ func ExtractImagesFromChart(hcli *Helm, repo, name, version string, values map[s if err != nil { return nil, fmt.Errorf("pull: %w", err) } + defer os.RemoveAll(chartPath) return ExtractImagesFromLocalChart(hcli, name, chartPath, values) } @@ -73,6 +77,26 @@ func ExtractImagesFromLocalChart(hcli *Helm, name, path string, values map[strin return images, nil } +func GetOCIChartMetadata(hcli *Helm, url, name, version string) (*chart.Metadata, error) { + chartPath, err := hcli.PullOCI(url, version) + if err != nil { + return nil, fmt.Errorf("pull oci: %w", err) + } + defer os.RemoveAll(chartPath) + + return hcli.GetChartMetadata(chartPath) +} + +func GetChartMetadata(hcli *Helm, repo, name, version string) (*chart.Metadata, error) { + chartPath, err := hcli.Pull(repo, name, version) + if err != nil { + return nil, fmt.Errorf("pull oci: %w", err) + } + defer os.RemoveAll(chartPath) + + return hcli.GetChartMetadata(chartPath) +} + func extractImagesFromK8sManifest(resource []byte) ([]string, error) { images := []string{}