Skip to content

Commit 9b5b1a7

Browse files
committed
Support provided contexts
Allow users to provide an explicit k8s context. While at it, rely on clientcmd provided code to load the configuration.
1 parent b48989c commit 9b5b1a7

File tree

5 files changed

+28
-45
lines changed

5 files changed

+28
-45
lines changed

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ will help to keep resources usage low, and a concise git history. Eg.:
3535
# confidential), events and node (irrelevant), and the leader-elector
3636
# configmap that has low value and changes a lot, causing commits churn.
3737

38-
katafygio \
39-
-g https://user:[email protected]/myorg/myrepos.git -e /tmp/kfdump \
40-
-x secret -x pod -x replicaset -x node -x endpoints -x event \
38+
katafygio -e /tmp/kfdump \
39+
-g https://user:[email protected]/myorg/myrepos.git \
40+
-x secret,pod,event,replicaset,node,endpoints \
4141
-y configmap:kube-system/leader-elector
4242
```
4343

@@ -60,6 +60,7 @@ Available Commands:
6060
Flags:
6161
-s, --api-server string Kubernetes api-server url
6262
-c, --config string Configuration file (default "/etc/katafygio/katafygio.yaml")
63+
-q, --context string Kubernetes configuration context
6364
-d, --dry-run Dry-run mode: don't store anything
6465
-m, --dump-only Dump mode: dump everything once and exit
6566
-x, --exclude-kind strings Ressource kind to exclude. Eg. 'deployment'

cmd/execute.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func runE(cmd *cobra.Command, args []string) (err error) {
4747
logger.Info(appName, " starting")
4848

4949
if restcfg == nil {
50-
restcfg, err = client.New(apiServer, kubeConf)
50+
restcfg, err = client.New(apiServer, context, kubeConf)
5151
if err != nil {
5252
return fmt.Errorf("failed to create a client: %v", err)
5353
}

cmd/flags.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
var (
1212
cfgFile string
1313
apiServer string
14+
context string
1415
kubeConf string
1516
dryRun bool
1617
dumpMode bool
@@ -44,7 +45,10 @@ func init() {
4445
RootCmd.PersistentFlags().StringVarP(&apiServer, "api-server", "s", "", "Kubernetes api-server url")
4546
bindPFlag("api-server", "api-server")
4647

47-
RootCmd.PersistentFlags().StringVarP(&kubeConf, "kube-config", "k", "", "Kubernetes config path")
48+
RootCmd.PersistentFlags().StringVarP(&context, "context", "q", "", "Kubernetes configuration context")
49+
bindPFlag("context", "context")
50+
51+
RootCmd.PersistentFlags().StringVarP(&kubeConf, "kube-config", "k", "", "Kubernetes configuration path")
4852
bindPFlag("kube-config", "kube-config")
4953
if err := viper.BindEnv("kube-config", "KUBECONFIG"); err != nil {
5054
log.Fatal("Failed to bind cli argument:", err)

pkg/client/client.go

+14-36
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ package client
33

44
import (
55
"fmt"
6-
"os"
7-
"path/filepath"
86

97
"k8s.io/client-go/rest"
108
"k8s.io/client-go/tools/clientcmd"
11-
"k8s.io/client-go/util/homedir"
9+
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
1210

1311
// Ensure we have auth plugins (gcp, azure, openstack, ...) linked in
1412
_ "k8s.io/client-go/plugin/pkg/client/auth"
@@ -25,48 +23,28 @@ type RestClient struct {
2523
}
2624

2725
// New create a new RestClient
28-
func New(apiserver, kubeconfig string) (*RestClient, error) {
29-
cfg, err := newRestConfig(apiserver, kubeconfig)
26+
func New(apiserver, context, kubeconfig string) (*RestClient, error) {
27+
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
28+
loadingRules.ExplicitPath = kubeconfig
29+
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
30+
loadingRules,
31+
&clientcmd.ConfigOverrides{
32+
ClusterInfo: clientcmdapi.Cluster{Server: apiserver},
33+
CurrentContext: context,
34+
},
35+
)
36+
37+
restConfig, err := clientConfig.ClientConfig()
3038
if err != nil {
3139
return nil, fmt.Errorf("failed to build a restconfig: %v", err)
3240
}
3341

3442
return &RestClient{
35-
cfg: cfg,
43+
cfg: restConfig,
3644
}, nil
3745
}
3846

3947
// GetRestConfig returns the current rest.Config
4048
func (r *RestClient) GetRestConfig() *rest.Config {
4149
return r.cfg
4250
}
43-
44-
// newRestConfig create a *rest.Config, trying to mimic kubectl behavior:
45-
// - Explicit user provided api-server (and/or kubeconfig path) have higher priorities
46-
// - Else, use the config file path in KUBECONFIG environment variable (if any)
47-
// - Else, use the config file in ~/.kube/config, if any
48-
// - Else, consider we're running in cluster (in a pod), and use the pod's service
49-
// account and cluster's kubernetes.default service.
50-
func newRestConfig(apiserver string, kubeconfig string) (*rest.Config, error) {
51-
// if not passed as an argument, kubeconfig can be provided as env var
52-
if kubeconfig == "" {
53-
kubeconfig = os.Getenv("KUBECONFIG")
54-
}
55-
56-
// if we're not provided an explicit kubeconfig path (via env, or argument),
57-
// try to find one at the standard place (in user's home/.kube/config).
58-
homeCfg := filepath.Join(homedir.HomeDir(), ".kube", "config")
59-
_, err := os.Stat(homeCfg)
60-
if kubeconfig == "" && err == nil {
61-
kubeconfig = homeCfg
62-
}
63-
64-
// if we were provided or found a kubeconfig,
65-
// or if we were provided an api-server url, use that
66-
if apiserver != "" || kubeconfig != "" {
67-
return clientcmd.BuildConfigFromFlags(apiserver, kubeconfig)
68-
}
69-
70-
// else assume we're running in a pod, in cluster
71-
return rest.InClusterConfig()
72-
}

pkg/client/client_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,28 @@ const nonExistentPath = "\\/non / existent / $path$"
1111
func TestClientSet(t *testing.T) {
1212
here, _ := os.Getwd()
1313
_ = os.Setenv("HOME", here+"/../../assets")
14-
cs, err := New("", "")
14+
cs, err := New("", "", "")
1515
if err != nil {
1616
t.Fatal(err)
1717
}
1818
if fmt.Sprintf("%T", cs.GetRestConfig()) != "*rest.Config" {
1919
t.Errorf("GetRestConfig() didn't return a *rest.Config: %T", cs)
2020
}
2121

22-
cs, _ = New("http://127.0.0.1", "/dev/null")
22+
cs, _ = New("http://127.0.0.1", "", "/dev/null")
2323
if fmt.Sprintf("%T", cs.GetRestConfig()) != "*rest.Config" {
2424
t.Errorf("New(server) didn't return a *rest.Config: %T", cs)
2525
}
2626

27-
_, err = New("http://127.0.0.1", nonExistentPath)
27+
_, err = New("http://127.0.0.1", "", nonExistentPath)
2828
if err == nil {
2929
t.Fatal("New() should fail on non existent kubeconfig path")
3030
}
3131

3232
_ = os.Unsetenv("KUBERNETES_SERVICE_HOST")
3333
_ = os.Setenv("HOME", nonExistentPath)
3434
_ = os.Setenv("KUBECONFIG", nonExistentPath)
35-
_, err = New("", "")
35+
_, err = New("", "", "")
3636
if err == nil {
3737
t.Fatal("New() should fail to load InClusterConfig without kube address env")
3838
}

0 commit comments

Comments
 (0)