123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- /*
- Copyright 2014 The Kubernetes 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 client
- import (
- "context"
- "fmt"
- "net/http"
- "strconv"
- "time"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- utilnet "k8s.io/apimachinery/pkg/util/net"
- "k8s.io/apiserver/pkg/server/egressselector"
- restclient "k8s.io/client-go/rest"
- "k8s.io/client-go/transport"
- nodeutil "k8s.io/kubernetes/pkg/util/node"
- )
- // KubeletClientConfig defines config parameters for the kubelet client
- type KubeletClientConfig struct {
- // Port specifies the default port - used if no information about Kubelet port can be found in Node.NodeStatus.DaemonEndpoints.
- Port uint
- // ReadOnlyPort specifies the Port for ReadOnly communications.
- ReadOnlyPort uint
- // EnableHTTPs specifies if traffic should be encrypted.
- EnableHTTPS bool
- // PreferredAddressTypes - used to select an address from Node.NodeStatus.Addresses
- PreferredAddressTypes []string
- // TLSClientConfig contains settings to enable transport layer security
- restclient.TLSClientConfig
- // Server requires Bearer authentication
- BearerToken string
- // HTTPTimeout is used by the client to timeout http requests to Kubelet.
- HTTPTimeout time.Duration
- // Dial is a custom dialer used for the client
- Dial utilnet.DialFunc
- // Lookup will give us a dialer if the egress selector is configured for it
- Lookup egressselector.Lookup
- }
- // ConnectionInfo provides the information needed to connect to a kubelet
- type ConnectionInfo struct {
- Scheme string
- Hostname string
- Port string
- Transport http.RoundTripper
- InsecureSkipTLSVerifyTransport http.RoundTripper
- }
- // ConnectionInfoGetter provides ConnectionInfo for the kubelet running on a named node
- type ConnectionInfoGetter interface {
- GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*ConnectionInfo, error)
- }
- // MakeTransport creates a secure RoundTripper for HTTP Transport.
- func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
- return makeTransport(config, false)
- }
- // MakeInsecureTransport creates an insecure RoundTripper for HTTP Transport.
- func MakeInsecureTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
- return makeTransport(config, true)
- }
- // makeTransport creates a RoundTripper for HTTP Transport.
- func makeTransport(config *KubeletClientConfig, insecureSkipTLSVerify bool) (http.RoundTripper, error) {
- // do the insecureSkipTLSVerify on the pre-transport *before* we go get a potentially cached connection.
- // transportConfig always produces a new struct pointer.
- preTLSConfig := config.transportConfig()
- if insecureSkipTLSVerify && preTLSConfig != nil {
- preTLSConfig.TLS.Insecure = true
- preTLSConfig.TLS.CAData = nil
- preTLSConfig.TLS.CAFile = ""
- }
- tlsConfig, err := transport.TLSConfigFor(preTLSConfig)
- if err != nil {
- return nil, err
- }
- rt := http.DefaultTransport
- dialer := config.Dial
- if dialer == nil && config.Lookup != nil {
- // Assuming EgressSelector if SSHTunnel is not turned on.
- // We will not get a dialer if egress selector is disabled.
- networkContext := egressselector.Cluster.AsNetworkContext()
- dialer, err = config.Lookup(networkContext)
- if err != nil {
- return nil, fmt.Errorf("failed to get context dialer for 'cluster': got %v", err)
- }
- }
- if dialer != nil || tlsConfig != nil {
- // If SSH Tunnel is turned on
- rt = utilnet.SetOldTransportDefaults(&http.Transport{
- DialContext: dialer,
- TLSClientConfig: tlsConfig,
- })
- }
- return transport.HTTPWrappersForConfig(config.transportConfig(), rt)
- }
- // transportConfig converts a client config to an appropriate transport config.
- func (c *KubeletClientConfig) transportConfig() *transport.Config {
- cfg := &transport.Config{
- TLS: transport.TLSConfig{
- CAFile: c.CAFile,
- CAData: c.CAData,
- CertFile: c.CertFile,
- CertData: c.CertData,
- KeyFile: c.KeyFile,
- KeyData: c.KeyData,
- NextProtos: c.NextProtos,
- },
- BearerToken: c.BearerToken,
- }
- if c.EnableHTTPS && !cfg.HasCA() {
- cfg.TLS.Insecure = true
- }
- return cfg
- }
- // NodeGetter defines an interface for looking up a node by name
- type NodeGetter interface {
- Get(ctx context.Context, name string, options metav1.GetOptions) (*v1.Node, error)
- }
- // NodeGetterFunc allows implementing NodeGetter with a function
- type NodeGetterFunc func(ctx context.Context, name string, options metav1.GetOptions) (*v1.Node, error)
- // Get fetches information via NodeGetterFunc.
- func (f NodeGetterFunc) Get(ctx context.Context, name string, options metav1.GetOptions) (*v1.Node, error) {
- return f(ctx, name, options)
- }
- // NodeConnectionInfoGetter obtains connection info from the status of a Node API object
- type NodeConnectionInfoGetter struct {
- // nodes is used to look up Node objects
- nodes NodeGetter
- // scheme is the scheme to use to connect to all kubelets
- scheme string
- // defaultPort is the port to use if no Kubelet endpoint port is recorded in the node status
- defaultPort int
- // transport is the transport to use to send a request to all kubelets
- transport http.RoundTripper
- // insecureSkipTLSVerifyTransport is the transport to use if the kube-apiserver wants to skip verifying the TLS certificate of the kubelet
- insecureSkipTLSVerifyTransport http.RoundTripper
- // preferredAddressTypes specifies the preferred order to use to find a node address
- preferredAddressTypes []v1.NodeAddressType
- }
- // NewNodeConnectionInfoGetter creates a new NodeConnectionInfoGetter.
- func NewNodeConnectionInfoGetter(nodes NodeGetter, config KubeletClientConfig) (ConnectionInfoGetter, error) {
- scheme := "http"
- if config.EnableHTTPS {
- scheme = "https"
- }
- transport, err := MakeTransport(&config)
- if err != nil {
- return nil, err
- }
- insecureSkipTLSVerifyTransport, err := MakeInsecureTransport(&config)
- if err != nil {
- return nil, err
- }
- types := []v1.NodeAddressType{}
- for _, t := range config.PreferredAddressTypes {
- types = append(types, v1.NodeAddressType(t))
- }
- return &NodeConnectionInfoGetter{
- nodes: nodes,
- scheme: scheme,
- defaultPort: int(config.Port),
- transport: transport,
- insecureSkipTLSVerifyTransport: insecureSkipTLSVerifyTransport,
- preferredAddressTypes: types,
- }, nil
- }
- // GetConnectionInfo retrieves connection info from the status of a Node API object.
- func (k *NodeConnectionInfoGetter) GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*ConnectionInfo, error) {
- node, err := k.nodes.Get(ctx, string(nodeName), metav1.GetOptions{})
- if err != nil {
- return nil, err
- }
- // Find a kubelet-reported address, using preferred address type
- host, err := nodeutil.GetPreferredNodeAddress(node, k.preferredAddressTypes)
- if err != nil {
- return nil, err
- }
- // Use the kubelet-reported port, if present
- port := int(node.Status.DaemonEndpoints.KubeletEndpoint.Port)
- if port <= 0 {
- port = k.defaultPort
- }
- return &ConnectionInfo{
- Scheme: k.scheme,
- Hostname: host,
- Port: strconv.Itoa(port),
- Transport: k.transport,
- InsecureSkipTLSVerifyTransport: k.insecureSkipTLSVerifyTransport,
- }, nil
- }
|