Backup Kube Config to Helm Config Directory

Backup kubeconfig to <helm-config-path>/kubeconfig
during initialization of subcommands (env, install, etc.)
The backup file will have rw permissions for user.
All subcommands will then use backup kubeconfig file.

Signed-off-by: Bhargav Ravuri <bhargav.ravuri@infracloud.io>
pull/11908/head
Bhargav Ravuri 1 year ago
parent d27d1bde4c
commit 80224849cd
No known key found for this signature in database
GPG Key ID: B551A0E55CDF8320

@ -72,6 +72,18 @@ func main() {
// run when each command's execute method is called
cobra.OnInitialize(func() {
helmDriver := os.Getenv("HELM_DRIVER")
if settings.KubeConfig != "" {
// If KubeConfig path is not empty, backup kube config to: <helm-config-path>/kubeconfig
// When the backup is successful, the settings.KubeConfig path is updated to backup file's path.
err = settings.BackupKubeConfig()
if err != nil {
log.Fatal(err)
}
} else {
debug("kube config backup aborted due to empty KubeConfig path in settings")
}
if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug); err != nil {
log.Fatal(err)
}

@ -27,6 +27,7 @@ import (
"fmt"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
@ -34,6 +35,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest"
"helm.sh/helm/v3/internal/fileutil"
"helm.sh/helm/v3/internal/version"
"helm.sh/helm/v3/pkg/helmpath"
)
@ -235,3 +237,41 @@ func (s *EnvSettings) SetNamespace(namespace string) {
func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter {
return s.config
}
// BackupKubeConfig copies kube config file to <helm-config-path>/kubeconfig
// as backup. The backup file will have rw permissions for user.
// The backup file's path is updated in EnvSettings.KubeConfig.
//
// There is no safety check on EnvSettings.KubeConfig, i.e., the caller
// should call this method only when there is kube config path specified.
// Else, the actual kubeconfig file read fails.
func (s *EnvSettings) BackupKubeConfig() error {
// Form the backup file path as: <helm-config-path>/kubeconfig
// The helm-config-path is derived from envs HELM_CONFIG_HOME,
// XDG_CONFIG_HOME and default path. Defaults paths:
// - Linux : $HOME/.config/helm
// - Mac : $HOME/Library/Preferences/helm
// - Windows : %APPDATA%\helm
helmConfigPath := helmpath.ConfigPath("")
kubeConfigBackupFilename := filepath.Join(helmConfigPath, "kubeconfig")
// Create reader from actual kube config file
kubeConfigReader, err := os.Open(s.KubeConfig)
if err != nil {
return fmt.Errorf("failed to read input kubeconfig file %q: %v",
s.KubeConfig, err)
}
defer kubeConfigReader.Close()
// Copy actual kube config file to backup file
err = fileutil.AtomicWriteFile(kubeConfigBackupFilename, kubeConfigReader, 0600)
if err != nil {
return fmt.Errorf("failed to copy kubeconfig from %q to %q: %v",
s.KubeConfig, kubeConfigBackupFilename, err)
}
// Update the kube config in EnvSettings to backup file path
s.KubeConfig = kubeConfigBackupFilename
return nil
}

@ -263,3 +263,87 @@ func resetEnv() func() {
}
}
}
func TestEnvSettings_BackupKubeConfig(t *testing.T) {
var (
testDataDir = `testdata/`
kubeConfigFilename = testDataDir + "kubeconfig"
)
type fields struct {
KubeConfig string
helmConfigHome string
}
type toggles struct {
wantErr bool
cleanUpTestKubeConfig bool
}
type testCase struct {
name string
fields fields
toggles toggles
}
tests := []testCase{
{
name: "Backup kube config",
fields: fields{
KubeConfig: testDataDir + `valid-kubeconfig-no-contexts`,
helmConfigHome: testDataDir,
},
toggles: toggles{
cleanUpTestKubeConfig: true,
},
},
{
name: "Failure missing input kube config file",
fields: fields{
KubeConfig: testDataDir + `missing-kubeconfig`,
helmConfigHome: testDataDir,
},
toggles: toggles{
wantErr: true,
},
},
{
name: "Failure invalid destination path",
fields: fields{
KubeConfig: testDataDir + `valid-kubeconfig-no-contexts`,
helmConfigHome: testDataDir + `non-existing-dir/`,
},
toggles: toggles{
wantErr: true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &EnvSettings{
KubeConfig: tt.fields.KubeConfig,
}
t.Setenv(`HELM_CONFIG_HOME`, tt.fields.helmConfigHome)
err := s.BackupKubeConfig()
if (err != nil) != tt.toggles.wantErr {
t.Errorf("EnvSettings.BackupKubeConfig() error = %v, wantErr %v",
err, tt.toggles.wantErr)
}
if !tt.toggles.wantErr && s.KubeConfig != kubeConfigFilename {
t.Errorf("kube config path not updated after backup, want = %s, got = %s",
kubeConfigFilename, s.KubeConfig)
}
if tt.toggles.cleanUpTestKubeConfig {
err = os.Remove(kubeConfigFilename)
if err != nil {
t.Errorf("failed to delete %q: %v", kubeConfigFilename, err)
}
}
})
}
}

@ -0,0 +1,11 @@
apiVersion: v1
clusters: null
contexts: null
current-context: ""
kind: Config
preferences: {}
users:
- name: kubeuser/
user:
password: password
username: user
Loading…
Cancel
Save