github.phpd.cn/cilium/cilium@v1.6.12/pkg/k8s/client.go (about) 1 // Copyright 2016-2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package k8s abstracts all Kubernetes specific behaviour 16 package k8s 17 18 import ( 19 goerrors "errors" 20 "fmt" 21 "time" 22 23 "github.com/cilium/cilium/api/v1/models" 24 clientset "github.com/cilium/cilium/pkg/k8s/client/clientset/versioned" 25 "github.com/cilium/cilium/pkg/logging/logfields" 26 "github.com/cilium/cilium/pkg/version" 27 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/util/wait" 30 "k8s.io/client-go/kubernetes" 31 "k8s.io/client-go/rest" 32 "k8s.io/client-go/tools/clientcmd" 33 ) 34 35 var ( 36 // ErrNilNode is returned when the Kubernetes API server has returned a nil node 37 ErrNilNode = goerrors.New("API server returned nil node") 38 39 // k8sCli is the default client. 40 k8sCli = &K8sClient{} 41 42 // k8sCiliumCli is the default Cilium client. 43 k8sCiliumCli = &K8sCiliumClient{} 44 ) 45 46 // CreateConfig creates a rest.Config for a given endpoint using a kubeconfig file. 47 func createConfig(endpoint, kubeCfgPath string, qps float32, burst int) (*rest.Config, error) { 48 userAgent := fmt.Sprintf("Cilium %s", version.Version) 49 50 // If the endpoint and the kubeCfgPath are empty then we can try getting 51 // the rest.Config from the InClusterConfig 52 if endpoint == "" && kubeCfgPath == "" { 53 config, err := rest.InClusterConfig() 54 if err != nil { 55 return nil, err 56 } 57 setConfig(config, userAgent, qps, burst) 58 return config, nil 59 } 60 61 if kubeCfgPath != "" { 62 config, err := clientcmd.BuildConfigFromFlags("", kubeCfgPath) 63 if err != nil { 64 return nil, err 65 } 66 setConfig(config, userAgent, qps, burst) 67 return config, nil 68 } 69 70 config := &rest.Config{Host: endpoint, UserAgent: userAgent} 71 setConfig(config, userAgent, qps, burst) 72 err := rest.SetKubernetesDefaults(config) 73 74 return config, err 75 } 76 77 func setConfig(config *rest.Config, userAgent string, qps float32, burst int) { 78 if config.UserAgent != "" { 79 config.UserAgent = userAgent 80 } 81 if qps != 0.0 { 82 config.QPS = qps 83 } 84 if burst != 0 { 85 config.Burst = burst 86 } 87 } 88 89 // CreateConfigFromAgentResponse creates a client configuration from a 90 // models.DaemonConfigurationResponse 91 func CreateConfigFromAgentResponse(resp *models.DaemonConfiguration) (*rest.Config, error) { 92 return createConfig(resp.Status.K8sEndpoint, resp.Status.K8sConfiguration, GetQPS(), GetBurst()) 93 } 94 95 // CreateConfig creates a client configuration based on the configured API 96 // server and Kubeconfig path 97 func CreateConfig() (*rest.Config, error) { 98 return createConfig(GetAPIServer(), GetKubeconfigPath(), GetQPS(), GetBurst()) 99 } 100 101 // CreateClient creates a new client to access the Kubernetes API 102 func CreateClient(config *rest.Config) (*kubernetes.Clientset, error) { 103 cs, err := kubernetes.NewForConfig(config) 104 if err != nil { 105 return nil, err 106 } 107 stop := make(chan struct{}) 108 timeout := time.NewTimer(time.Minute) 109 defer timeout.Stop() 110 wait.Until(func() { 111 // FIXME: Use config.String() when we rebase to latest go-client 112 log.WithField("host", config.Host).Info("Establishing connection to apiserver") 113 err = isConnReady(cs) 114 if err == nil { 115 close(stop) 116 return 117 } 118 select { 119 case <-timeout.C: 120 log.WithError(err).WithField(logfields.IPAddr, config.Host).Error("Unable to contact k8s api-server") 121 close(stop) 122 default: 123 } 124 }, 5*time.Second, stop) 125 if err == nil { 126 log.Info("Connected to apiserver") 127 } 128 return cs, err 129 } 130 131 // isConnReady returns the err for the kube-system namespace get 132 func isConnReady(c *kubernetes.Clientset) error { 133 _, err := c.CoreV1().Namespaces().Get("kube-system", metav1.GetOptions{}) 134 return err 135 } 136 137 // Client returns the default Kubernetes client. 138 func Client() *K8sClient { 139 return k8sCli 140 } 141 142 func createDefaultClient() error { 143 restConfig, err := CreateConfig() 144 if err != nil { 145 return fmt.Errorf("unable to create k8s client rest configuration: %s", err) 146 } 147 restConfig.ContentConfig.ContentType = `application/vnd.kubernetes.protobuf` 148 149 createdK8sClient, err := CreateClient(restConfig) 150 if err != nil { 151 return fmt.Errorf("unable to create k8s client: %s", err) 152 } 153 154 k8sCli.Interface = createdK8sClient 155 156 return nil 157 } 158 159 // CiliumClient returns the default Cilium Kubernetes client. 160 func CiliumClient() *K8sCiliumClient { 161 return k8sCiliumCli 162 } 163 164 func createDefaultCiliumClient() error { 165 restConfig, err := CreateConfig() 166 if err != nil { 167 return fmt.Errorf("unable to create k8s client rest configuration: %s", err) 168 } 169 170 createdCiliumK8sClient, err := clientset.NewForConfig(restConfig) 171 if err != nil { 172 return fmt.Errorf("unable to create k8s client: %s", err) 173 } 174 175 k8sCiliumCli.Interface = createdCiliumK8sClient 176 177 return nil 178 }