+
+ SSL/TLS private key
+
+
+
+
{{ $ctrl.formValues.keyFile.name }}
@@ -76,7 +97,7 @@
+
diff --git a/app/react/portainer/feature-flags/enums.ts b/app/react/portainer/feature-flags/enums.ts
index 4c9efa8d6..49a238bbd 100644
--- a/app/react/portainer/feature-flags/enums.ts
+++ b/app/react/portainer/feature-flags/enums.ts
@@ -40,4 +40,5 @@ export enum FeatureId {
K8S_ROLLING_RESTART = 'k8s-rolling-restart',
K8SINSTALL = 'k8s-install',
K8S_ANNOTATIONS = 'k8s-annotations',
+ CA_FILE = 'ca-file',
}
diff --git a/app/react/portainer/feature-flags/feature-flags.service.ts b/app/react/portainer/feature-flags/feature-flags.service.ts
index a16559ab7..ba8ceddcb 100644
--- a/app/react/portainer/feature-flags/feature-flags.service.ts
+++ b/app/react/portainer/feature-flags/feature-flags.service.ts
@@ -45,6 +45,7 @@ export async function init(edition: Edition) {
[FeatureId.K8S_ADM_ONLY_USR_INGRESS_DEPLY]: Edition.BE,
[FeatureId.K8S_ROLLING_RESTART]: Edition.BE,
[FeatureId.K8S_ANNOTATIONS]: Edition.BE,
+ [FeatureId.CA_FILE]: Edition.BE,
};
state.currentEdition = currentEdition;
diff --git a/pkg/libhelm/binary/get.go b/pkg/libhelm/binary/get.go
index 883a61a2d..0df41bbc8 100644
--- a/pkg/libhelm/binary/get.go
+++ b/pkg/libhelm/binary/get.go
@@ -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")
}
diff --git a/pkg/libhelm/binary/helm_package.go b/pkg/libhelm/binary/helm_package.go
index 73805a89e..2e64a8a2b 100644
--- a/pkg/libhelm/binary/helm_package.go
+++ b/pkg/libhelm/binary/helm_package.go
@@ -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())
diff --git a/pkg/libhelm/binary/install.go b/pkg/libhelm/binary/install.go
index 24798517d..dbd2e5dd0 100644
--- a/pkg/libhelm/binary/install.go
+++ b/pkg/libhelm/binary/install.go
@@ -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")
}
diff --git a/pkg/libhelm/binary/install_test.go b/pkg/libhelm/binary/install_test.go
index f22d5916a..e3252e1f2 100644
--- a/pkg/libhelm/binary/install_test.go
+++ b/pkg/libhelm/binary/install_test.go
@@ -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)
})
diff --git a/pkg/libhelm/binary/list.go b/pkg/libhelm/binary/list.go
index a81f511bf..7859c77f4 100644
--- a/pkg/libhelm/binary/list.go
+++ b/pkg/libhelm/binary/list.go
@@ -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")
}
diff --git a/pkg/libhelm/binary/search_repo.go b/pkg/libhelm/binary/search_repo.go
index a959f512e..465c0d7f4 100644
--- a/pkg/libhelm/binary/search_repo.go
+++ b/pkg/libhelm/binary/search_repo.go
@@ -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)
diff --git a/pkg/libhelm/binary/show.go b/pkg/libhelm/binary/show.go
index 7639e6dc2..4fe49aeef 100644
--- a/pkg/libhelm/binary/show.go
+++ b/pkg/libhelm/binary/show.go
@@ -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")
}
diff --git a/pkg/libhelm/binary/uninstall.go b/pkg/libhelm/binary/uninstall.go
index d8a7fdfc6..b926e8ee5 100644
--- a/pkg/libhelm/binary/uninstall.go
+++ b/pkg/libhelm/binary/uninstall.go
@@ -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")
}
diff --git a/pkg/libhelm/options/get_options.go b/pkg/libhelm/options/get_options.go
index fb857eb95..a65cd75a7 100644
--- a/pkg/libhelm/options/get_options.go
+++ b/pkg/libhelm/options/get_options.go
@@ -17,4 +17,6 @@ type GetOptions struct {
Namespace string
ReleaseResource releaseResource
KubernetesClusterAccess *KubernetesClusterAccess
+
+ Env []string
}
diff --git a/pkg/libhelm/options/install_options.go b/pkg/libhelm/options/install_options.go
index 0ccef33a3..5cc6081fb 100644
--- a/pkg/libhelm/options/install_options.go
+++ b/pkg/libhelm/options/install_options.go
@@ -9,4 +9,7 @@ type InstallOptions struct {
ValuesFile string
PostRenderer string
KubernetesClusterAccess *KubernetesClusterAccess
+
+ // Optional environment vars to pass when running helm
+ Env []string
}
diff --git a/pkg/libhelm/options/list_options.go b/pkg/libhelm/options/list_options.go
index 57a520dab..72e0b2562 100644
--- a/pkg/libhelm/options/list_options.go
+++ b/pkg/libhelm/options/list_options.go
@@ -6,4 +6,6 @@ type ListOptions struct {
Selector string
Namespace string
KubernetesClusterAccess *KubernetesClusterAccess
+
+ Env []string
}
diff --git a/pkg/libhelm/options/search_repo_options.go b/pkg/libhelm/options/search_repo_options.go
index da937c21c..73acc5709 100644
--- a/pkg/libhelm/options/search_repo_options.go
+++ b/pkg/libhelm/options/search_repo_options.go
@@ -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}"`
}
diff --git a/pkg/libhelm/options/show_options.go b/pkg/libhelm/options/show_options.go
index 2da79b945..c94e14d80 100644
--- a/pkg/libhelm/options/show_options.go
+++ b/pkg/libhelm/options/show_options.go
@@ -19,4 +19,6 @@ type ShowOptions struct {
OutputFormat ShowOutputFormat
Chart string
Repo string
+
+ Env []string
}
diff --git a/pkg/libhelm/options/uninstall_options.go b/pkg/libhelm/options/uninstall_options.go
index 01753b306..6363e763a 100644
--- a/pkg/libhelm/options/uninstall_options.go
+++ b/pkg/libhelm/options/uninstall_options.go
@@ -5,4 +5,6 @@ type UninstallOptions struct {
Name string
Namespace string
KubernetesClusterAccess *KubernetesClusterAccess
+
+ Env []string
}
diff --git a/pkg/libhelm/validate_repo.go b/pkg/libhelm/validate_repo.go
index 19cf6eabb..b11dfa4d3 100644
--- a/pkg/libhelm/validate_repo.go
+++ b/pkg/libhelm/validate_repo.go
@@ -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)
diff --git a/pkg/libhelm/validate_repo_test.go b/pkg/libhelm/validate_repo_test.go
index 1df96531a..ea04a3818 100644
--- a/pkg/libhelm/validate_repo_test.go
+++ b/pkg/libhelm/validate_repo_test.go
@@ -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 {