From 58b494e09fd6f747a646465b8a0d0d376ded24b7 Mon Sep 17 00:00:00 2001 From: Christian Gebhard Date: Mon, 9 Dec 2024 10:44:17 +0100 Subject: [PATCH 1/2] feature: allow providing kubeconfig from string --- README.md | 15 ++-- .../com/marcnuri/helm/InstallCommand.java | 15 +++- .../java/com/marcnuri/helm/ListCommand.java | 15 +++- .../java/com/marcnuri/helm/TestCommand.java | 15 +++- .../com/marcnuri/helm/UninstallCommand.java | 15 +++- .../com/marcnuri/helm/UpgradeCommand.java | 15 +++- .../com/marcnuri/helm/HelmKubernetesTest.java | 17 ++++ native/internal/helm/clientgetter.go | 84 +++++++++++++++++++ native/internal/helm/clientgetter_test.go | 76 +++++++++++++++++ native/internal/helm/helm.go | 24 ++++-- native/internal/helm/helm_test.go | 57 +++++++++++++ 11 files changed, 328 insertions(+), 20 deletions(-) create mode 100644 native/internal/helm/clientgetter.go create mode 100644 native/internal/helm/clientgetter_test.go create mode 100644 native/internal/helm/helm_test.go diff --git a/README.md b/README.md index d8100929..c0417121 100644 --- a/README.md +++ b/README.md @@ -148,8 +148,9 @@ Release result = installCommand .set("key", "value") // Optionally add a values (YAML) file to source values for the chart (can specify multiple) .withValuesFile(Paths.get("path", "to", "valuesFile")) - // Optionally specify the path to the kubeconfig file to use for CLI requests + // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) + .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally specify an SSL certificate file to identify the registry client .withCertFile(Paths.get("path", "to", "cert")) // Optionally specify an SSL key file to identify the registry client @@ -197,8 +198,9 @@ Lists all the releases for a specified namespace (uses current namespace context List releases = Helm.list() // Optionally specify the Kubernetes namespace to list the releases from .withNamespace("namespace") - // Optionally specify the path to the kubeconfig file to use for CLI requests + // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) + .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally show all releases without any filter applied .all() // Optionally show releases across all namespaces @@ -626,8 +628,9 @@ Release result = Helm.test("chart/reference") .withTimeout(int timeout) // Optionally specify the Kubernetes namespace .withNamespace("namespace") - // Optionally specify the path to the kubeconfig file to use for CLI requests + // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) + .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally enable verbose output .debug() .call(); @@ -653,8 +656,9 @@ String result = Helm.uninstall("chart/reference") .withCascade(Cascade.BACKGROUND) // Optionally specify the Kubernetes namespace to uninstall the release from .withNamespace("namespace") - // Optionally specify the path to the kubeconfig file to use for CLI requests + // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) + .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally enable verbose output .debug() .call(); @@ -719,8 +723,9 @@ Release result = upgradeCommand .set("key", "value") // Optionally add a values (YAML) file to source values for the chart (can specify multiple) .withValuesFile(Paths.get("path", "to", "valuesFile")) - // Optionally specify the path to the kubeconfig file to use for CLI requests + // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) + .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally specify an SSL certificate file to identify the registry client .withCertFile(Paths.get("path", "to", "cert")) // Optionally specify an SSL key file to identify the registry client diff --git a/helm-java/src/main/java/com/marcnuri/helm/InstallCommand.java b/helm-java/src/main/java/com/marcnuri/helm/InstallCommand.java index 233c58eb..ad447a96 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/InstallCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/InstallCommand.java @@ -53,7 +53,7 @@ public class InstallCommand extends HelmCommand { private int timeout; private final Map values; private final List valuesFiles; - private Path kubeConfig; + private String kubeConfig; private Path certFile; private Path keyFile; private Path caFile; @@ -96,7 +96,7 @@ public Release call() { timeout, urlEncode(values), toString(valuesFiles), - toString(kubeConfig), + kubeConfig, toString(certFile), toString(keyFile), toString(caFile), @@ -317,6 +317,17 @@ public InstallCommand withValuesFile(Path valuesFile) { * @return this {@link InstallCommand} instance. */ public InstallCommand withKubeConfig(Path kubeConfig) { + this.kubeConfig = toString(kubeConfig); + return this; + } + + /** + * Set the kube config to use + * + * @param kubeConfig the content of the kube config file. + * @return this {@link TestCommand} instance. + */ + public InstallCommand withKubeConfig(String kubeConfig) { this.kubeConfig = kubeConfig; return this; } diff --git a/helm-java/src/main/java/com/marcnuri/helm/ListCommand.java b/helm-java/src/main/java/com/marcnuri/helm/ListCommand.java index 4c26710f..bc6ac65c 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/ListCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/ListCommand.java @@ -38,7 +38,7 @@ public class ListCommand extends HelmCommand> { private boolean uninstalled; private boolean uninstalling; private String namespace; - private Path kubeConfig; + private String kubeConfig; public ListCommand(HelmLib helmLib) { super(helmLib); @@ -56,7 +56,7 @@ public List call() { toInt(uninstalled), toInt(uninstalling), namespace, - toString(kubeConfig) + kubeConfig )))); } @@ -158,6 +158,17 @@ public ListCommand withNamespace(String namespace) { * @return this {@link ListCommand} instance. */ public ListCommand withKubeConfig(Path kubeConfig) { + this.kubeConfig = toString(kubeConfig); + return this; + } + + /** + * Set the kube config to use + * + * @param kubeConfig the content of the kube config file. + * @return this {@link ListCommand} instance. + */ + public ListCommand withKubeConfig(String kubeConfig) { this.kubeConfig = kubeConfig; return this; } diff --git a/helm-java/src/main/java/com/marcnuri/helm/TestCommand.java b/helm-java/src/main/java/com/marcnuri/helm/TestCommand.java index efc81a7d..a291d405 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/TestCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/TestCommand.java @@ -31,7 +31,7 @@ public class TestCommand extends HelmCommand { private final String releaseName; private int timeout; private String namespace; - private Path kubeConfig; + private String kubeConfig; private boolean debug; public TestCommand(HelmLib helmLib, String releaseName) { @@ -45,7 +45,7 @@ public Release call() { releaseName, timeout, namespace, - toString(kubeConfig), + kubeConfig, toInt(debug) )))); } @@ -79,6 +79,17 @@ public TestCommand withNamespace(String namespace) { * @return this {@link TestCommand} instance. */ public TestCommand withKubeConfig(Path kubeConfig) { + this.kubeConfig = toString(kubeConfig); + return this; + } + + /** + * Set the kube config to use + * + * @param kubeConfig the content of the kube config file. + * @return this {@link TestCommand} instance. + */ + public TestCommand withKubeConfig(String kubeConfig) { this.kubeConfig = kubeConfig; return this; } diff --git a/helm-java/src/main/java/com/marcnuri/helm/UninstallCommand.java b/helm-java/src/main/java/com/marcnuri/helm/UninstallCommand.java index 124ff8d7..5bdaece0 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/UninstallCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/UninstallCommand.java @@ -38,7 +38,7 @@ public enum Cascade { private boolean keepHistory; private Cascade cascade; private String namespace; - private Path kubeConfig; + private String kubeConfig; private boolean debug; public UninstallCommand(HelmLib helmLib, String releaseName) { @@ -56,7 +56,7 @@ public String call() { toInt(keepHistory), cascade == null ? null : cascade.name().toLowerCase(Locale.ROOT), namespace, - toString(kubeConfig), + kubeConfig, toInt(debug) ))).out; } @@ -131,6 +131,17 @@ public UninstallCommand withNamespace(String namespace) { * @return this {@link UninstallCommand} instance. */ public UninstallCommand withKubeConfig(Path kubeConfig) { + this.kubeConfig = toString(kubeConfig); + return this; + } + + /** + * Set the kube config to use + * + * @param kubeConfig the content of the kube config file. + * @return this {@link UninstallCommand} instance. + */ + public UninstallCommand withKubeConfig(String kubeConfig) { this.kubeConfig = kubeConfig; return this; } diff --git a/helm-java/src/main/java/com/marcnuri/helm/UpgradeCommand.java b/helm-java/src/main/java/com/marcnuri/helm/UpgradeCommand.java index 59d2b806..62aeb58b 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/UpgradeCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/UpgradeCommand.java @@ -57,7 +57,7 @@ public class UpgradeCommand extends HelmCommand { private int timeout; private final Map values; private final List valuesFiles; - private Path kubeConfig; + private String kubeConfig; private Path certFile; private Path keyFile; private Path caFile; @@ -104,7 +104,7 @@ public Release call() { timeout, urlEncode(values), toString(valuesFiles), - toString(kubeConfig), + kubeConfig, toString(certFile), toString(keyFile), toString(caFile), @@ -369,6 +369,17 @@ public UpgradeCommand withValuesFile(Path valuesFile) { * @return this {@link UpgradeCommand} instance. */ public UpgradeCommand withKubeConfig(Path kubeConfig) { + this.kubeConfig = toString(kubeConfig); + return this; + } + + /** + * Set the kube config to use + * + * @param kubeConfig the content of the kube config file. + * @return this {@link UpgradeCommand} instance. + */ + public UpgradeCommand withKubeConfig(String kubeConfig) { this.kubeConfig = kubeConfig; return this; } diff --git a/helm-java/src/test/java/com/marcnuri/helm/HelmKubernetesTest.java b/helm-java/src/test/java/com/marcnuri/helm/HelmKubernetesTest.java index 07742e2b..8bed2841 100644 --- a/helm-java/src/test/java/com/marcnuri/helm/HelmKubernetesTest.java +++ b/helm-java/src/test/java/com/marcnuri/helm/HelmKubernetesTest.java @@ -271,6 +271,23 @@ void listsCurrentNamespace() { .matches(d -> d.toLocalDate().equals(LocalDate.now())); } + @Test + void listsCurrentNamespaceWithKubeConfigContents() { + final List result = Helm.list().withKubeConfig(kindContainer.getKubeconfig()).call(); + assertThat(result) + .filteredOn(r -> r.getName().equals("list-default")) + .singleElement() + .returns("list-default", Release::getName) + .returns(null, Release::getNamespace) + .returns("deployed", Release::getStatus) + .returns("1", Release::getRevision) + .returns("test-0.1.0", Release::getChart) + .returns("1.16.0", Release::getAppVersion) + .returns("", Release::getOutput) + .extracting(Release::getLastDeployed) + .matches(d -> d.toLocalDate().equals(LocalDate.now())); + } + @Test void listsSpecificNamespace() { final List result = Helm.list().withKubeConfig(kubeConfig) diff --git a/native/internal/helm/clientgetter.go b/native/internal/helm/clientgetter.go new file mode 100644 index 00000000..02651ba1 --- /dev/null +++ b/native/internal/helm/clientgetter.go @@ -0,0 +1,84 @@ +/* + * Copyright 2024 Marc Nuri + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package helm + +import ( + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/memory" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" + "k8s.io/client-go/tools/clientcmd" +) + +type SimpleRESTClientGetter struct { + Namespace string + KubeConfig string +} + +func NewRESTClientGetter(namespace, kubeConfig string) *SimpleRESTClientGetter { + return &SimpleRESTClientGetter{ + Namespace: namespace, + KubeConfig: kubeConfig, + } +} + +func (c *SimpleRESTClientGetter) ToRESTConfig() (*rest.Config, error) { + config, err := clientcmd.RESTConfigFromKubeConfig([]byte(c.KubeConfig)) + if err != nil { + return nil, err + } + return config, nil +} + +func (c *SimpleRESTClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + config, err := c.ToRESTConfig() + if err != nil { + return nil, err + } + + // The more groups you have, the more discovery requests you need to make. + // given 25 groups (our groups + a few custom conf) with one-ish version each, discovery needs to make 50 requests + // double it just so we don't end up here again for a while. This config is only used for discovery. + config.Burst = 300 + + discoveryClient, _ := discovery.NewDiscoveryClientForConfig(config) + return memory.NewMemCacheClient(discoveryClient), nil +} + +func (c *SimpleRESTClientGetter) ToRESTMapper() (meta.RESTMapper, error) { + discoveryClient, err := c.ToDiscoveryClient() + if err != nil { + return nil, err + } + + mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) + expander := restmapper.NewShortcutExpander(mapper, discoveryClient, nil) + return expander, nil +} + +func (c *SimpleRESTClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig { + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + // use the standard defaults for this client command + // DEPRECATED: remove and replace with something more accurate + loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig + + overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} + overrides.Context.Namespace = c.Namespace + + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) +} diff --git a/native/internal/helm/clientgetter_test.go b/native/internal/helm/clientgetter_test.go new file mode 100644 index 00000000..cd8eb377 --- /dev/null +++ b/native/internal/helm/clientgetter_test.go @@ -0,0 +1,76 @@ +/* + * Copyright 2024 Marc Nuri + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package helm + +import ( + "reflect" + "testing" + + "k8s.io/client-go/rest" +) + +const KUBECONFIG = ` +apiVersion: v1 +clusters: +- cluster: + server: https://1.2.3.4 + name: development +contexts: +- context: + cluster: development + namespace: frontend + user: developer + name: dev-frontend +current-context: dev-frontend +kind: Config +preferences: {} +users: +- name: developer + user: + username: user + password: password +` + +func TestNewRESTClientGetter(t *testing.T) { + namespace := "default" + restClientGetter := NewRESTClientGetter(namespace, KUBECONFIG) + + if restClientGetter.KubeConfig != KUBECONFIG { + t.Errorf("Expected %s\n got %s", KUBECONFIG, restClientGetter.KubeConfig) + } + if restClientGetter.Namespace != namespace { + t.Errorf("Expected %s, got %s", namespace, restClientGetter.Namespace) + } +} + +func TestToRESTConfig(t *testing.T) { + namespace := "default" + restClientGetter := NewRESTClientGetter(namespace, KUBECONFIG) + expectedRestConfig := &rest.Config{ + Host: "https://1.2.3.4", + Username: "user", + Password: "password", + } + restConfig, err := restClientGetter.ToRESTConfig() + if err != nil { + t.Errorf("Expected converting to succeed, got %s", err) + } + + if !reflect.DeepEqual(restConfig, expectedRestConfig) { + t.Errorf("Expected %s, got %s", expectedRestConfig, restConfig) + } +} diff --git a/native/internal/helm/helm.go b/native/internal/helm/helm.go index 4a806f41..ac82b44c 100644 --- a/native/internal/helm/helm.go +++ b/native/internal/helm/helm.go @@ -19,6 +19,11 @@ package helm import ( "bytes" "fmt" + "io" + "os" + "strings" + "time" + "github.com/pkg/errors" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" @@ -27,10 +32,7 @@ import ( "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v3/pkg/release" - "io" - "os" - "strings" - "time" + "k8s.io/cli-runtime/pkg/genericclioptions" ) type CfgOptions struct { @@ -50,6 +52,8 @@ type CertOptions struct { Keyring string } +const KUBECONFIG_IDENTIFIER = "kind: Config" + func NewCfg(options *CfgOptions) *action.Configuration { settings := cli.New() settings.KubeConfig = options.KubeConfig @@ -66,7 +70,13 @@ func NewCfg(options *CfgOptions) *action.Configuration { if options.AllNamespaces { effectiveNamespace = "" } - err := actionConfig.Init(settings.RESTClientGetter(), effectiveNamespace, os.Getenv("HELM_DRIVER"), log) + var restClientGetter genericclioptions.RESTClientGetter + if isKubeConfig(options.KubeConfig) { + restClientGetter = NewRESTClientGetter(effectiveNamespace, options.KubeConfig) + } else { + restClientGetter = settings.RESTClientGetter() + } + err := actionConfig.Init(restClientGetter, effectiveNamespace, os.Getenv("HELM_DRIVER"), log) if err != nil { panic(err) } @@ -181,3 +191,7 @@ func repositoryConfig(options *RepoOptions) string { return options.RepositoryConfig } } + +func isKubeConfig(potentialConfig string) bool { + return strings.Contains(potentialConfig, KUBECONFIG_IDENTIFIER) +} diff --git a/native/internal/helm/helm_test.go b/native/internal/helm/helm_test.go new file mode 100644 index 00000000..38707c61 --- /dev/null +++ b/native/internal/helm/helm_test.go @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Marc Nuri + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package helm + +import ( + "reflect" + "testing" + + "k8s.io/cli-runtime/pkg/genericclioptions" +) + +func TestNewCfgKubeConfigContent(t *testing.T) { + cfg := NewCfg(&CfgOptions{ + RegistryClient: nil, + KubeConfig: KUBECONFIG, + Namespace: "default", + AllNamespaces: false, + KubeOut: nil, + }) + expectedGetter := NewRESTClientGetter("default", KUBECONFIG) + + if !reflect.DeepEqual(cfg.RESTClientGetter, expectedGetter) { + t.Errorf("Expected %s, got %s", expectedGetter, cfg.RESTClientGetter) + return + } +} + +func TestNewCfgKubeConfigPath(t *testing.T) { + path := "/path/to/kubeconfig" + cfg := NewCfg(&CfgOptions{ + RegistryClient: nil, + KubeConfig: path, + Namespace: "default", + AllNamespaces: false, + KubeOut: nil, + }) + expectedGetter := &genericclioptions.ConfigFlags{} + + if reflect.TypeOf(cfg.RESTClientGetter) != reflect.TypeOf(expectedGetter) { + t.Errorf("Expected type %v \n got %v", reflect.TypeOf(expectedGetter), reflect.TypeOf(cfg.RESTClientGetter)) + return + } +} From ec4f77306a983562766269c2dd4aadedf52c0992 Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Sat, 21 Dec 2024 09:06:16 +0100 Subject: [PATCH 2/2] review:feat: allow providing kubeconfig from string --- README.md | 25 +++-- .../com/marcnuri/helm/InstallCommand.java | 15 +-- .../java/com/marcnuri/helm/ListCommand.java | 15 +-- .../java/com/marcnuri/helm/TestCommand.java | 15 +-- .../com/marcnuri/helm/UninstallCommand.java | 15 +-- .../com/marcnuri/helm/UpgradeCommand.java | 15 +-- .../com/marcnuri/helm/HelmKubernetesTest.java | 100 +++++++++--------- .../com/marcnuri/helm/jni/InstallOptions.java | 5 + .../com/marcnuri/helm/jni/ListOptions.java | 8 +- .../com/marcnuri/helm/jni/TestOptions.java | 5 + .../marcnuri/helm/jni/UninstallOptions.java | 5 + .../com/marcnuri/helm/jni/UpgradeOptions.java | 5 + native/internal/helm/clientgetter.go | 84 --------------- native/internal/helm/clientgetter_test.go | 76 ------------- native/internal/helm/envtest_test.go | 30 ++++++ native/internal/helm/helm.go | 37 ++++--- native/internal/helm/helm_test.go | 65 ++++++------ native/internal/helm/install.go | 8 +- native/internal/helm/list.go | 28 ++--- native/internal/helm/test.go | 16 +-- native/internal/helm/uninstall.go | 24 +++-- native/internal/helm/upgrade.go | 8 +- native/main.go | 58 +++++----- 23 files changed, 303 insertions(+), 359 deletions(-) delete mode 100644 native/internal/helm/clientgetter.go delete mode 100644 native/internal/helm/clientgetter_test.go diff --git a/README.md b/README.md index c0417121..5db4a7cf 100644 --- a/README.md +++ b/README.md @@ -148,9 +148,10 @@ Release result = installCommand .set("key", "value") // Optionally add a values (YAML) file to source values for the chart (can specify multiple) .withValuesFile(Paths.get("path", "to", "valuesFile")) - // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests + // Optionally specify the path to the kubeconfig file to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) - .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") + // Optionally set the contents of the kubeconfig file as a string (takes precedence over the path) + .withKubeConfigContents("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally specify an SSL certificate file to identify the registry client .withCertFile(Paths.get("path", "to", "cert")) // Optionally specify an SSL key file to identify the registry client @@ -198,9 +199,10 @@ Lists all the releases for a specified namespace (uses current namespace context List releases = Helm.list() // Optionally specify the Kubernetes namespace to list the releases from .withNamespace("namespace") - // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests + // Optionally specify the path to the kubeconfig file to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) - .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") + // Optionally set the contents of the kubeconfig file as a string (takes precedence over the path) + .withKubeConfigContents("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally show all releases without any filter applied .all() // Optionally show releases across all namespaces @@ -628,9 +630,10 @@ Release result = Helm.test("chart/reference") .withTimeout(int timeout) // Optionally specify the Kubernetes namespace .withNamespace("namespace") - // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests + // Optionally specify the path to the kubeconfig file to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) - .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") + // Optionally set the contents of the kubeconfig file as a string (takes precedence over the path) + .withKubeConfigContents("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally enable verbose output .debug() .call(); @@ -656,9 +659,10 @@ String result = Helm.uninstall("chart/reference") .withCascade(Cascade.BACKGROUND) // Optionally specify the Kubernetes namespace to uninstall the release from .withNamespace("namespace") - // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests + // Optionally specify the path to the kubeconfig file to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) - .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") + // Optionally set the contents of the kubeconfig file as a string (takes precedence over the path) + .withKubeConfigContents("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally enable verbose output .debug() .call(); @@ -723,9 +727,10 @@ Release result = upgradeCommand .set("key", "value") // Optionally add a values (YAML) file to source values for the chart (can specify multiple) .withValuesFile(Paths.get("path", "to", "valuesFile")) - // Optionally specify the path to the kubeconfig file or the contents as a string to use for CLI requests + // Optionally specify the path to the kubeconfig file to use for CLI requests .withKubeConfig(Paths.get("path", "to", "kubeconfig")) - .withKubeConfig("apiVersion: v1\nkind: Config\nclusters:\n...") + // Optionally set the contents of the kubeconfig file as a string (takes precedence over the path) + .withKubeConfigContents("apiVersion: v1\nkind: Config\nclusters:\n...") // Optionally specify an SSL certificate file to identify the registry client .withCertFile(Paths.get("path", "to", "cert")) // Optionally specify an SSL key file to identify the registry client diff --git a/helm-java/src/main/java/com/marcnuri/helm/InstallCommand.java b/helm-java/src/main/java/com/marcnuri/helm/InstallCommand.java index ad447a96..6092a4e5 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/InstallCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/InstallCommand.java @@ -32,6 +32,7 @@ * @author Marc Nuri * @author Miriam Schmidt * @author Kevin J. Mckernan + * @author Christian Gebhard */ public class InstallCommand extends HelmCommand { @@ -53,7 +54,8 @@ public class InstallCommand extends HelmCommand { private int timeout; private final Map values; private final List valuesFiles; - private String kubeConfig; + private Path kubeConfig; + private String kubeConfigContents; private Path certFile; private Path keyFile; private Path caFile; @@ -96,7 +98,8 @@ public Release call() { timeout, urlEncode(values), toString(valuesFiles), - kubeConfig, + toString(kubeConfig), + kubeConfigContents, toString(certFile), toString(keyFile), toString(caFile), @@ -317,18 +320,18 @@ public InstallCommand withValuesFile(Path valuesFile) { * @return this {@link InstallCommand} instance. */ public InstallCommand withKubeConfig(Path kubeConfig) { - this.kubeConfig = toString(kubeConfig); + this.kubeConfig = kubeConfig; return this; } /** * Set the kube config to use * - * @param kubeConfig the content of the kube config file. + * @param kubeConfigContents the contents of the kube config file. * @return this {@link TestCommand} instance. */ - public InstallCommand withKubeConfig(String kubeConfig) { - this.kubeConfig = kubeConfig; + public InstallCommand withKubeConfigContents(String kubeConfigContents) { + this.kubeConfigContents = kubeConfigContents; return this; } diff --git a/helm-java/src/main/java/com/marcnuri/helm/ListCommand.java b/helm-java/src/main/java/com/marcnuri/helm/ListCommand.java index bc6ac65c..c3e07afb 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/ListCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/ListCommand.java @@ -26,6 +26,7 @@ /** * @author Marc Nuri + * @author Christian Gebhard */ public class ListCommand extends HelmCommand> { @@ -38,7 +39,8 @@ public class ListCommand extends HelmCommand> { private boolean uninstalled; private boolean uninstalling; private String namespace; - private String kubeConfig; + private Path kubeConfig; + private String kubeConfigContents; public ListCommand(HelmLib helmLib) { super(helmLib); @@ -56,7 +58,8 @@ public List call() { toInt(uninstalled), toInt(uninstalling), namespace, - kubeConfig + toString(kubeConfig), + kubeConfigContents )))); } @@ -158,18 +161,18 @@ public ListCommand withNamespace(String namespace) { * @return this {@link ListCommand} instance. */ public ListCommand withKubeConfig(Path kubeConfig) { - this.kubeConfig = toString(kubeConfig); + this.kubeConfig = kubeConfig; return this; } /** * Set the kube config to use * - * @param kubeConfig the content of the kube config file. + * @param kubeConfigContents the contents of the kube config file. * @return this {@link ListCommand} instance. */ - public ListCommand withKubeConfig(String kubeConfig) { - this.kubeConfig = kubeConfig; + public ListCommand withKubeConfigContents(String kubeConfigContents) { + this.kubeConfigContents = kubeConfigContents; return this; } } diff --git a/helm-java/src/main/java/com/marcnuri/helm/TestCommand.java b/helm-java/src/main/java/com/marcnuri/helm/TestCommand.java index a291d405..172e8e0c 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/TestCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/TestCommand.java @@ -25,13 +25,15 @@ /** * @author Marc Nuri + * @author Christian Gebhard */ public class TestCommand extends HelmCommand { private final String releaseName; private int timeout; private String namespace; - private String kubeConfig; + private Path kubeConfig; + private String kubeConfigContents; private boolean debug; public TestCommand(HelmLib helmLib, String releaseName) { @@ -45,7 +47,8 @@ public Release call() { releaseName, timeout, namespace, - kubeConfig, + toString(kubeConfig), + kubeConfigContents, toInt(debug) )))); } @@ -79,18 +82,18 @@ public TestCommand withNamespace(String namespace) { * @return this {@link TestCommand} instance. */ public TestCommand withKubeConfig(Path kubeConfig) { - this.kubeConfig = toString(kubeConfig); + this.kubeConfig = kubeConfig; return this; } /** * Set the kube config to use * - * @param kubeConfig the content of the kube config file. + * @param kubeConfigContents the contents of the kube config file. * @return this {@link TestCommand} instance. */ - public TestCommand withKubeConfig(String kubeConfig) { - this.kubeConfig = kubeConfig; + public TestCommand withKubeConfigContents(String kubeConfigContents) { + this.kubeConfigContents = kubeConfigContents; return this; } diff --git a/helm-java/src/main/java/com/marcnuri/helm/UninstallCommand.java b/helm-java/src/main/java/com/marcnuri/helm/UninstallCommand.java index 5bdaece0..8d0c9720 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/UninstallCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/UninstallCommand.java @@ -24,6 +24,7 @@ /** * @author Marc Nuri + * @author Christian Gebhard */ public class UninstallCommand extends HelmCommand { @@ -38,7 +39,8 @@ public enum Cascade { private boolean keepHistory; private Cascade cascade; private String namespace; - private String kubeConfig; + private Path kubeConfig; + private String kubeConfigContents; private boolean debug; public UninstallCommand(HelmLib helmLib, String releaseName) { @@ -56,7 +58,8 @@ public String call() { toInt(keepHistory), cascade == null ? null : cascade.name().toLowerCase(Locale.ROOT), namespace, - kubeConfig, + toString(kubeConfig), + kubeConfigContents, toInt(debug) ))).out; } @@ -131,18 +134,18 @@ public UninstallCommand withNamespace(String namespace) { * @return this {@link UninstallCommand} instance. */ public UninstallCommand withKubeConfig(Path kubeConfig) { - this.kubeConfig = toString(kubeConfig); + this.kubeConfig = kubeConfig; return this; } /** * Set the kube config to use * - * @param kubeConfig the content of the kube config file. + * @param kubeConfigContents the contents of the kube config file. * @return this {@link UninstallCommand} instance. */ - public UninstallCommand withKubeConfig(String kubeConfig) { - this.kubeConfig = kubeConfig; + public UninstallCommand withKubeConfigContents(String kubeConfigContents) { + this.kubeConfigContents = kubeConfigContents; return this; } diff --git a/helm-java/src/main/java/com/marcnuri/helm/UpgradeCommand.java b/helm-java/src/main/java/com/marcnuri/helm/UpgradeCommand.java index 62aeb58b..21c8ccff 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/UpgradeCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/UpgradeCommand.java @@ -32,6 +32,7 @@ * @author Marc Nuri * @author Miriam Schmidt * @author Kevin J. Mckernan + * @author Christian Gebhard */ public class UpgradeCommand extends HelmCommand { @@ -57,7 +58,8 @@ public class UpgradeCommand extends HelmCommand { private int timeout; private final Map values; private final List valuesFiles; - private String kubeConfig; + private Path kubeConfig; + private String kubeConfigContents; private Path certFile; private Path keyFile; private Path caFile; @@ -104,7 +106,8 @@ public Release call() { timeout, urlEncode(values), toString(valuesFiles), - kubeConfig, + toString(kubeConfig), + kubeConfigContents, toString(certFile), toString(keyFile), toString(caFile), @@ -369,18 +372,18 @@ public UpgradeCommand withValuesFile(Path valuesFile) { * @return this {@link UpgradeCommand} instance. */ public UpgradeCommand withKubeConfig(Path kubeConfig) { - this.kubeConfig = toString(kubeConfig); + this.kubeConfig = kubeConfig; return this; } /** * Set the kube config to use * - * @param kubeConfig the content of the kube config file. + * @param kubeConfigContents the contents of the kube config file. * @return this {@link UpgradeCommand} instance. */ - public UpgradeCommand withKubeConfig(String kubeConfig) { - this.kubeConfig = kubeConfig; + public UpgradeCommand withKubeConfigContents(String kubeConfigContents) { + this.kubeConfigContents = kubeConfigContents; return this; } diff --git a/helm-java/src/test/java/com/marcnuri/helm/HelmKubernetesTest.java b/helm-java/src/test/java/com/marcnuri/helm/HelmKubernetesTest.java index 8bed2841..ee7853cb 100644 --- a/helm-java/src/test/java/com/marcnuri/helm/HelmKubernetesTest.java +++ b/helm-java/src/test/java/com/marcnuri/helm/HelmKubernetesTest.java @@ -47,7 +47,8 @@ class HelmKubernetesTest { static KindContainer kindContainer; - static Path kubeConfig; + static String kubeConfigContents; + static Path kubeConfigFile; private Helm helm; @@ -55,8 +56,9 @@ class HelmKubernetesTest { static void setUpKubernetes(@TempDir Path tempDir) throws IOException { kindContainer = new KindContainer<>(KindContainerVersion.VERSION_1_31_0); kindContainer.start(); - kubeConfig = tempDir.resolve("config.yaml"); - Files.write(kubeConfig, kindContainer.getKubeconfig().getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE); + kubeConfigContents = kindContainer.getKubeconfig(); + kubeConfigFile = tempDir.resolve("config.yaml"); + Files.write(kubeConfigFile,kubeConfigContents.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE); } @AfterAll @@ -77,7 +79,7 @@ class Valid { @Test void withName() { final Release result = helm.install() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-install-with-name") .call(); assertThat(result) @@ -93,7 +95,7 @@ void withName() { @Test void withDebug() { final Release result = helm.install() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-install-with-with-debug") .debug() .call(); @@ -109,7 +111,7 @@ void withDebug() { @Test void withWaitReady() { final Release result = helm.install() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-install-with-wait-ready") .set("fullnameOverride", "helm-install-with-wait-ready") .set("image.repository", "ghcr.io/linuxserver/nginx") @@ -127,7 +129,7 @@ void withWaitReady() { @Test void withWaitReadyAndCustomTimeout() { final Release result = helm.install() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-install-with-wait-ready-and-custom-timeout") .set("fullnameOverride", "helm-install-with-wait-ready-and-custom-timeout") .set("image.repository", "ghcr.io/linuxserver/nginx") @@ -146,7 +148,7 @@ void withWaitReadyAndCustomTimeout() { @Test void withNamespaceAndCreateNamespace() { final Release result = helm.install() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("created-namespace") .withNamespace("to-be-created") .createNamespace() @@ -170,7 +172,7 @@ class Invalid { @Test void missingNamespace() { final InstallCommand install = helm.install() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("missing-namespace") .withNamespace("non-existent"); assertThatThrownBy(install::call) @@ -181,7 +183,7 @@ void missingNamespace() { @Test void lowTimeout() { final InstallCommand installCommand = helm.install() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-install-with-wait-ready-and-low-timeout") .set("fullnameOverride", "helm-install-with-wait-ready-and-low-timeout") .set("image.repository", "ghcr.io/linuxserver/nginx") @@ -216,11 +218,11 @@ void setUp(@TempDir Path tempDir) throws IOException { @Test void withoutAtomic() { - InstallCommand installCommand = failingHelm.install().withKubeConfig(kubeConfig).withName("test-fail"); + InstallCommand installCommand = failingHelm.install().withKubeConfig(kubeConfigFile).withName("test-fail"); assertThatThrownBy(installCommand::call).isInstanceOf(IllegalStateException.class) .hasMessageContaining("Pod \"test-fail-test-failing\" is invalid: spec.containers: Required value"); - assertThat(Helm.list().withKubeConfig(kubeConfig).call()).filteredOn(r -> r.getName().equals("test-fail")) + assertThat(Helm.list().withKubeConfig(kubeConfigFile).call()).filteredOn(r -> r.getName().equals("test-fail")) .singleElement() .returns("failed", Release::getStatus); } @@ -228,11 +230,11 @@ void withoutAtomic() { @Test void withAtomic() { InstallCommand atomicInstallCommand = - failingHelm.install().withKubeConfig(kubeConfig).withName("test-rollback").atomic(); + failingHelm.install().withKubeConfig(kubeConfigFile).withName("test-rollback").atomic(); assertThatThrownBy(atomicInstallCommand::call).isInstanceOf(IllegalStateException.class) .hasMessageContaining("Pod \"test-rollback-test-failing\" is invalid: spec.containers: Required value"); - assertThat(Helm.list().withKubeConfig(kubeConfig).call()).filteredOn(r -> r.getName().equals("test-rollback")) + assertThat(Helm.list().withKubeConfig(kubeConfigFile).call()).filteredOn(r -> r.getName().equals("test-rollback")) .isEmpty(); } } @@ -243,20 +245,20 @@ class HelmList { @BeforeEach void setUp() { - helm.install().withKubeConfig(kubeConfig).withName("list-default").call(); - helm.install().withKubeConfig(kubeConfig) + helm.install().withKubeConfig(kubeConfigFile).withName("list-default").call(); + helm.install().withKubeConfig(kubeConfigFile) .withName("list-namespace").withNamespace("list-namespace").createNamespace().call(); } @AfterEach() void tearDown() { - Helm.uninstall("list-default").withKubeConfig(kubeConfig).call(); - Helm.uninstall("list-namespace").withKubeConfig(kubeConfig).withNamespace("list-namespace").call(); + Helm.uninstall("list-default").withKubeConfig(kubeConfigFile).call(); + Helm.uninstall("list-namespace").withKubeConfig(kubeConfigFile).withNamespace("list-namespace").call(); } @Test void listsCurrentNamespace() { - final List result = Helm.list().withKubeConfig(kubeConfig).call(); + final List result = Helm.list().withKubeConfig(kubeConfigFile).call(); assertThat(result) .filteredOn(r -> r.getName().equals("list-default")) .singleElement() @@ -273,7 +275,7 @@ void listsCurrentNamespace() { @Test void listsCurrentNamespaceWithKubeConfigContents() { - final List result = Helm.list().withKubeConfig(kindContainer.getKubeconfig()).call(); + final List result = Helm.list().withKubeConfigContents(kubeConfigContents).call(); assertThat(result) .filteredOn(r -> r.getName().equals("list-default")) .singleElement() @@ -290,7 +292,7 @@ void listsCurrentNamespaceWithKubeConfigContents() { @Test void listsSpecificNamespace() { - final List result = Helm.list().withKubeConfig(kubeConfig) + final List result = Helm.list().withKubeConfig(kubeConfigFile) .withNamespace("list-namespace") .call(); assertThat(result) @@ -301,7 +303,7 @@ void listsSpecificNamespace() { @Test void listsAllNamespaces() { - final List result = Helm.list().withKubeConfig(kubeConfig) + final List result = Helm.list().withKubeConfig(kubeConfigFile) .allNamespaces() .call(); assertThat(result) @@ -320,7 +322,7 @@ class Valid { @Test void withValidRelease() { helm.install() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-test-valid-release") .set("fullnameOverride", "helm-test-valid-release") .set("image.repository", "ghcr.io/linuxserver/nginx") @@ -329,7 +331,7 @@ void withValidRelease() { .waitReady() .call(); final Release result = Helm.test("helm-test-valid-release") - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .call(); assertThat(result) .hasFieldOrPropertyWithValue("name", "helm-test-valid-release") @@ -349,7 +351,7 @@ class Invalid { @Test void missingRelease() { final TestCommand testCommand = Helm.test("i-was-never-created") - .withKubeConfig(kubeConfig); + .withKubeConfig(kubeConfigFile); assertThatThrownBy(testCommand::call) .message() .isEqualTo("release: not found"); @@ -357,9 +359,9 @@ void missingRelease() { @Test void lowTimeout() { - helm.install().withKubeConfig(kubeConfig).withName("test-low-timeout").call(); + helm.install().withKubeConfig(kubeConfigFile).withName("test-low-timeout").call(); final TestCommand testCommand = Helm.test("test-low-timeout") - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withTimeout(1); assertThatThrownBy(testCommand::call) .message() @@ -376,8 +378,8 @@ class Valid { @Test void withValidRelease() { - helm.install().withKubeConfig(kubeConfig).withName("uninstall").call(); - final String out = Helm.uninstall("uninstall").withKubeConfig(kubeConfig).call(); + helm.install().withKubeConfig(kubeConfigFile).withName("uninstall").call(); + final String out = Helm.uninstall("uninstall").withKubeConfig(kubeConfigFile).call(); assertThat(out).contains( "release \"uninstall\" uninstalled\n" ); @@ -385,10 +387,10 @@ void withValidRelease() { @Test void withNamespace() { - helm.install().withKubeConfig(kubeConfig).withName("uninstall-with-namespace") + helm.install().withKubeConfig(kubeConfigFile).withName("uninstall-with-namespace") .withNamespace("uninstall-with-namespace").createNamespace().call(); final String out = Helm.uninstall("uninstall-with-namespace") - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withNamespace("uninstall-with-namespace") .call(); assertThat(out).contains( @@ -398,9 +400,9 @@ void withNamespace() { @Test void withValidReleaseAndDebug() { - helm.install().withKubeConfig(kubeConfig).withName("uninstall-with-debug").call(); + helm.install().withKubeConfig(kubeConfigFile).withName("uninstall-with-debug").call(); final String out = Helm.uninstall("uninstall-with-debug") - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .debug() .call(); assertThat(out).contains( @@ -416,9 +418,9 @@ void withValidReleaseAndDebug() { @Test void withValidReleaseAndDryRunAndDebug() { - helm.install().withKubeConfig(kubeConfig).withName("uninstall-with-dry-run").call(); + helm.install().withKubeConfig(kubeConfigFile).withName("uninstall-with-dry-run").call(); final String out = Helm.uninstall("uninstall-with-dry-run") - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .dryRun() .debug() .call(); @@ -436,9 +438,9 @@ void withValidReleaseAndDryRunAndDebug() { @Test void withValidReleaseAndNoHooksAndDebug() { - helm.install().withKubeConfig(kubeConfig).withName("uninstall-with-no-hooks-debug").call(); + helm.install().withKubeConfig(kubeConfigFile).withName("uninstall-with-no-hooks-debug").call(); final String out = Helm.uninstall("uninstall-with-no-hooks-debug") - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .debug() .withCascade(UninstallCommand.Cascade.FOREGROUND) .keepHistory() @@ -462,7 +464,7 @@ void withValidReleaseAndNoHooksAndDebug() { @Test void missingReleaseWithIgnoreNotFound() { final String out = Helm.uninstall("i-was-never-created") - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .ignoreNotFound() .call(); assertThat(out).contains( @@ -477,7 +479,7 @@ class Invalid { @Test void missingRelease() { final UninstallCommand uninstall = Helm.uninstall("i-was-never-created") - .withKubeConfig(kubeConfig); + .withKubeConfig(kubeConfigFile); assertThatThrownBy(uninstall::call) .message() .isEqualTo("uninstall: Release not loaded: i-was-never-created: release: not found"); @@ -494,7 +496,7 @@ class Valid { @Test void withInstall() { final Release result = helm.upgrade() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .install() .withName("upgrade-with-install") .call(); @@ -505,9 +507,9 @@ void withInstall() { @Test void withPriorInstall() { - helm.install().withName("upgrade-prior-install").withKubeConfig(kubeConfig).call(); + helm.install().withName("upgrade-prior-install").withKubeConfig(kubeConfigFile).call(); final Release result = helm.upgrade() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("upgrade-prior-install") .call(); assertThat(result) @@ -517,9 +519,9 @@ void withPriorInstall() { @Test void withWaitReady() { - helm.install().withName("helm-upgrade-with-wait-ready").withKubeConfig(kubeConfig).call(); + helm.install().withName("helm-upgrade-with-wait-ready").withKubeConfig(kubeConfigFile).call(); final Release result = helm.upgrade() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-upgrade-with-wait-ready") .set("fullnameOverride", "helm-upgrade-with-wait-ready") .set("image.repository", "ghcr.io/linuxserver/nginx") @@ -536,9 +538,9 @@ void withWaitReady() { @Test void withWaitAndCustomTimeout() { - helm.install().withName("helm-upgrade-with-wait-ready-and-custom-timeout").withKubeConfig(kubeConfig).call(); + helm.install().withName("helm-upgrade-with-wait-ready-and-custom-timeout").withKubeConfig(kubeConfigFile).call(); final Release result = helm.upgrade() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-upgrade-with-wait-ready-and-custom-timeout") .set("fullnameOverride", "helm-upgrade-with-wait-ready-and-custom-timeout") .set("image.repository", "ghcr.io/linuxserver/nginx") @@ -561,7 +563,7 @@ class Invalid { void missingRelease() { final UpgradeCommand upgrade = helm.upgrade() .withName("upgrade-missing-release") - .withKubeConfig(kubeConfig); + .withKubeConfig(kubeConfigFile); assertThatThrownBy(upgrade::call) .message() .isEqualTo("\"upgrade-missing-release\" has no deployed releases"); @@ -569,9 +571,9 @@ void missingRelease() { @Test void lowTimeout() { - helm.install().withName("helm-upgrade-with-wait-ready-and-low-timeout").withKubeConfig(kubeConfig).call(); + helm.install().withName("helm-upgrade-with-wait-ready-and-low-timeout").withKubeConfig(kubeConfigFile).call(); final UpgradeCommand upgrade = helm.upgrade() - .withKubeConfig(kubeConfig) + .withKubeConfig(kubeConfigFile) .withName("helm-upgrade-with-wait-ready-and-low-timeout") .set("fullnameOverride", "helm-upgrade-with-wait-ready-and-low-timeout") .set("image.repository", "ghcr.io/linuxserver/nginx") diff --git a/lib/api/src/main/java/com/marcnuri/helm/jni/InstallOptions.java b/lib/api/src/main/java/com/marcnuri/helm/jni/InstallOptions.java index c8f89af1..70e0b02b 100644 --- a/lib/api/src/main/java/com/marcnuri/helm/jni/InstallOptions.java +++ b/lib/api/src/main/java/com/marcnuri/helm/jni/InstallOptions.java @@ -22,6 +22,7 @@ * @author Marc Nuri * @author Miriam Schmidt * @author Kevin J. Mckernan + * @author Christian Gebhard */ @Structure.FieldOrder({ "name", @@ -43,6 +44,7 @@ "values", "valuesFiles", "kubeConfig", + "kubeConfigContents", "certFile", "keyFile", "caFile", @@ -74,6 +76,7 @@ public class InstallOptions extends Structure { public String values; public String valuesFiles; public String kubeConfig; + public String kubeConfigContents; public String certFile; public String keyFile; public String caFile; @@ -104,6 +107,7 @@ public InstallOptions( String values, String valuesFiles, String kubeConfig, + String kubeConfigContents, String certFile, String keyFile, String caFile, @@ -133,6 +137,7 @@ public InstallOptions( this.values = values; this.valuesFiles = valuesFiles; this.kubeConfig = kubeConfig; + this.kubeConfigContents = kubeConfigContents; this.certFile = certFile; this.keyFile = keyFile; this.caFile = caFile; diff --git a/lib/api/src/main/java/com/marcnuri/helm/jni/ListOptions.java b/lib/api/src/main/java/com/marcnuri/helm/jni/ListOptions.java index 6ae9c726..16d36a8c 100644 --- a/lib/api/src/main/java/com/marcnuri/helm/jni/ListOptions.java +++ b/lib/api/src/main/java/com/marcnuri/helm/jni/ListOptions.java @@ -20,6 +20,7 @@ /** * @author Marc Nuri + * @author Christian Gebhard */ @Structure.FieldOrder({ "all", @@ -31,7 +32,8 @@ "uninstalled", "uninstalling", "namespace", - "kubeConfig" + "kubeConfig", + "kubeConfigContents" }) public class ListOptions extends Structure { public int all; @@ -44,8 +46,9 @@ public class ListOptions extends Structure { public int uninstalling; public String namespace; public String kubeConfig; + public String kubeConfigContents; - public ListOptions(int all, int allNamespaces, int deployed, int failed, int pending, int superseded, int uninstalled, int uninstalling, String namespace, String kubeConfig) { + public ListOptions(int all, int allNamespaces, int deployed, int failed, int pending, int superseded, int uninstalled, int uninstalling, String namespace, String kubeConfig, String kubeConfigContents) { this.all = all; this.allNamespaces = allNamespaces; this.deployed = deployed; @@ -56,5 +59,6 @@ public ListOptions(int all, int allNamespaces, int deployed, int failed, int pen this.uninstalling = uninstalling; this.namespace = namespace; this.kubeConfig = kubeConfig; + this.kubeConfigContents = kubeConfigContents; } } diff --git a/lib/api/src/main/java/com/marcnuri/helm/jni/TestOptions.java b/lib/api/src/main/java/com/marcnuri/helm/jni/TestOptions.java index bef0be4e..3a4f5c67 100644 --- a/lib/api/src/main/java/com/marcnuri/helm/jni/TestOptions.java +++ b/lib/api/src/main/java/com/marcnuri/helm/jni/TestOptions.java @@ -20,12 +20,14 @@ /** * @author Marc Nuri + * @author Christian Gebhard */ @Structure.FieldOrder({ "releaseName", "timeout", "namespace", "kubeConfig", + "kubeConfigContents", "debug" }) public class TestOptions extends Structure { @@ -33,6 +35,7 @@ public class TestOptions extends Structure { public int timeout; public String namespace; public String kubeConfig; + public String kubeConfigContents; public int debug; public TestOptions( @@ -40,12 +43,14 @@ public TestOptions( int timeout, String namespace, String kubeConfig, + String kubeConfigContents, int debug ) { this.releaseName = releaseName; this.timeout = timeout; this.namespace = namespace; this.kubeConfig = kubeConfig; + this.kubeConfigContents = kubeConfigContents; this.debug = debug; } diff --git a/lib/api/src/main/java/com/marcnuri/helm/jni/UninstallOptions.java b/lib/api/src/main/java/com/marcnuri/helm/jni/UninstallOptions.java index ae5d6ebf..9596bf86 100644 --- a/lib/api/src/main/java/com/marcnuri/helm/jni/UninstallOptions.java +++ b/lib/api/src/main/java/com/marcnuri/helm/jni/UninstallOptions.java @@ -20,6 +20,7 @@ /** * @author Marc Nuri + * @author Christian Gebhard */ @Structure.FieldOrder({ "releaseName", @@ -30,6 +31,7 @@ "cascade", "namespace", "kubeConfig", + "kubeConfigContents", "debug" }) public class UninstallOptions extends Structure { @@ -41,6 +43,7 @@ public class UninstallOptions extends Structure { public String cascade; public String namespace; public String kubeConfig; + public String kubeConfigContents; public int debug; public UninstallOptions( @@ -52,6 +55,7 @@ public UninstallOptions( String cascade, String namespace, String kubeConfig, + String kubeConfigContents, int debug ) { this.releaseName = releaseName; @@ -62,6 +66,7 @@ public UninstallOptions( this.cascade = cascade; this.namespace = namespace; this.kubeConfig = kubeConfig; + this.kubeConfigContents = kubeConfigContents; this.debug = debug; } } diff --git a/lib/api/src/main/java/com/marcnuri/helm/jni/UpgradeOptions.java b/lib/api/src/main/java/com/marcnuri/helm/jni/UpgradeOptions.java index 322e0f1b..b6743f83 100644 --- a/lib/api/src/main/java/com/marcnuri/helm/jni/UpgradeOptions.java +++ b/lib/api/src/main/java/com/marcnuri/helm/jni/UpgradeOptions.java @@ -22,6 +22,7 @@ * @author Marc Nuri * @author Miriam Schmidt * @author Kevin J. Mckernan + * @author Christian Gebhard */ @Structure.FieldOrder({ "name", @@ -47,6 +48,7 @@ "values", "valuesFiles", "kubeConfig", + "kubeConfigContents", "certFile", "keyFile", "caFile", @@ -81,6 +83,7 @@ public class UpgradeOptions extends Structure { public String values; public String valuesFiles; public String kubeConfig; + public String kubeConfigContents; public String certFile; public String keyFile; public String caFile; @@ -115,6 +118,7 @@ public UpgradeOptions( String values, String valuesFiles, String kubeConfig, + String kubeConfigContents, String certFile, String keyFile, String caFile, @@ -148,6 +152,7 @@ public UpgradeOptions( this.values = values; this.valuesFiles = valuesFiles; this.kubeConfig = kubeConfig; + this.kubeConfigContents = kubeConfigContents; this.certFile = certFile; this.keyFile = keyFile; this.caFile = caFile; diff --git a/native/internal/helm/clientgetter.go b/native/internal/helm/clientgetter.go deleted file mode 100644 index 02651ba1..00000000 --- a/native/internal/helm/clientgetter.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2024 Marc Nuri - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package helm - -import ( - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/client-go/discovery" - "k8s.io/client-go/discovery/cached/memory" - "k8s.io/client-go/rest" - "k8s.io/client-go/restmapper" - "k8s.io/client-go/tools/clientcmd" -) - -type SimpleRESTClientGetter struct { - Namespace string - KubeConfig string -} - -func NewRESTClientGetter(namespace, kubeConfig string) *SimpleRESTClientGetter { - return &SimpleRESTClientGetter{ - Namespace: namespace, - KubeConfig: kubeConfig, - } -} - -func (c *SimpleRESTClientGetter) ToRESTConfig() (*rest.Config, error) { - config, err := clientcmd.RESTConfigFromKubeConfig([]byte(c.KubeConfig)) - if err != nil { - return nil, err - } - return config, nil -} - -func (c *SimpleRESTClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { - config, err := c.ToRESTConfig() - if err != nil { - return nil, err - } - - // The more groups you have, the more discovery requests you need to make. - // given 25 groups (our groups + a few custom conf) with one-ish version each, discovery needs to make 50 requests - // double it just so we don't end up here again for a while. This config is only used for discovery. - config.Burst = 300 - - discoveryClient, _ := discovery.NewDiscoveryClientForConfig(config) - return memory.NewMemCacheClient(discoveryClient), nil -} - -func (c *SimpleRESTClientGetter) ToRESTMapper() (meta.RESTMapper, error) { - discoveryClient, err := c.ToDiscoveryClient() - if err != nil { - return nil, err - } - - mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) - expander := restmapper.NewShortcutExpander(mapper, discoveryClient, nil) - return expander, nil -} - -func (c *SimpleRESTClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig { - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - // use the standard defaults for this client command - // DEPRECATED: remove and replace with something more accurate - loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig - - overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} - overrides.Context.Namespace = c.Namespace - - return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) -} diff --git a/native/internal/helm/clientgetter_test.go b/native/internal/helm/clientgetter_test.go deleted file mode 100644 index cd8eb377..00000000 --- a/native/internal/helm/clientgetter_test.go +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2024 Marc Nuri - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package helm - -import ( - "reflect" - "testing" - - "k8s.io/client-go/rest" -) - -const KUBECONFIG = ` -apiVersion: v1 -clusters: -- cluster: - server: https://1.2.3.4 - name: development -contexts: -- context: - cluster: development - namespace: frontend - user: developer - name: dev-frontend -current-context: dev-frontend -kind: Config -preferences: {} -users: -- name: developer - user: - username: user - password: password -` - -func TestNewRESTClientGetter(t *testing.T) { - namespace := "default" - restClientGetter := NewRESTClientGetter(namespace, KUBECONFIG) - - if restClientGetter.KubeConfig != KUBECONFIG { - t.Errorf("Expected %s\n got %s", KUBECONFIG, restClientGetter.KubeConfig) - } - if restClientGetter.Namespace != namespace { - t.Errorf("Expected %s, got %s", namespace, restClientGetter.Namespace) - } -} - -func TestToRESTConfig(t *testing.T) { - namespace := "default" - restClientGetter := NewRESTClientGetter(namespace, KUBECONFIG) - expectedRestConfig := &rest.Config{ - Host: "https://1.2.3.4", - Username: "user", - Password: "password", - } - restConfig, err := restClientGetter.ToRESTConfig() - if err != nil { - t.Errorf("Expected converting to succeed, got %s", err) - } - - if !reflect.DeepEqual(restConfig, expectedRestConfig) { - t.Errorf("Expected %s, got %s", expectedRestConfig, restConfig) - } -} diff --git a/native/internal/helm/envtest_test.go b/native/internal/helm/envtest_test.go index c8a5459a..b5213e89 100644 --- a/native/internal/helm/envtest_test.go +++ b/native/internal/helm/envtest_test.go @@ -244,6 +244,36 @@ func TestList(t *testing.T) { } } +func TestListUsingKubeConfigContents(t *testing.T) { + cleanUp, kubeConfigFile := setupEnvTest() + defer cleanUp() + kubeConfigContents, _ := os.ReadFile(kubeConfigFile.Name()) + create, _ := Create(&CreateOptions{ + Name: "test-list", + Dir: t.TempDir(), + }) + _, _ = Install(&InstallOptions{ + KubeConfigContents: string(kubeConfigContents), + Chart: create, + Name: "test-list", + }) + out, err := List(&ListOptions{ + KubeConfig: kubeConfigFile.Name(), + }) + if err != nil { + t.Errorf("Expected list to succeed, got %s", err) + return + } + if !strings.Contains(out, "name=test-list") { + t.Errorf("Expected list to include test-list, got %s", out) + return + } + if !strings.Contains(out, "chart=test-list-0.1.0") { + t.Errorf("Expected list to include test-list, got %s", out) + return + } +} + func TestTest(t *testing.T) { cleanUp, kubeConfigFile := setupEnvTest() defer cleanUp() diff --git a/native/internal/helm/helm.go b/native/internal/helm/helm.go index ac82b44c..fd662472 100644 --- a/native/internal/helm/helm.go +++ b/native/internal/helm/helm.go @@ -20,6 +20,9 @@ import ( "bytes" "fmt" "io" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" "os" "strings" "time" @@ -32,15 +35,15 @@ import ( "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v3/pkg/release" - "k8s.io/cli-runtime/pkg/genericclioptions" ) type CfgOptions struct { - RegistryClient *registry.Client - KubeConfig string - Namespace string - AllNamespaces bool - KubeOut io.Writer + RegistryClient *registry.Client + KubeConfig string + KubeConfigContents string + Namespace string + AllNamespaces bool + KubeOut io.Writer } type CertOptions struct { @@ -52,8 +55,6 @@ type CertOptions struct { Keyring string } -const KUBECONFIG_IDENTIFIER = "kind: Config" - func NewCfg(options *CfgOptions) *action.Configuration { settings := cli.New() settings.KubeConfig = options.KubeConfig @@ -70,11 +71,17 @@ func NewCfg(options *CfgOptions) *action.Configuration { if options.AllNamespaces { effectiveNamespace = "" } - var restClientGetter genericclioptions.RESTClientGetter - if isKubeConfig(options.KubeConfig) { - restClientGetter = NewRESTClientGetter(effectiveNamespace, options.KubeConfig) - } else { - restClientGetter = settings.RESTClientGetter() + restClientGetter := settings.RESTClientGetter() + restClientGetter.(*genericclioptions.ConfigFlags).WrapConfigFn = func(original *rest.Config) *rest.Config { + if options.KubeConfigContents != "" { + // TODO: we could actually merge both kubeconfigs + config, err := clientcmd.RESTConfigFromKubeConfig([]byte(options.KubeConfigContents)) + if err != nil { + panic(err) + } + return config + } + return original } err := actionConfig.Init(restClientGetter, effectiveNamespace, os.Getenv("HELM_DRIVER"), log) if err != nil { @@ -191,7 +198,3 @@ func repositoryConfig(options *RepoOptions) string { return options.RepositoryConfig } } - -func isKubeConfig(potentialConfig string) bool { - return strings.Contains(potentialConfig, KUBECONFIG_IDENTIFIER) -} diff --git a/native/internal/helm/helm_test.go b/native/internal/helm/helm_test.go index 38707c61..11620e52 100644 --- a/native/internal/helm/helm_test.go +++ b/native/internal/helm/helm_test.go @@ -17,41 +17,46 @@ package helm import ( - "reflect" "testing" - - "k8s.io/cli-runtime/pkg/genericclioptions" ) -func TestNewCfgKubeConfigContent(t *testing.T) { - cfg := NewCfg(&CfgOptions{ - RegistryClient: nil, - KubeConfig: KUBECONFIG, - Namespace: "default", - AllNamespaces: false, - KubeOut: nil, - }) - expectedGetter := NewRESTClientGetter("default", KUBECONFIG) - - if !reflect.DeepEqual(cfg.RESTClientGetter, expectedGetter) { - t.Errorf("Expected %s, got %s", expectedGetter, cfg.RESTClientGetter) - return - } -} +const kubeConfigContentsForTests = ` +apiVersion: v1 +clusters: +- cluster: + server: https://host.example.com + name: development +contexts: +- context: + cluster: development + namespace: the-namespace + user: developer + name: kube-config-test-contents +current-context: kube-config-test-contents +kind: Config +preferences: {} +users: +- name: developer + user: + username: test-user + password: test-password +` -func TestNewCfgKubeConfigPath(t *testing.T) { - path := "/path/to/kubeconfig" +func TestNewCfg_KubeConfigContents(t *testing.T) { cfg := NewCfg(&CfgOptions{ - RegistryClient: nil, - KubeConfig: path, - Namespace: "default", - AllNamespaces: false, - KubeOut: nil, + KubeConfigContents: kubeConfigContentsForTests, }) - expectedGetter := &genericclioptions.ConfigFlags{} - - if reflect.TypeOf(cfg.RESTClientGetter) != reflect.TypeOf(expectedGetter) { - t.Errorf("Expected type %v \n got %v", reflect.TypeOf(expectedGetter), reflect.TypeOf(cfg.RESTClientGetter)) - return + restConfig, err := cfg.RESTClientGetter.ToRESTConfig() + if err != nil { + t.Fatalf("Expected converting to succeed, got %s", err) + } + if restConfig.Host != "https://host.example.com" { + t.Fatalf("Expected https://host.example.com, got %s", restConfig.Host) + } + if restConfig.Username != "test-user" { + t.Fatalf("Expected test-user, got %s", restConfig.Username) + } + if restConfig.Password != "test-password" { + t.Fatalf("Expected test-password, got %s", restConfig.Password) } } diff --git a/native/internal/helm/install.go b/native/internal/helm/install.go index 2df6cf1c..9a5cf7e1 100644 --- a/native/internal/helm/install.go +++ b/native/internal/helm/install.go @@ -58,6 +58,7 @@ type InstallOptions struct { Values string ValuesFiles string KubeConfig string + KubeConfigContents string Debug bool // For testing purposes only, prevents connecting to Kubernetes (happens even with DryRun=true and DryRunOption=client) ClientOnly bool @@ -97,9 +98,10 @@ func install(options *InstallOptions) (*release.Release, *installOutputs, error) return nil, outputs, err } cfgOptions := &CfgOptions{ - RegistryClient: registryClient, - KubeConfig: options.KubeConfig, - Namespace: options.Namespace, + RegistryClient: registryClient, + KubeConfig: options.KubeConfig, + KubeConfigContents: options.KubeConfigContents, + Namespace: options.Namespace, } if options.Debug { cfgOptions.KubeOut = outputs.kubeOut diff --git a/native/internal/helm/list.go b/native/internal/helm/list.go index b73aded9..0980982f 100644 --- a/native/internal/helm/list.go +++ b/native/internal/helm/list.go @@ -26,23 +26,25 @@ import ( ) type ListOptions struct { - All bool - AllNamespaces bool - Deployed bool - Failed bool - Pending bool - Superseded bool - Uninstalled bool - Uninstalling bool - Namespace string - KubeConfig string + All bool + AllNamespaces bool + Deployed bool + Failed bool + Pending bool + Superseded bool + Uninstalled bool + Uninstalling bool + Namespace string + KubeConfig string + KubeConfigContents string } func List(options *ListOptions) (string, error) { cfg := NewCfg(&CfgOptions{ - KubeConfig: options.KubeConfig, - Namespace: options.Namespace, - AllNamespaces: options.AllNamespaces, + KubeConfig: options.KubeConfig, + KubeConfigContents: options.KubeConfigContents, + Namespace: options.Namespace, + AllNamespaces: options.AllNamespaces, }) client := action.NewList(cfg) client.All = options.All diff --git a/native/internal/helm/test.go b/native/internal/helm/test.go index 75efdab6..582dc0bf 100644 --- a/native/internal/helm/test.go +++ b/native/internal/helm/test.go @@ -22,17 +22,19 @@ import ( ) type TestOptions struct { - ReleaseName string - Timeout time.Duration - Namespace string - KubeConfig string - Debug bool + ReleaseName string + Timeout time.Duration + Namespace string + KubeConfig string + KubeConfigContents string + Debug bool } func Test(options *TestOptions) (string, error) { cfgOptions := &CfgOptions{ - KubeConfig: options.KubeConfig, - Namespace: options.Namespace, + KubeConfig: options.KubeConfig, + KubeConfigContents: options.KubeConfigContents, + Namespace: options.Namespace, } client := action.NewReleaseTesting(NewCfg(cfgOptions)) client.Namespace = options.Namespace diff --git a/native/internal/helm/uninstall.go b/native/internal/helm/uninstall.go index 57a0dff9..3194a667 100644 --- a/native/internal/helm/uninstall.go +++ b/native/internal/helm/uninstall.go @@ -23,21 +23,23 @@ import ( ) type UninstallOptions struct { - ReleaseName string - DryRun bool - NoHooks bool - IgnoreNotFound bool - KeepHistory bool - Cascade string - Namespace string - KubeConfig string - Debug bool + ReleaseName string + DryRun bool + NoHooks bool + IgnoreNotFound bool + KeepHistory bool + Cascade string + Namespace string + KubeConfig string + KubeConfigContents string + Debug bool } func Uninstall(options *UninstallOptions) (string, error) { cfgOptions := &CfgOptions{ - KubeConfig: options.KubeConfig, - Namespace: options.Namespace, + KubeConfig: options.KubeConfig, + KubeConfigContents: options.KubeConfigContents, + Namespace: options.Namespace, } kubeOut := bytes.NewBuffer(make([]byte, 0)) if options.Debug { diff --git a/native/internal/helm/upgrade.go b/native/internal/helm/upgrade.go index 1cb51684..c661345c 100644 --- a/native/internal/helm/upgrade.go +++ b/native/internal/helm/upgrade.go @@ -49,6 +49,7 @@ type UpgradeOptions struct { Values string ValuesFiles string KubeConfig string + KubeConfigContents string Debug bool // For testing purposes only, prevents connecting to Kubernetes (happens even with DryRun=true and DryRunOption=client) ClientOnly bool @@ -69,9 +70,10 @@ func Upgrade(options *UpgradeOptions) (string, error) { } kubeOut := bytes.NewBuffer(make([]byte, 0)) cfgOptions := &CfgOptions{ - RegistryClient: registryClient, - KubeConfig: options.KubeConfig, - Namespace: options.Namespace, + RegistryClient: registryClient, + KubeConfig: options.KubeConfig, + KubeConfigContents: options.KubeConfigContents, + Namespace: options.Namespace, } if options.Debug { cfgOptions.KubeOut = kubeOut diff --git a/native/main.go b/native/main.go index 7f739059..0027dfa0 100644 --- a/native/main.go +++ b/native/main.go @@ -60,6 +60,7 @@ struct InstallOptions { char* values; char* valuesFiles; char* kubeConfig; + char* kubeConfigContents; char* certFile; char* keyFile; char* caFile; @@ -88,6 +89,7 @@ struct ListOptions { int uninstalling; char* namespace; char* kubeConfig; + char* kubeConfigContents; }; struct PackageOptions { @@ -184,6 +186,7 @@ struct TestOptions { int timeout; char* namespace; char* kubeConfig; + char* kubeConfigContents; int debug; }; @@ -196,6 +199,7 @@ struct UninstallOptions { char* cascade; char* namespace; char* kubeConfig; + char* kubeConfigContents; int debug; }; @@ -223,6 +227,7 @@ struct UpgradeOptions { char* values; char* valuesFiles; char* kubeConfig; + char* kubeConfigContents; char* certFile; char* keyFile; char* caFile; @@ -353,6 +358,7 @@ func Install(options *C.struct_InstallOptions) C.Result { Values: C.GoString(options.values), ValuesFiles: C.GoString(options.valuesFiles), KubeConfig: C.GoString(options.kubeConfig), + KubeConfigContents: C.GoString(options.kubeConfigContents), CertOptions: helm.CertOptions{ CertFile: C.GoString(options.certFile), KeyFile: C.GoString(options.keyFile), @@ -386,16 +392,17 @@ func Lint(options *C.struct_LintOptions) C.Result { func List(options *C.struct_ListOptions) C.Result { return runCommand(func() (string, error) { return helm.List(&helm.ListOptions{ - All: options.all == 1, - AllNamespaces: options.allNamespaces == 1, - Deployed: options.deployed == 1, - Failed: options.failed == 1, - Pending: options.pending == 1, - Superseded: options.superseded == 1, - Uninstalled: options.uninstalled == 1, - Uninstalling: options.uninstalling == 1, - Namespace: C.GoString(options.namespace), - KubeConfig: C.GoString(options.kubeConfig), + All: options.all == 1, + AllNamespaces: options.allNamespaces == 1, + Deployed: options.deployed == 1, + Failed: options.failed == 1, + Pending: options.pending == 1, + Superseded: options.superseded == 1, + Uninstalled: options.uninstalled == 1, + Uninstalling: options.uninstalling == 1, + Namespace: C.GoString(options.namespace), + KubeConfig: C.GoString(options.kubeConfig), + KubeConfigContents: C.GoString(options.kubeConfigContents), }) }) } @@ -626,11 +633,12 @@ func Test(options *C.struct_TestOptions) C.Result { } return runCommand(func() (string, error) { return helm.Test(&helm.TestOptions{ - ReleaseName: C.GoString(options.releaseName), - Namespace: C.GoString(options.namespace), - KubeConfig: C.GoString(options.kubeConfig), - Timeout: timeout, - Debug: options.debug == 1, + ReleaseName: C.GoString(options.releaseName), + Namespace: C.GoString(options.namespace), + KubeConfig: C.GoString(options.kubeConfig), + KubeConfigContents: C.GoString(options.kubeConfigContents), + Timeout: timeout, + Debug: options.debug == 1, }) }) } @@ -639,15 +647,16 @@ func Test(options *C.struct_TestOptions) C.Result { func Uninstall(options *C.struct_UninstallOptions) C.Result { return runCommand(func() (string, error) { return helm.Uninstall(&helm.UninstallOptions{ - ReleaseName: C.GoString(options.releaseName), - DryRun: options.dryRun == 1, - NoHooks: options.noHooks == 1, - IgnoreNotFound: options.ignoreNotFound == 1, - KeepHistory: options.keepHistory == 1, - Cascade: C.GoString(options.cascade), - Namespace: C.GoString(options.namespace), - KubeConfig: C.GoString(options.kubeConfig), - Debug: options.debug == 1, + ReleaseName: C.GoString(options.releaseName), + DryRun: options.dryRun == 1, + NoHooks: options.noHooks == 1, + IgnoreNotFound: options.ignoreNotFound == 1, + KeepHistory: options.keepHistory == 1, + Cascade: C.GoString(options.cascade), + Namespace: C.GoString(options.namespace), + KubeConfig: C.GoString(options.kubeConfig), + KubeConfigContents: C.GoString(options.kubeConfigContents), + Debug: options.debug == 1, }) }) } @@ -685,6 +694,7 @@ func Upgrade(options *C.struct_UpgradeOptions) C.Result { Values: C.GoString(options.values), ValuesFiles: C.GoString(options.valuesFiles), KubeConfig: C.GoString(options.kubeConfig), + KubeConfigContents: C.GoString(options.kubeConfigContents), CertOptions: helm.CertOptions{ CertFile: C.GoString(options.certFile), KeyFile: C.GoString(options.keyFile),