k8s.io/kubernetes@v1.29.3/pkg/kubelet/client/kubelet_client.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 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 // KubeletClientConfig defines config parameters for the kubelet client 35 type KubeletClientConfig struct { 36 // Port specifies the default port - used if no information about Kubelet port can be found in Node.NodeStatus.DaemonEndpoints. 37 Port uint 38 39 // ReadOnlyPort specifies the Port for ReadOnly communications. 40 ReadOnlyPort uint 41 42 // PreferredAddressTypes - used to select an address from Node.NodeStatus.Addresses 43 PreferredAddressTypes []string 44 45 // TLSClientConfig contains settings to enable transport layer security 46 TLSClientConfig KubeletTLSConfig 47 48 // HTTPTimeout is used by the client to timeout http requests to Kubelet. 49 HTTPTimeout time.Duration 50 51 // Lookup will give us a dialer if the egress selector is configured for it 52 Lookup egressselector.Lookup 53 } 54 55 type KubeletTLSConfig struct { 56 // Server requires TLS client certificate authentication 57 CertFile string 58 // Server requires TLS client certificate authentication 59 KeyFile string 60 // Trusted root certificates for server 61 CAFile string 62 } 63 64 // ConnectionInfo provides the information needed to connect to a kubelet 65 type ConnectionInfo struct { 66 Scheme string 67 Hostname string 68 Port string 69 Transport http.RoundTripper 70 InsecureSkipTLSVerifyTransport http.RoundTripper 71 } 72 73 // ConnectionInfoGetter provides ConnectionInfo for the kubelet running on a named node 74 type ConnectionInfoGetter interface { 75 GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*ConnectionInfo, error) 76 } 77 78 // MakeTransport creates a secure RoundTripper for HTTP Transport. 79 func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) { 80 return makeTransport(config, false) 81 } 82 83 // MakeInsecureTransport creates an insecure RoundTripper for HTTP Transport. 84 func MakeInsecureTransport(config *KubeletClientConfig) (http.RoundTripper, error) { 85 return makeTransport(config, true) 86 } 87 88 // makeTransport creates a RoundTripper for HTTP Transport. 89 func makeTransport(config *KubeletClientConfig, insecureSkipTLSVerify bool) (http.RoundTripper, error) { 90 // do the insecureSkipTLSVerify on the pre-transport *before* we go get a potentially cached connection. 91 // transportConfig always produces a new struct pointer. 92 transportConfig := config.transportConfig() 93 if insecureSkipTLSVerify { 94 transportConfig.TLS.Insecure = true 95 transportConfig.TLS.CAFile = "" // we are only using files so we can ignore CAData 96 } 97 98 if config.Lookup != nil { 99 // Assuming EgressSelector if SSHTunnel is not turned on. 100 // We will not get a dialer if egress selector is disabled. 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 // transportConfig converts a client config to an appropriate transport config. 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 // transport.loadTLSFiles would set this to true because we are only using files 121 // it is clearer to set it explicitly here so we remember that this is happening 122 ReloadTLSFiles: true, 123 }, 124 } 125 if !cfg.HasCA() { 126 cfg.TLS.Insecure = true 127 } 128 return cfg 129 } 130 131 // NodeGetter defines an interface for looking up a node by name 132 type NodeGetter interface { 133 Get(ctx context.Context, name string, options metav1.GetOptions) (*v1.Node, error) 134 } 135 136 // NodeGetterFunc allows implementing NodeGetter with a function 137 type NodeGetterFunc func(ctx context.Context, name string, options metav1.GetOptions) (*v1.Node, error) 138 139 // Get fetches information via NodeGetterFunc. 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 // NodeConnectionInfoGetter obtains connection info from the status of a Node API object 145 type NodeConnectionInfoGetter struct { 146 // nodes is used to look up Node objects 147 nodes NodeGetter 148 // scheme is the scheme to use to connect to all kubelets 149 scheme string 150 // defaultPort is the port to use if no Kubelet endpoint port is recorded in the node status 151 defaultPort int 152 // transport is the transport to use to send a request to all kubelets 153 transport http.RoundTripper 154 // insecureSkipTLSVerifyTransport is the transport to use if the kube-apiserver wants to skip verifying the TLS certificate of the kubelet 155 insecureSkipTLSVerifyTransport http.RoundTripper 156 // preferredAddressTypes specifies the preferred order to use to find a node address 157 preferredAddressTypes []v1.NodeAddressType 158 } 159 160 // NewNodeConnectionInfoGetter creates a new NodeConnectionInfoGetter. 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 // GetConnectionInfo retrieves connection info from the status of a Node API object. 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 // Find a kubelet-reported address, using preferred address type 195 host, err := nodeutil.GetPreferredNodeAddress(node, k.preferredAddressTypes) 196 if err != nil { 197 return nil, err 198 } 199 200 // Use the kubelet-reported port, if present 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 }