Skip to content

Commit

Permalink
feat(helm): add ability for --dry-run to do lookup functions
Browse files Browse the repository at this point in the history
When a helm command is run with the --dry-run flag, it will try to connect to the cluster
if the value is 'server' to be able to render lookup functions.
Closes #8137

Signed-off-by: Tapas Kapadia <tapaskapadia10@gmail.com>
  • Loading branch information
tapaskapadia committed Apr 8, 2023
2 parents 4899e8a + eea2f27 commit 4b7248e
Show file tree
Hide file tree
Showing 116 changed files with 1,546 additions and 1,455 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/build-test.yml
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@3.5.0
with:
go-version: '1.18'
go-version: '1.20'
- name: Install golangci-lint
run: |
curl -sSLO https://github.com/golangci/golangci-lint/releases/download/v$GOLANGCI_LINT_VERSION/golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64.tar.gz
Expand All @@ -26,8 +26,8 @@ jobs:
sudo mv golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64/golangci-lint /usr/local/bin/golangci-lint
rm -rf golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64*
env:
GOLANGCI_LINT_VERSION: '1.46.2'
GOLANGCI_LINT_SHA256: '242cd4f2d6ac0556e315192e8555784d13da5d1874e51304711570769c4f2b9b'
GOLANGCI_LINT_VERSION: '1.51.2'
GOLANGCI_LINT_SHA256: '4de479eb9d9bc29da51aec1834e7c255b333723d38dbd56781c68e5dddc6a90b'
- name: Test style
run: make test-style
- name: Run unit tests
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@3.5.0
with:
go-version: '1.18'
go-version: '1.20'

- name: Run unit tests
run: make test-coverage
Expand Down Expand Up @@ -54,7 +54,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@3.5.0
with:
go-version: '1.18'
go-version: '1.20'

- name: Run unit tests
run: make test-coverage
Expand Down
5 changes: 2 additions & 3 deletions cmd/helm/create_test.go
Expand Up @@ -18,7 +18,6 @@ package main

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -77,7 +76,7 @@ func TestCreateStarterCmd(t *testing.T) {
t.Logf("Created %s", dest)
}
tplpath := filepath.Join(starterchart, "starterchart", "templates", "foo.tpl")
if err := ioutil.WriteFile(tplpath, []byte("test"), 0644); err != nil {
if err := os.WriteFile(tplpath, []byte("test"), 0644); err != nil {
t.Fatalf("Could not write template: %s", err)
}

Expand Down Expand Up @@ -140,7 +139,7 @@ func TestCreateStarterAbsoluteCmd(t *testing.T) {
t.Logf("Created %s", dest)
}
tplpath := filepath.Join(starterchart, "starterchart", "templates", "foo.tpl")
if err := ioutil.WriteFile(tplpath, []byte("test"), 0644); err != nil {
if err := os.WriteFile(tplpath, []byte("test"), 0644); err != nil {
t.Fatalf("Could not write template: %s", err)
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/helm/helm.go
Expand Up @@ -18,7 +18,7 @@ package main // import "helm.sh/helm/v3/cmd/helm"

import (
"fmt"
"io/ioutil"
"io"
"log"
"os"
"strings"
Expand Down Expand Up @@ -106,10 +106,10 @@ func loadReleasesInMemory(actionConfig *action.Configuration) {
return
}

actionConfig.KubeClient = &kubefake.PrintingKubeClient{Out: ioutil.Discard}
actionConfig.KubeClient = &kubefake.PrintingKubeClient{Out: io.Discard}

for _, path := range filePaths {
b, err := ioutil.ReadFile(path)
b, err := os.ReadFile(path)
if err != nil {
log.Fatal("Unable to read memory driver data", err)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/helm/helm_test.go
Expand Up @@ -18,7 +18,7 @@ package main

import (
"bytes"
"io/ioutil"
"io"
"os"
"os/exec"
"runtime"
Expand Down Expand Up @@ -92,7 +92,7 @@ func executeActionCommandStdinC(store *storage.Storage, in *os.File, cmd string)

actionConfig := &action.Configuration{
Releases: store,
KubeClient: &kubefake.PrintingKubeClient{Out: ioutil.Discard},
KubeClient: &kubefake.PrintingKubeClient{Out: io.Discard},
Capabilities: chartutil.DefaultCapabilities,
Log: func(format string, v ...interface{}) {},
}
Expand Down
11 changes: 10 additions & 1 deletion cmd/helm/install.go
Expand Up @@ -136,6 +136,15 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return compInstall(args, toComplete, client)
},
RunE: func(_ *cobra.Command, args []string) error {
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify)
if err != nil {
return fmt.Errorf("missing registry client: %w", err)
}
client.SetRegistryClient(registryClient)

if client.DryRunOption == "unchanged" {
client.DryRunOption = "none"
}
rel, err := runInstall(args, client, valueOpts, out)
if err != nil {
return errors.Wrap(err, "INSTALLATION FAILED")
Expand All @@ -154,7 +163,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {

func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Install, valueOpts *values.Options) {
f.BoolVar(&client.CreateNamespace, "create-namespace", false, "create the release namespace if not present")
f.StringVar(&client.DryRunOption, "dry-run", "none", "simulate an install. If --dry-run is set with no option being specified or as 'client', it will not attempt cluster connections. Setting option as 'server' allows attempting cluster connections.")
f.StringVar(&client.DryRunOption, "dry-run", "unchanged", "simulate an install. If --dry-run is set with no option being specified or as '--dry-run=client', it will not attempt cluster connections. Setting '--dry-run=server' allows attempting cluster connections.")
f.Lookup("dry-run").NoOptDefVal = "client"
f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy")
f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install")
Expand Down
3 changes: 1 addition & 2 deletions cmd/helm/load_plugins.go
Expand Up @@ -19,7 +19,6 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
Expand Down Expand Up @@ -311,7 +310,7 @@ func addPluginCommands(plugin *plugin.Plugin, baseCmd *cobra.Command, cmds *plug
// loadFile takes a yaml file at the given path, parses it and returns a pluginCommand object
func loadFile(path string) (*pluginCommand, error) {
cmds := new(pluginCommand)
b, err := ioutil.ReadFile(path)
b, err := os.ReadFile(path)
if err != nil {
return cmds, fmt.Errorf("file (%s) not provided by plugin. No plugin auto-completion possible", path)
}
Expand Down
3 changes: 1 addition & 2 deletions cmd/helm/package.go
Expand Up @@ -19,7 +19,6 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"

Expand Down Expand Up @@ -87,7 +86,7 @@ func newPackageCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {

if client.DependencyUpdate {
downloadManager := &downloader.Manager{
Out: ioutil.Discard,
Out: io.Discard,
ChartPath: path,
Keyring: client.Keyring,
Getters: p,
Expand Down
6 changes: 6 additions & 0 deletions cmd/helm/pull.go
Expand Up @@ -64,6 +64,12 @@ func newPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client.Version = ">0.0.0-0"
}

registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify)
if err != nil {
return fmt.Errorf("missing registry client: %w", err)
}
client.SetRegistryClient(registryClient)

for i := 0; i < len(args); i++ {
output, err := client.Run(args[i])
if err != nil {
Expand Down
24 changes: 23 additions & 1 deletion cmd/helm/push.go
Expand Up @@ -34,8 +34,15 @@ If the chart has an associated provenance file,
it will also be uploaded.
`

type registryPushOptions struct {
certFile string
keyFile string
caFile string
insecureSkipTLSverify bool
}

func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewPushWithOpts(action.WithPushConfig(cfg))
o := &registryPushOptions{}

cmd := &cobra.Command{
Use: "push [chart] [remote]",
Expand All @@ -60,8 +67,17 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return nil, cobra.ShellCompDirectiveNoFileComp
},
RunE: func(cmd *cobra.Command, args []string) error {
registryClient, err := newRegistryClient(o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSverify)
if err != nil {
return fmt.Errorf("missing registry client: %w", err)
}
cfg.RegistryClient = registryClient
chartRef := args[0]
remote := args[1]
client := action.NewPushWithOpts(action.WithPushConfig(cfg),
action.WithTLSClientConfig(o.certFile, o.keyFile, o.caFile),
action.WithInsecureSkipTLSVerify(o.insecureSkipTLSverify),
action.WithPushOptWriter(out))
client.Settings = settings
output, err := client.Run(chartRef, remote)
if err != nil {
Expand All @@ -72,5 +88,11 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}

f := cmd.Flags()
f.StringVar(&o.certFile, "cert-file", "", "identify registry client using this SSL certificate file")
f.StringVar(&o.keyFile, "key-file", "", "identify registry client using this SSL key file")
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart upload")

return cmd
}
35 changes: 25 additions & 10 deletions cmd/helm/registry_login.go
Expand Up @@ -21,7 +21,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"

Expand All @@ -36,9 +35,18 @@ const registryLoginDesc = `
Authenticate to a remote registry.
`

type registryLoginOptions struct {
username string
password string
passwordFromStdinOpt bool
certFile string
keyFile string
caFile string
insecure bool
}

func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
var usernameOpt, passwordOpt string
var passwordFromStdinOpt, insecureOpt bool
o := &registryLoginOptions{}

cmd := &cobra.Command{
Use: "login [host]",
Expand All @@ -49,20 +57,27 @@ func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Comman
RunE: func(cmd *cobra.Command, args []string) error {
hostname := args[0]

username, password, err := getUsernamePassword(usernameOpt, passwordOpt, passwordFromStdinOpt)
username, password, err := getUsernamePassword(o.username, o.password, o.passwordFromStdinOpt)
if err != nil {
return err
}

return action.NewRegistryLogin(cfg).Run(out, hostname, username, password, insecureOpt)
return action.NewRegistryLogin(cfg).Run(out, hostname, username, password,
action.WithCertFile(o.certFile),
action.WithKeyFile(o.keyFile),
action.WithCAFile(o.caFile),
action.WithInsecure(o.insecure))
},
}

f := cmd.Flags()
f.StringVarP(&usernameOpt, "username", "u", "", "registry username")
f.StringVarP(&passwordOpt, "password", "p", "", "registry password or identity token")
f.BoolVarP(&passwordFromStdinOpt, "password-stdin", "", false, "read password or identity token from stdin")
f.BoolVarP(&insecureOpt, "insecure", "", false, "allow connections to TLS registry without certs")
f.StringVarP(&o.username, "username", "u", "", "registry username")
f.StringVarP(&o.password, "password", "p", "", "registry password or identity token")
f.BoolVarP(&o.passwordFromStdinOpt, "password-stdin", "", false, "read password or identity token from stdin")
f.BoolVarP(&o.insecure, "insecure", "", false, "allow connections to TLS registry without certs")
f.StringVar(&o.certFile, "cert-file", "", "identify registry client using this SSL certificate file")
f.StringVar(&o.keyFile, "key-file", "", "identify registry client using this SSL key file")
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")

return cmd
}
Expand All @@ -74,7 +89,7 @@ func getUsernamePassword(usernameOpt string, passwordOpt string, passwordFromStd
password := passwordOpt

if passwordFromStdinOpt {
passwordFromStdin, err := ioutil.ReadAll(os.Stdin)
passwordFromStdin, err := io.ReadAll(os.Stdin)
if err != nil {
return "", "", err
}
Expand Down
3 changes: 1 addition & 2 deletions cmd/helm/repo_add.go
Expand Up @@ -20,7 +20,6 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -134,7 +133,7 @@ func (o *repoAddOptions) run(out io.Writer) error {
return err
}

b, err := ioutil.ReadFile(o.repoFile)
b, err := os.ReadFile(o.repoFile)
if err != nil && !os.IsNotExist(err) {
return err
}
Expand Down
14 changes: 7 additions & 7 deletions cmd/helm/repo_add_test.go
Expand Up @@ -18,7 +18,7 @@ package main

import (
"fmt"
"io/ioutil"
"io"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -102,7 +102,7 @@ func TestRepoAdd(t *testing.T) {
}
os.Setenv(xdg.CacheHomeEnvVar, rootDir)

if err := o.run(ioutil.Discard); err != nil {
if err := o.run(io.Discard); err != nil {
t.Error(err)
}

Expand All @@ -126,11 +126,11 @@ func TestRepoAdd(t *testing.T) {

o.forceUpdate = true

if err := o.run(ioutil.Discard); err != nil {
if err := o.run(io.Discard); err != nil {
t.Errorf("Repository was not updated: %s", err)
}

if err := o.run(ioutil.Discard); err != nil {
if err := o.run(io.Discard); err != nil {
t.Errorf("Duplicate repository name was added")
}
}
Expand Down Expand Up @@ -159,7 +159,7 @@ func TestRepoAddCheckLegalName(t *testing.T) {

wantErrorMsg := fmt.Sprintf("repository name (%s) contains '/', please specify a different name without '/'", testRepoName)

if err := o.run(ioutil.Discard); err != nil {
if err := o.run(io.Discard); err != nil {
if wantErrorMsg != err.Error() {
t.Fatalf("Actual error %s, not equal to expected error %s", err, wantErrorMsg)
}
Expand Down Expand Up @@ -211,14 +211,14 @@ func repoAddConcurrent(t *testing.T, testName, repoFile string) {
forceUpdate: false,
repoFile: repoFile,
}
if err := o.run(ioutil.Discard); err != nil {
if err := o.run(io.Discard); err != nil {
t.Error(err)
}
}(fmt.Sprintf("%s-%d", testName, i))
}
wg.Wait()

b, err := ioutil.ReadFile(repoFile)
b, err := os.ReadFile(repoFile)
if err != nil {
t.Error(err)
}
Expand Down
3 changes: 1 addition & 2 deletions cmd/helm/repo_update_test.go
Expand Up @@ -19,7 +19,6 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -119,7 +118,7 @@ func TestUpdateCustomCacheCmd(t *testing.T) {
repoFile: filepath.Join(ts.Root(), "repositories.yaml"),
repoCache: cachePath,
}
b := ioutil.Discard
b := io.Discard
if err := o.run(b); err != nil {
t.Fatal(err)
}
Expand Down

0 comments on commit 4b7248e

Please sign in to comment.