-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
context.go
129 lines (108 loc) · 4.34 KB
/
context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
Copyright 2019 The Skaffold Authors
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 context
import (
"context"
"fmt"
"sync"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/output/log"
)
// For testing
var (
CurrentConfig = getCurrentConfig
)
var (
kubeConfigOnce sync.Once
kubeConfig clientcmd.ClientConfig
configureOnce sync.Once
kubeContext string
kubeConfigFile string
)
// ConfigureKubeConfig sets an override for the current context in the k8s config.
// When given, the firstCliValue always takes precedence over the yamlValue.
// Changing the kube-context of a running Skaffold process is not supported, so
// after the first call, the kube-context will be locked.
func ConfigureKubeConfig(cliKubeConfig, cliKubeContext string) {
configureOnce.Do(func() {
kubeContext = cliKubeContext
kubeConfigFile = cliKubeConfig
if kubeContext != "" {
log.Entry(context.TODO()).Infof("Activated kube-context %q", kubeContext)
}
})
}
// GetDefaultRestClientConfig returns a REST client config for API calls against the Kubernetes API.
// If ConfigureKubeConfig was called before, the CurrentContext will be overridden.
// The kubeconfig used will be cached for the life of the skaffold process after the first call.
// If the CurrentContext is empty and the resulting config is empty, this method attempts to
// create a RESTClient with an in-cluster config.
func GetDefaultRestClientConfig() (*restclient.Config, error) {
return getRestClientConfig(kubeContext, kubeConfigFile)
}
// GetRestClientConfig returns a REST client config for API calls against the Kubernetes API for the given context.
func GetRestClientConfig(kubeContext string) (*restclient.Config, error) {
return getRestClientConfig(kubeContext, kubeConfigFile)
}
// GetClusterInfo returns the Cluster information for the given kubeContext
func GetClusterInfo(kctx string) (*clientcmdapi.Cluster, error) {
rawConfig, err := getCurrentConfig()
if err != nil {
return nil, err
}
c, found := rawConfig.Clusters[kctx]
if !found {
return nil, fmt.Errorf("failed to get cluster info for kubeContext: `%s`", kctx)
}
return c, nil
}
func getRestClientConfig(kctx string, kcfg string) (*restclient.Config, error) {
log.Entry(context.TODO()).Debugf("getting client config for kubeContext: `%s`", kctx)
rawConfig, err := getCurrentConfig()
if err != nil {
return nil, err
}
clientConfig := clientcmd.NewNonInteractiveClientConfig(rawConfig, kctx, &clientcmd.ConfigOverrides{CurrentContext: kctx}, clientcmd.NewDefaultClientConfigLoadingRules())
restConfig, err := clientConfig.ClientConfig()
if kctx == "" && kcfg == "" && clientcmd.IsEmptyConfig(err) {
log.Entry(context.TODO()).Debug("no kube-context set and no kubeConfig found, attempting in-cluster config")
restConfig, err := restclient.InClusterConfig()
if err != nil {
return restConfig, fmt.Errorf("error creating REST client config in-cluster: %w", err)
}
return restConfig, nil
}
if err != nil {
return restConfig, fmt.Errorf("error creating REST client config for kubeContext %q: %w", kctx, err)
}
return restConfig, nil
}
// getCurrentConfig retrieves and caches the raw kubeConfig. The cache ensures that Skaffold always works with the identical kubeconfig,
// even if it was changed on disk.
func getCurrentConfig() (clientcmdapi.Config, error) {
kubeConfigOnce.Do(func() {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
loadingRules.ExplicitPath = kubeConfigFile
kubeConfig = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{
CurrentContext: kubeContext,
})
})
cfg, err := kubeConfig.RawConfig()
if kubeContext != "" {
// RawConfig does not respect the override in kubeConfig
cfg.CurrentContext = kubeContext
}
return cfg, err
}