mirror of https://github.com/linkerd/linkerd2.git
132 lines
4.1 KiB
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
|
|
}
|