/
config_factory.go
134 lines (107 loc) · 3.46 KB
/
config_factory.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
130
131
132
133
134
// Copyright 2024 The Carvel Authors.
// SPDX-License-Identifier: Apache-2.0
package core
import (
"fmt"
"net"
"os"
"strings"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
type ConfigFactory interface {
ConfigurePathResolver(func() (string, error))
ConfigureContextResolver(func() (string, error))
ConfigureYAMLResolver(func() (string, error))
ConfigureClient(float32, int)
RESTConfig() (*rest.Config, error)
DefaultNamespace() (string, error)
}
type ConfigFactoryImpl struct {
pathResolverFunc func() (string, error)
contextResolverFunc func() (string, error)
yamlResolverFunc func() (string, error)
qps float32
burst int
}
var _ ConfigFactory = &ConfigFactoryImpl{}
func NewConfigFactoryImpl() *ConfigFactoryImpl {
return &ConfigFactoryImpl{}
}
func (f *ConfigFactoryImpl) ConfigurePathResolver(resolverFunc func() (string, error)) {
f.pathResolverFunc = resolverFunc
}
func (f *ConfigFactoryImpl) ConfigureContextResolver(resolverFunc func() (string, error)) {
f.contextResolverFunc = resolverFunc
}
func (f *ConfigFactoryImpl) ConfigureYAMLResolver(resolverFunc func() (string, error)) {
f.yamlResolverFunc = resolverFunc
}
func (f *ConfigFactoryImpl) ConfigureClient(qps float32, burst int) {
f.qps = qps
f.burst = burst
}
func (f *ConfigFactoryImpl) RESTConfig() (*rest.Config, error) {
isExplicitYAMLConfig, config, err := f.clientConfig()
if err != nil {
return nil, err
}
restConfig, err := config.ClientConfig()
if err != nil {
prefixMsg := ""
if isExplicitYAMLConfig {
prefixMsg = " (explicit config given)"
}
hintMsg := ""
if strings.Contains(err.Error(), "no configuration has been provided") {
hintMsg = "Ensure cluster name is specified correctly in context configuration"
}
if len(hintMsg) > 0 {
hintMsg = " (hint: " + hintMsg + ")"
}
return nil, fmt.Errorf("Building Kubernetes config%s: %s%s", prefixMsg, err, hintMsg)
}
if f.qps > 0.0 {
restConfig.QPS = f.qps
restConfig.Burst = f.burst
}
return restConfig, nil
}
func (f *ConfigFactoryImpl) DefaultNamespace() (string, error) {
_, config, err := f.clientConfig()
if err != nil {
return "", err
}
name, _, err := config.Namespace()
return name, err
}
func (f *ConfigFactoryImpl) clientConfig() (bool, clientcmd.ClientConfig, error) {
path, err := f.pathResolverFunc()
if err != nil {
return false, nil, fmt.Errorf("Resolving config path: %s", err)
}
context, err := f.contextResolverFunc()
if err != nil {
return false, nil, fmt.Errorf("Resolving config context: %s", err)
}
configYAML, err := f.yamlResolverFunc()
if err != nil {
return false, nil, fmt.Errorf("Resolving config YAML: %s", err)
}
if len(configYAML) > 0 {
envHostPort := net.JoinHostPort(os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT"))
configYAML = strings.ReplaceAll(configYAML, "${KCTRL_KUBERNETES_SERVICE_HOST_PORT}", envHostPort)
config, err := clientcmd.NewClientConfigFromBytes([]byte(configYAML))
return true, config, err
}
// Based on https://github.com/kubernetes/kubernetes/blob/30c7df5cd822067016640aa267714204ac089172/staging/src/k8s.io/cli-runtime/pkg/genericclioptions/config_flags.go#L124
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
overrides := &clientcmd.ConfigOverrides{}
if len(path) > 0 {
loadingRules.ExplicitPath = path
}
if len(context) > 0 {
overrides.CurrentContext = context
}
return false, clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides), nil
}