Skip to content

Commit

Permalink
Add support for Helm3 OCI registries
Browse files Browse the repository at this point in the history
Signed-off-by: Mathias Åhsberg <[email protected]>
  • Loading branch information
mathias-ahsberg-resurs committed Feb 17, 2022
1 parent 456667d commit 5c4069f
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 19 deletions.
1 change: 1 addition & 0 deletions apis/generate.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build generate
// +build generate

/*
Expand Down
94 changes: 75 additions & 19 deletions pkg/clients/helm/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package helm

import (
"fmt"
"helm.sh/helm/v3/pkg/registry"
"io/ioutil"
"net/url"
"os"
Expand All @@ -32,6 +31,7 @@ import (
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/registry"
"helm.sh/helm/v3/pkg/release"
"k8s.io/client-go/rest"
ktype "sigs.k8s.io/kustomize/api/types"
Expand All @@ -51,6 +51,8 @@ const (
errFailedToLoadChart = "failed to load chart"
errUnexpectedDirContentTmpl = "expected 1 .tgz chart file, got [%s]"
errFailedToParseURL = "failed to parse URL"
errFailedToLogin = "failed to login to registry"
errUnexpectedOCIUrlTmpl = "url not prefixed with oci://, got [%s]"
)

// Client is the interface to interact with Helm
Expand Down Expand Up @@ -194,29 +196,29 @@ func (hc *client) pullChart(spec *v1beta1.ChartSpec, creds *RepoCreds, chartDir

chartRef := spec.URL
if spec.URL == "" {
chartRef = spec.Name

pc.RepoURL = spec.Repository
if registry.IsOCI(spec.Repository) {
chartRef = strings.Join([]string{strings.TrimSuffix(spec.Repository, "/"), spec.Name}, "/")
} else {
chartRef = spec.Name
pc.RepoURL = spec.Repository
}
pc.Version = spec.Version
} else if registry.IsOCI(spec.URL) {
ociURL, version, err := resolveOCIChartVersion(spec.URL)
if err != nil {
return err
}
pc.Version = version
chartRef = ociURL.String()
}
pc.Username = creds.Username
pc.Password = creds.Password

pc.DestDir = chartDir

// TODO check if login is required
if registry.IsOCI(spec.Repository) {
parsedUrl, err := url.Parse(spec.Repository)
if err != nil {
return errors.Wrap(err, errFailedToParseURL)
}
var out strings.Builder
// TODO add support for insecure
err = hc.loginClient.Run(&out, parsedUrl.Host, creds.Username, creds.Password, false)
if err != nil {
hc.log.Debug(out.String())
return err
}
err := hc.login(spec, creds, false)
if err != nil {
return err
}

o, err := pc.Run(chartRef)
Expand All @@ -227,15 +229,53 @@ func (hc *client) pullChart(spec *v1beta1.ChartSpec, creds *RepoCreds, chartDir
return nil
}

func (hc *client) login(spec *v1beta1.ChartSpec, creds *RepoCreds, insecure bool) error {
ociURL := spec.URL
if spec.URL == "" {
ociURL = spec.Repository
}
if !registry.IsOCI(ociURL) {
return nil
}
parsedURL, err := url.Parse(ociURL)
if err != nil {
return errors.Wrap(err, errFailedToParseURL)
}
var out strings.Builder
// TODO add support for insecure
err = hc.loginClient.Run(&out, parsedURL.Host, creds.Username, creds.Password, insecure)
hc.log.Debug(out.String())
if err != nil {
return errors.Wrap(err, errFailedToLogin)
}
return nil
}

func (hc *client) PullAndLoadChart(spec *v1beta1.ChartSpec, creds *RepoCreds) (*chart.Chart, error) {
var chartFilePath string
var err error
if spec.URL == "" && spec.Version == "" {
switch {
case spec.URL == "" && spec.Version == "":
chartFilePath, err = hc.pullLatestChartVersion(spec, creds)
if err != nil {
return nil, err
}
} else {
case registry.IsOCI(spec.URL):
u, v, err := resolveOCIChartVersion(spec.URL)
if err != nil {
return nil, err
}

if v == "" {
chartFilePath, err = hc.pullLatestChartVersion(spec, creds)
if err != nil {
return nil, err
}
} else {
filename := fmt.Sprintf("%s-%s.tgz", path.Base(u.Path), v)
chartFilePath = filepath.Join(chartCache, filename)
}
default:
filename := fmt.Sprintf("%s-%s.tgz", spec.Name, spec.Version)
if spec.URL != "" {
u, err := url.Parse(spec.URL)
Expand Down Expand Up @@ -302,3 +342,19 @@ func (hc *client) Uninstall(release string) error {
_, err := hc.uninstallClient.Run(release)
return err
}

func resolveOCIChartVersion(chartURL string) (*url.URL, string, error) {
if !registry.IsOCI(chartURL) {
return nil, "", errors.Errorf(errUnexpectedOCIUrlTmpl, chartURL)
}
ociURL, err := url.Parse(chartURL)
if err != nil {
return nil, "", errors.Wrap(err, errFailedToParseURL)
}
parts := strings.Split(ociURL.Path, ":")
if len(parts) > 1 {
ociURL.Path = parts[0]
return ociURL, parts[1], nil
}
return ociURL, "", nil
}

0 comments on commit 5c4069f

Please sign in to comment.