Files
helmfile/pkg/exectest/helm.go
T
Indrek Juhkam 608bb0b525 Avoid --skip-refresh on local charts (#541)
All the dependencies get correctly installed when dealing with remote
charts.

If there's a local chart that depends on remote dependencies then those
don't get automatically installed. See #526. They end up with this
error:

```
Error: no cached repository for helm-manager-b6cf96b91af4f01317d185adfbe32610179e5246214be9646a52cb0b86032272 found. (try 'helm repo update'): open /root/.cache/helm/repository/helm-manager-b6cf96b91af4f01317d185adfbe32610179e5246214be9646a52cb0b86032272-index.yaml: no such file or directory
```

One workaround for that would be to add the repositories from the local
charts. Something like this:

```
cd local-chart/ && helm dependency list $dir 2> /dev/null | tail +2 | head -n -1 | awk '{ print "helm repo add " $1 " " $3 }' | while read cmd; do $cmd; done
```

This however is not trivial to parse and implement.

An easier fix which I did here is just to not allow doing
`--skip-refresh` for local repositories.

Fixes #526

Signed-off-by: Indrek Juhkam <indrek@urgas.eu>

Signed-off-by: Indrek Juhkam <indrek@urgas.eu>
Signed-off-by: yxxhero <aiopsclub@163.com>
2022-12-13 13:12:07 +08:00

248 lines
6.3 KiB
Go

package exectest
import (
"errors"
"fmt"
"strings"
"sync"
"github.com/Masterminds/semver/v3"
"helm.sh/helm/v3/pkg/chart"
"github.com/helmfile/helmfile/pkg/helmexec"
)
type ListKey struct {
Filter string
Flags string
}
func (k ListKey) String() string {
return fmt.Sprintf("listkey(filter=%s,flags=%s)", k.Filter, k.Flags)
}
type DiffKey struct {
Name string
Chart string
Flags string
}
type Helm struct {
Charts []string
Repo []string
Releases []Release
Deleted []Release
Linted []Release
Templated []Release
Lists map[ListKey]string
Diffs map[DiffKey]error
Diffed []Release
FailOnUnexpectedDiff bool
FailOnUnexpectedList bool
Version *semver.Version
UpdateDepsCallbacks map[string]func(string) error
DiffMutex *sync.Mutex
ChartsMutex *sync.Mutex
ReleasesMutex *sync.Mutex
Helm3 bool
}
type Release struct {
Name string
Flags []string
}
type Affected struct {
Upgraded []*Release
Deleted []*Release
Failed []*Release
}
func (helm *Helm) UpdateDeps(chart string) error {
if strings.Contains(chart, "error") {
return fmt.Errorf("simulated UpdateDeps failure for chart: %s", chart)
}
helm.Charts = append(helm.Charts, chart)
if helm.UpdateDepsCallbacks != nil {
callback, exists := helm.UpdateDepsCallbacks[chart]
if exists {
if err := callback(chart); err != nil {
return err
}
}
}
return nil
}
func (helm *Helm) BuildDeps(name, chart string, flags ...string) error {
if strings.Contains(chart, "error") {
return errors.New("error")
}
helm.Charts = append(helm.Charts, chart)
return nil
}
func (helm *Helm) SetExtraArgs(args ...string) {
}
func (helm *Helm) SetHelmBinary(bin string) {
}
func (helm *Helm) SetEnableLiveOutput(enableLiveOutput bool) {
}
func (helm *Helm) SetPostRenderer(postRenderer string) {
}
func (helm *Helm) GetPostRenderer() string {
return ""
}
func (helm *Helm) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string, passCredentials string, skipTLSVerify string) error {
helm.Repo = []string{name, repository, cafile, certfile, keyfile, username, password, managed, passCredentials, skipTLSVerify}
return nil
}
func (helm *Helm) UpdateRepo() error {
return nil
}
func (helm *Helm) RegistryLogin(name string, username string, password string) error {
return nil
}
func (helm *Helm) SyncRelease(context helmexec.HelmContext, name, chart string, flags ...string) error {
if strings.Contains(name, "error") {
return errors.New("error")
}
helm.sync(helm.ReleasesMutex, func() {
helm.Releases = append(helm.Releases, Release{Name: name, Flags: flags})
})
helm.sync(helm.ChartsMutex, func() {
helm.Charts = append(helm.Charts, chart)
})
return nil
}
func (helm *Helm) DiffRelease(context helmexec.HelmContext, name, chart string, suppressDiff bool, flags ...string) error {
if helm.DiffMutex != nil {
helm.DiffMutex.Lock()
}
helm.Diffed = append(helm.Diffed, Release{Name: name, Flags: flags})
if helm.DiffMutex != nil {
helm.DiffMutex.Unlock()
}
if helm.Diffs == nil {
return nil
}
key := DiffKey{Name: name, Chart: chart, Flags: strings.Join(flags, "")}
err, ok := helm.Diffs[key]
if !ok && helm.FailOnUnexpectedDiff {
return fmt.Errorf("unexpected diff with key: %v", key)
}
return err
}
func (helm *Helm) ReleaseStatus(context helmexec.HelmContext, release string, flags ...string) error {
if strings.Contains(release, "error") {
return errors.New("error")
}
helm.Releases = append(helm.Releases, Release{Name: release, Flags: flags})
return nil
}
func (helm *Helm) DeleteRelease(context helmexec.HelmContext, name string, flags ...string) error {
if strings.Contains(name, "error") {
return errors.New("error")
}
helm.Deleted = append(helm.Deleted, Release{Name: name, Flags: flags})
return nil
}
func (helm *Helm) List(context helmexec.HelmContext, filter string, flags ...string) (string, error) {
key := ListKey{Filter: filter, Flags: strings.Join(flags, "")}
if helm.Lists == nil {
return "dummy non-empty helm-list output", nil
}
res, ok := helm.Lists[key]
if !ok && helm.FailOnUnexpectedList {
var keys []string
for k := range helm.Lists {
keys = append(keys, k.String())
}
return "", fmt.Errorf("unexpected list key: %v not found in %v", key, strings.Join(keys, ", "))
}
return res, nil
}
func (helm *Helm) DecryptSecret(context helmexec.HelmContext, name string, flags ...string) (string, error) {
return "", nil
}
func (helm *Helm) TestRelease(context helmexec.HelmContext, name string, flags ...string) error {
if strings.Contains(name, "error") {
return errors.New("error")
}
helm.Releases = append(helm.Releases, Release{Name: name, Flags: flags})
return nil
}
func (helm *Helm) Fetch(chart string, flags ...string) error {
return nil
}
func (helm *Helm) Lint(name, chart string, flags ...string) error {
if strings.Contains(name, "error") {
return errors.New("error")
}
helm.Linted = append(helm.Linted, Release{Name: name, Flags: flags})
return nil
}
func (helm *Helm) TemplateRelease(name, chart string, flags ...string) error {
if strings.Contains(name, "error") {
return errors.New("error")
}
helm.Templated = append(helm.Templated, Release{Name: name, Flags: flags})
return nil
}
func (helm *Helm) ChartPull(chart string, path string, flags ...string) error {
return nil
}
func (helm *Helm) ChartExport(chart string, path string, flags ...string) error {
return nil
}
func (helm *Helm) IsHelm3() bool {
if helm.Version == nil {
return helm.Helm3
}
return helm.Version.Major() == 3
}
func (helm *Helm) GetVersion() helmexec.Version {
return helmexec.Version{
Major: int(helm.Version.Major()),
Minor: int(helm.Version.Minor()),
Patch: int(helm.Version.Patch()),
}
}
func (helm *Helm) IsVersionAtLeast(versionStr string) bool {
if helm.Version == nil {
return false
}
ver := semver.MustParse(versionStr)
return helm.Version.Equal(ver) || helm.Version.GreaterThan(ver)
}
func (helm *Helm) sync(m *sync.Mutex, f func()) {
if m != nil {
m.Lock()
defer m.Unlock()
}
f()
}
func (helm *Helm) ShowChart(chartPath string) (chart.Metadata, error) {
switch chartPath {
case "../../foo-bar":
return chart.Metadata{Version: "3.2.0"}, nil
default:
return chart.Metadata{}, errors.New("fake test error")
}
}