feat(libhelm): allow passing optional env and http client [EE-5252] (#8798)

Co-authored-by: Matt Hook <hookenz@gmail.com>
pull/8802/head
Dakota Walsh 2 years ago committed by GitHub
parent 33b141bcd3
commit 8e724e3fbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -25,7 +25,7 @@ type addHelmRepoUrlPayload struct {
}
func (p *addHelmRepoUrlPayload) Validate(_ *http.Request) error {
return libhelm.ValidateHelmRepositoryURL(p.URL)
return libhelm.ValidateHelmRepositoryURL(p.URL, nil)
}
// @id HelmUserRepositoryCreate

@ -143,7 +143,7 @@ func (handler *Handler) settingsUpdate(w http.ResponseWriter, r *http.Request) *
newHelmRepo := strings.TrimSuffix(strings.ToLower(*payload.HelmRepositoryURL), "/")
if newHelmRepo != settings.HelmRepositoryURL && newHelmRepo != portainer.DefaultHelmRepositoryURL {
err := libhelm.ValidateHelmRepositoryURL(*payload.HelmRepositoryURL)
err := libhelm.ValidateHelmRepositoryURL(*payload.HelmRepositoryURL, nil)
if err != nil {
return httperror.BadRequest("Invalid Helm repository URL. Must correspond to a valid URL format", err)
}

@ -20,7 +20,7 @@ func (hbpm *helmBinaryPackageManager) Get(getOpts options.GetOptions) ([]byte, e
args = append(args, "--namespace", getOpts.Namespace)
}
result, err := hbpm.runWithKubeConfig("get", args, getOpts.KubernetesClusterAccess)
result, err := hbpm.runWithKubeConfig("get", args, getOpts.KubernetesClusterAccess, getOpts.Env)
if err != nil {
return nil, errors.Wrap(err, "failed to run helm get on specified args")
}

@ -2,6 +2,7 @@ package binary
import (
"bytes"
"os"
"os/exec"
"path"
"runtime"
@ -21,7 +22,7 @@ func NewHelmBinaryPackageManager(binaryPath string) *helmBinaryPackageManager {
}
// runWithKubeConfig will execute run against the provided Kubernetes cluster with kubeconfig as cli arguments.
func (hbpm *helmBinaryPackageManager) runWithKubeConfig(command string, args []string, kca *options.KubernetesClusterAccess) ([]byte, error) {
func (hbpm *helmBinaryPackageManager) runWithKubeConfig(command string, args []string, kca *options.KubernetesClusterAccess, env []string) ([]byte, error) {
cmdArgs := make([]string, 0)
if kca != nil {
cmdArgs = append(cmdArgs, "--kube-apiserver", kca.ClusterServerURL)
@ -29,13 +30,13 @@ func (hbpm *helmBinaryPackageManager) runWithKubeConfig(command string, args []s
cmdArgs = append(cmdArgs, "--kube-ca-file", kca.CertificateAuthorityFile)
}
cmdArgs = append(cmdArgs, args...)
return hbpm.run(command, cmdArgs)
return hbpm.run(command, cmdArgs, env)
}
// run will execute helm command against the provided Kubernetes cluster.
// The endpointId and authToken are dynamic params (based on the user) that allow helm to execute commands
// in the context of the current user against specified k8s cluster.
func (hbpm *helmBinaryPackageManager) run(command string, args []string) ([]byte, error) {
func (hbpm *helmBinaryPackageManager) run(command string, args []string, env []string) ([]byte, error) {
cmdArgs := make([]string, 0)
cmdArgs = append(cmdArgs, command)
cmdArgs = append(cmdArgs, args...)
@ -49,6 +50,9 @@ func (hbpm *helmBinaryPackageManager) run(command string, args []string) ([]byte
cmd := exec.Command(helmPath, cmdArgs...)
cmd.Stderr = &stderr
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, env...)
output, err := cmd.Output()
if err != nil {
return nil, errors.Wrap(err, stderr.String())

@ -33,7 +33,7 @@ func (hbpm *helmBinaryPackageManager) Install(installOpts options.InstallOptions
args = append(args, "--post-renderer", installOpts.PostRenderer)
}
result, err := hbpm.runWithKubeConfig("install", args, installOpts.KubernetesClusterAccess)
result, err := hbpm.runWithKubeConfig("install", args, installOpts.KubernetesClusterAccess, installOpts.Env)
if err != nil {
return nil, errors.Wrap(err, "failed to run helm install on specified args")
}

@ -61,7 +61,7 @@ func Test_Install(t *testing.T) {
}
release, err := hbpm.Install(installOpts)
defer hbpm.run("uninstall", []string{"test-nginx"})
defer hbpm.run("uninstall", []string{"test-nginx"}, nil)
is.NoError(err, "should successfully install release", release)
})
@ -73,7 +73,7 @@ func Test_Install(t *testing.T) {
Repo: "https://charts.bitnami.com/bitnami",
}
release, err := hbpm.Install(installOpts)
defer hbpm.run("uninstall", []string{release.Name})
defer hbpm.run("uninstall", []string{release.Name}, nil)
is.NoError(err, "should successfully install release", release)
})
@ -92,7 +92,7 @@ func Test_Install(t *testing.T) {
ValuesFile: values,
}
release, err := hbpm.Install(installOpts)
defer hbpm.run("uninstall", []string{"test-nginx-2"})
defer hbpm.run("uninstall", []string{"test-nginx-2"}, nil)
is.NoError(err, "should successfully install release", release)
})
@ -105,7 +105,7 @@ func Test_Install(t *testing.T) {
Repo: "https://portainer.github.io/k8s/",
}
release, err := hbpm.Install(installOpts)
defer hbpm.run("uninstall", []string{installOpts.Name})
defer hbpm.run("uninstall", []string{installOpts.Name}, nil)
is.NoError(err, "should successfully install release", release)
})

@ -23,7 +23,7 @@ func (hbpm *helmBinaryPackageManager) List(listOpts options.ListOptions) ([]rele
args = append(args, "--namespace", listOpts.Namespace)
}
result, err := hbpm.runWithKubeConfig("list", args, listOpts.KubernetesClusterAccess)
result, err := hbpm.runWithKubeConfig("list", args, listOpts.KubernetesClusterAccess, listOpts.Env)
if err != nil {
return []release.ReleaseElement{}, errors.Wrap(err, "failed to run helm list on specified args")
}

@ -50,12 +50,15 @@ func (hbpm *helmBinaryPackageManager) SearchRepo(searchRepoOpts options.SearchRe
return nil, errRequiredSearchOptions
}
// The current index.yaml is ~9MB on bitnami.
// At a slow @2mbit download = 40s. @100bit = ~1s.
// I'm seeing 3 - 4s over wifi.
// Give ample time but timeout for now. Can be improved in the future
client := http.Client{
Timeout: 60 * time.Second,
client := searchRepoOpts.Client
if searchRepoOpts.Client == nil {
// The current index.yaml is ~9MB on bitnami.
// At a slow @2mbit download = 40s. @100bit = ~1s.
// I'm seeing 3 - 4s over wifi.
// Give ample time but timeout for now. Can be improved in the future
client = &http.Client{
Timeout: 60 * time.Second,
}
}
url, err := url.ParseRequestURI(searchRepoOpts.Repo)

@ -20,7 +20,7 @@ func (hbpm *helmBinaryPackageManager) Show(showOpts options.ShowOptions) ([]byte
"--repo", showOpts.Repo,
}
result, err := hbpm.run("show", args)
result, err := hbpm.run("show", args, showOpts.Env)
if err != nil {
return nil, errors.Wrap(err, "failed to run helm show on specified args")
}

@ -20,7 +20,7 @@ func (hbpm *helmBinaryPackageManager) Uninstall(uninstallOpts options.UninstallO
args = append(args, "--namespace", uninstallOpts.Namespace)
}
_, err := hbpm.runWithKubeConfig("uninstall", args, uninstallOpts.KubernetesClusterAccess)
_, err := hbpm.runWithKubeConfig("uninstall", args, uninstallOpts.KubernetesClusterAccess, uninstallOpts.Env)
if err != nil {
return errors.Wrap(err, "failed to run helm uninstall on specified args")
}

@ -17,4 +17,6 @@ type GetOptions struct {
Namespace string
ReleaseResource releaseResource
KubernetesClusterAccess *KubernetesClusterAccess
Env []string
}

@ -9,4 +9,7 @@ type InstallOptions struct {
ValuesFile string
PostRenderer string
KubernetesClusterAccess *KubernetesClusterAccess
// Optional environment vars to pass when running helm
Env []string
}

@ -6,4 +6,6 @@ type ListOptions struct {
Selector string
Namespace string
KubernetesClusterAccess *KubernetesClusterAccess
Env []string
}

@ -1,5 +1,8 @@
package options
import "net/http"
type SearchRepoOptions struct {
Repo string
Repo string `example:"https://charts.gitlab.io/"`
Client *http.Client `example:"&http.Client{Timeout: time.Second * 10}"`
}

@ -19,4 +19,6 @@ type ShowOptions struct {
OutputFormat ShowOutputFormat
Chart string
Repo string
Env []string
}

@ -5,4 +5,6 @@ type UninstallOptions struct {
Name string
Namespace string
KubernetesClusterAccess *KubernetesClusterAccess
Env []string
}

@ -13,7 +13,7 @@ import (
const invalidChartRepo = "%q is not a valid chart repository or cannot be reached"
func ValidateHelmRepositoryURL(repoUrl string) error {
func ValidateHelmRepositoryURL(repoUrl string, client *http.Client) error {
if repoUrl == "" {
return errors.New("URL is required")
}
@ -29,9 +29,12 @@ func ValidateHelmRepositoryURL(repoUrl string) error {
url.Path = path.Join(url.Path, "index.yaml")
var client = &http.Client{
Timeout: time.Second * 10,
if client == nil {
client = &http.Client{
Timeout: time.Second * 10,
}
}
response, err := client.Head(url.String())
if err != nil {
return errors.Wrapf(err, invalidChartRepo, repoUrl)

@ -37,7 +37,7 @@ func Test_ValidateHelmRepositoryURL(t *testing.T) {
func(tc testCase) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
err := ValidateHelmRepositoryURL(tc.url)
err := ValidateHelmRepositoryURL(tc.url, nil)
if tc.invalid {
is.Errorf(err, "error expected: %s", tc.url)
} else {

Loading…
Cancel
Save