1
16
17 package client
18
19 import (
20 "context"
21 "fmt"
22 "net/http"
23 "strconv"
24 "time"
25
26 v1 "k8s.io/api/core/v1"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/types"
29 "k8s.io/apiserver/pkg/server/egressselector"
30 "k8s.io/client-go/transport"
31 nodeutil "k8s.io/kubernetes/pkg/util/node"
32 )
33
34
35 type KubeletClientConfig struct {
36
37 Port uint
38
39
40 ReadOnlyPort uint
41
42
43 PreferredAddressTypes []string
44
45
46 TLSClientConfig KubeletTLSConfig
47
48
49 HTTPTimeout time.Duration
50
51
52 Lookup egressselector.Lookup
53 }
54
55 type KubeletTLSConfig struct {
56
57 CertFile string
58
59 KeyFile string
60
61 CAFile string
62 }
63
64
65 type ConnectionInfo struct {
66 Scheme string
67 Hostname string
68 Port string
69 Transport http.RoundTripper
70 InsecureSkipTLSVerifyTransport http.RoundTripper
71 }
72
73
74 type ConnectionInfoGetter interface {
75 GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*ConnectionInfo, error)
76 }
77
78
79 func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
80 return makeTransport(config, false)
81 }
82
83
84 func MakeInsecureTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
85 return makeTransport(config, true)
86 }
87
88
89 func makeTransport(config *KubeletClientConfig, insecureSkipTLSVerify bool) (http.RoundTripper, error) {
90
91
92 transportConfig := config.transportConfig()
93 if insecureSkipTLSVerify {
94 transportConfig.TLS.Insecure = true
95 transportConfig.TLS.CAFile = ""
96 }
97
98 if config.Lookup != nil {
99
100
101 networkContext := egressselector.Cluster.AsNetworkContext()
102 dialer, err := config.Lookup(networkContext)
103 if err != nil {
104 return nil, fmt.Errorf("failed to get context dialer for 'cluster': got %v", err)
105 }
106 if dialer != nil {
107 transportConfig.DialHolder = &transport.DialHolder{Dial: dialer}
108 }
109 }
110 return transport.New(transportConfig)
111 }
112
113
114 func (c *KubeletClientConfig) transportConfig() *transport.Config {
115 cfg := &transport.Config{
116 TLS: transport.TLSConfig{
117 CAFile: c.TLSClientConfig.CAFile,
118 CertFile: c.TLSClientConfig.CertFile,
119 KeyFile: c.TLSClientConfig.KeyFile,
120
121
122 ReloadTLSFiles: true,
123 },
124 }
125 if !cfg.HasCA() {
126 cfg.TLS.Insecure = true
127 }
128 return cfg
129 }
130
131
132 type NodeGetter interface {
133 Get(ctx context.Context, name string, options metav1.GetOptions) (*v1.Node, error)
134 }
135
136
137 type NodeGetterFunc func(ctx context.Context, name string, options metav1.GetOptions) (*v1.Node, error)
138
139
140 func (f NodeGetterFunc) Get(ctx context.Context, name string, options metav1.GetOptions) (*v1.Node, error) {
141 return f(ctx, name, options)
142 }
143
144
145 type NodeConnectionInfoGetter struct {
146
147 nodes NodeGetter
148
149 scheme string
150
151 defaultPort int
152
153 transport http.RoundTripper
154
155 insecureSkipTLSVerifyTransport http.RoundTripper
156
157 preferredAddressTypes []v1.NodeAddressType
158 }
159
160
161 func NewNodeConnectionInfoGetter(nodes NodeGetter, config KubeletClientConfig) (ConnectionInfoGetter, error) {
162 transport, err := MakeTransport(&config)
163 if err != nil {
164 return nil, err
165 }
166 insecureSkipTLSVerifyTransport, err := MakeInsecureTransport(&config)
167 if err != nil {
168 return nil, err
169 }
170
171 types := []v1.NodeAddressType{}
172 for _, t := range config.PreferredAddressTypes {
173 types = append(types, v1.NodeAddressType(t))
174 }
175
176 return &NodeConnectionInfoGetter{
177 nodes: nodes,
178 scheme: "https",
179 defaultPort: int(config.Port),
180 transport: transport,
181 insecureSkipTLSVerifyTransport: insecureSkipTLSVerifyTransport,
182
183 preferredAddressTypes: types,
184 }, nil
185 }
186
187
188 func (k *NodeConnectionInfoGetter) GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*ConnectionInfo, error) {
189 node, err := k.nodes.Get(ctx, string(nodeName), metav1.GetOptions{})
190 if err != nil {
191 return nil, err
192 }
193
194
195 host, err := nodeutil.GetPreferredNodeAddress(node, k.preferredAddressTypes)
196 if err != nil {
197 return nil, err
198 }
199
200
201 port := int(node.Status.DaemonEndpoints.KubeletEndpoint.Port)
202 if port <= 0 {
203 port = k.defaultPort
204 }
205
206 return &ConnectionInfo{
207 Scheme: k.scheme,
208 Hostname: host,
209 Port: strconv.Itoa(port),
210 Transport: k.transport,
211 InsecureSkipTLSVerifyTransport: k.insecureSkipTLSVerifyTransport,
212 }, nil
213 }
214
View as plain text