Skip to content

Commit

Permalink
helm: Add support for remote chart version
Browse files Browse the repository at this point in the history
Currently, the cilium charts are embedded inside cilium cli binary,
which will require a new cilium/charts bump in go.mod and then a new
release for cilium-cli. It's making sense to do so if some other code
changes are required to make installation working for new chart version,
but most of the time, only go.mod upgrade is required.

This commit is to add the capability to install new chart version without
the need of releasing or installing new cilium-cli. The new chart will
be downloaded and stored in user cache dir.

Signed-off-by: Tam Mach <[email protected]>
  • Loading branch information
sayboras authored and tklauser committed Sep 19, 2022
1 parent 29981e6 commit 7fb8e1f
Showing 1 changed file with 86 additions and 10 deletions.
96 changes: 86 additions & 10 deletions internal/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ package helm
import (
"bytes"
"context"
"errors"
"fmt"
"io/fs"
"os"
"path"
"regexp"
"sort"
"strings"
Expand All @@ -30,6 +34,8 @@ import (
corev1 "k8s.io/api/core/v1"
)

const ciliumChart = "https://helm.cilium.io"

var settings = cli.New()

// State contains Helm state for the current Cilium installation. Cilium CLI retrieves this
Expand Down Expand Up @@ -186,7 +192,7 @@ func newClient(namespace, k8sVersion string) (*action.Install, error) {
func newChartFromEmbeddedFile(ciliumVersion semver2.Version) (*chart.Chart, error) {
helmTgz, err := helm.HelmFS.ReadFile(fmt.Sprintf("cilium-%s.tgz", ciliumVersion))
if err != nil {
return nil, fmt.Errorf("cilium version not found: %s", err)
return nil, fmt.Errorf("cilium version not found: %w", err)
}

// Check chart dependencies to make sure all are present in /charts
Expand All @@ -197,6 +203,55 @@ func newChartFromDirectory(directory string) (*chart.Chart, error) {
return loader.LoadDir(directory)
}

// newChartFromRemoteWithCache fetches the chart from remote repository, the chart file
// is then stored in the local cache directory for future usage.
func newChartFromRemoteWithCache(ciliumVersion semver2.Version) (*chart.Chart, error) {
cacheDir, err := ciliumCacheDir()
if err != nil {
return nil, err
}

file := path.Join(cacheDir, fmt.Sprintf("cilium-%s.tgz", ciliumVersion))
if _, err = os.Stat(file); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return nil, err
}

// Download the chart from remote repository
pull := action.NewPullWithOpts(action.WithConfig(new(action.Configuration)))
pull.Settings = settings
pull.RepoURL = ciliumChart
pull.Version = ciliumVersion.String()
pull.DestDir = cacheDir

if _, err = pull.Run("cilium"); err != nil {
return nil, err
}
}

f, err := os.Open(file)
if err != nil {
return nil, err
}
defer f.Close()
return loader.LoadArchive(f)
}

func ciliumCacheDir() (string, error) {
cacheDir, err := os.UserCacheDir()
if err != nil {
return "", err
}

res := path.Join(cacheDir, "cilium-cli")
err = os.MkdirAll(res, 0755)
if err != nil && !os.IsExist(err) {
return "", err
}

return res, nil
}

// GenManifests returns the generated manifests in a map that maps the manifest
// name to its contents.
func GenManifests(
Expand All @@ -218,7 +273,13 @@ func GenManifests(
} else {
helmChart, err = newChartFromEmbeddedFile(ciliumVer)
if err != nil {
return nil, err
if !errors.Is(err, fs.ErrNotExist) {
return nil, err
}
helmChart, err = newChartFromRemoteWithCache(ciliumVer)
if err != nil {
return nil, err
}
}
}

Expand Down Expand Up @@ -328,14 +389,7 @@ func ListVersions() ([]string, error) {
func ResolveHelmChartVersion(versionFlag, chartDirectoryFlag string) (semver2.Version, error) {
if chartDirectoryFlag == "" {
// If --chart-directory flag is not specified, use the version specified with --version flag.
version, err := utils.ParseCiliumVersion(versionFlag)
if err != nil {
return semver2.Version{}, err
}
if _, err = newChartFromEmbeddedFile(version); err != nil {
return semver2.Version{}, err
}
return version, nil
return resolveChartVersion(versionFlag)
}

// Get the chart version from the local Helm chart specified with --chart-directory flag.
Expand All @@ -345,3 +399,25 @@ func ResolveHelmChartVersion(versionFlag, chartDirectoryFlag string) (semver2.Ve
}
return versioncheck.MustVersion(localChart.Metadata.Version), nil
}

func resolveChartVersion(versionFlag string) (semver2.Version, error) {
version, err := utils.ParseCiliumVersion(versionFlag)
if err != nil {
return semver2.Version{}, err
}

_, err = newChartFromEmbeddedFile(version)
if err == nil {
return version, nil
}

if !errors.Is(err, fs.ErrNotExist) {
return semver2.Version{}, err
}

_, err = newChartFromRemoteWithCache(version)
if err != nil {
return semver2.Version{}, err
}
return version, nil
}

0 comments on commit 7fb8e1f

Please sign in to comment.