linkerd2/pkg/k8s/api.go

132 lines
4.1 KiB
Go

package k8s
import (
"fmt"
"net/http"
"time"
"github.com/linkerd/linkerd2/pkg/prometheus"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
// Load all the auth plugins for the cloud providers.
_ "k8s.io/client-go/plugin/pkg/client/auth"
)
var minAPIVersion = [3]int{1, 10, 0}
// KubernetesAPI provides a client for accessing a Kubernetes cluster.
// TODO: support ServiceProfile ClientSet. A prerequisite is moving the
// ServiceProfile client code from `./controller` to `./pkg` (#2751). This will
// also allow making `NewFakeClientSets` private, as KubernetesAPI will support
// all relevant k8s resources.
type KubernetesAPI struct {
*rest.Config
kubernetes.Interface
Apiextensions apiextensionsclient.Interface // for CRDs
}
// NewAPI validates a Kubernetes config and returns a client for accessing the
// configured cluster.
func NewAPI(configPath, kubeContext string, timeout time.Duration) (*KubernetesAPI, error) {
config, err := GetConfig(configPath, kubeContext)
if err != nil {
return nil, fmt.Errorf("error configuring Kubernetes API client: %v", err)
}
// k8s' client-go doesn't support injecting context
// https://github.com/kubernetes/kubernetes/issues/46503
// but we can set the timeout manually
config.Timeout = timeout
wt := config.WrapTransport
config.WrapTransport = prometheus.ClientWithTelemetry("k8s", wt)
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("error configuring Kubernetes API clientset: %v", err)
}
apiextensions, err := apiextensionsclient.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("error configuring Kubernetes API Extensions clientset: %v", err)
}
return &KubernetesAPI{
Config: config,
Interface: clientset,
Apiextensions: apiextensions,
}, nil
}
// NewClient returns an http.Client configured with a Transport to connect to
// the Kubernetes cluster.
func (kubeAPI *KubernetesAPI) NewClient() (*http.Client, error) {
secureTransport, err := rest.TransportFor(kubeAPI.Config)
if err != nil {
return nil, fmt.Errorf("error instantiating Kubernetes API client: %v", err)
}
return &http.Client{
Transport: secureTransport,
}, nil
}
// GetVersionInfo returns version.Info for the Kubernetes cluster.
func (kubeAPI *KubernetesAPI) GetVersionInfo() (*version.Info, error) {
return kubeAPI.Discovery().ServerVersion()
}
// CheckVersion validates whether the configured Kubernetes cluster's version is
// running a minimum Kubernetes API version.
func (kubeAPI *KubernetesAPI) CheckVersion(versionInfo *version.Info) error {
apiVersion, err := getK8sVersion(versionInfo.String())
if err != nil {
return err
}
if !isCompatibleVersion(minAPIVersion, apiVersion) {
return fmt.Errorf("Kubernetes is on version [%d.%d.%d], but version [%d.%d.%d] or more recent is required",
apiVersion[0], apiVersion[1], apiVersion[2],
minAPIVersion[0], minAPIVersion[1], minAPIVersion[2])
}
return nil
}
// NamespaceExists validates whether a given namespace exists.
func (kubeAPI *KubernetesAPI) NamespaceExists(namespace string) (bool, error) {
ns, err := kubeAPI.CoreV1().Namespaces().Get(namespace, metav1.GetOptions{})
if kerrors.IsNotFound(err) {
return false, nil
}
if err != nil {
return false, err
}
return ns != nil, nil
}
// GetPodsByNamespace returns all pods in a given namespace
func (kubeAPI *KubernetesAPI) GetPodsByNamespace(namespace string) ([]corev1.Pod, error) {
podList, err := kubeAPI.CoreV1().Pods(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
return podList.Items, nil
}
// GetReplicaSets returns all replicasets in a given namespace
func (kubeAPI *KubernetesAPI) GetReplicaSets(namespace string) ([]appsv1.ReplicaSet, error) {
replicaSetList, err := kubeAPI.AppsV1().ReplicaSets(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
return replicaSetList.Items, nil
}