mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-01-22 13:21:07 -05:00
6af54142f2
The nested client pkg was necessary to implement a generator pattern. The generator was necessary as the Kubewrapper type expects a k8sapi.Client object during instantiation. However, the required kubeconfig is not ready during Kubewrapper creation. This patch relies on an Initialize function to set the Kubeconfig and hands over an empty struct during Kubewrapper creation. This allows us to remove the extra Client abstraction.
129 lines
4.0 KiB
Go
129 lines
4.0 KiB
Go
/*
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
package kubectl
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
apiextensionsclientv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/cli-runtime/pkg/resource"
|
|
"k8s.io/client-go/kubernetes"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
"k8s.io/client-go/util/retry"
|
|
)
|
|
|
|
// Kubectl implements functionality of the Kubernetes "kubectl" tool.
|
|
type Kubectl struct {
|
|
kubernetes.Interface
|
|
apiextensionClient apiextensionsclientv1.ApiextensionsV1Interface
|
|
builder *resource.Builder
|
|
}
|
|
|
|
// New returns an empty Kubectl client. Need to call Initialize before usable.
|
|
func New() *Kubectl {
|
|
return &Kubectl{}
|
|
}
|
|
|
|
// Initialize sets sets all required fields so the Kubectl client can be used.
|
|
func (k *Kubectl) Initialize(kubeconfig []byte) error {
|
|
clientConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig)
|
|
if err != nil {
|
|
return fmt.Errorf("creating k8s client config from kubeconfig: %w", err)
|
|
}
|
|
clientset, err := kubernetes.NewForConfig(clientConfig)
|
|
if err != nil {
|
|
return fmt.Errorf("creating k8s client from kubeconfig: %w", err)
|
|
}
|
|
k.Interface = clientset
|
|
|
|
apiextensionClient, err := apiextensionsclientv1.NewForConfig(clientConfig)
|
|
if err != nil {
|
|
return fmt.Errorf("creating api extension client from kubeconfig: %w", err)
|
|
}
|
|
k.apiextensionClient = apiextensionClient
|
|
|
|
restClientGetter, err := newRESTClientGetter(kubeconfig)
|
|
if err != nil {
|
|
return fmt.Errorf("creating k8s RESTClientGetter from kubeconfig: %w", err)
|
|
}
|
|
k.builder = resource.NewBuilder(restClientGetter).Unstructured()
|
|
|
|
return nil
|
|
}
|
|
|
|
// CreateConfigMap creates the provided configmap.
|
|
func (k *Kubectl) CreateConfigMap(ctx context.Context, configMap corev1.ConfigMap) error {
|
|
_, err := k.CoreV1().ConfigMaps(configMap.ObjectMeta.Namespace).Create(ctx, &configMap, metav1.CreateOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ListAllNamespaces returns all namespaces in the cluster.
|
|
func (k *Kubectl) ListAllNamespaces(ctx context.Context) (*corev1.NamespaceList, error) {
|
|
return k.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
|
|
}
|
|
|
|
// AddTolerationsToDeployment adds [K8s tolerations] to the deployment, identified
|
|
// by name and namespace.
|
|
//
|
|
// [K8s tolerations]: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/
|
|
func (k *Kubectl) AddTolerationsToDeployment(ctx context.Context, tolerations []corev1.Toleration, name string, namespace string) error {
|
|
deployments := k.AppsV1().Deployments(namespace)
|
|
|
|
// retry resource update if an error occurs
|
|
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
|
result, err := deployments.Get(ctx, name, metav1.GetOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get Deployment to add toleration: %w", err)
|
|
}
|
|
|
|
result.Spec.Template.Spec.Tolerations = append(result.Spec.Template.Spec.Tolerations, tolerations...)
|
|
if _, err = deployments.Update(ctx, result, metav1.UpdateOptions{}); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AddNodeSelectorsToDeployment adds [K8s selectors] to the deployment, identified
|
|
// by name and namespace.
|
|
//
|
|
// [K8s selectors]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
|
func (k *Kubectl) AddNodeSelectorsToDeployment(ctx context.Context, selectors map[string]string, name string, namespace string) error {
|
|
deployments := k.AppsV1().Deployments(namespace)
|
|
|
|
// retry resource update if an error occurs
|
|
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
|
result, err := deployments.Get(ctx, name, metav1.GetOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get Deployment to add node selector: %w", err)
|
|
}
|
|
|
|
for k, v := range selectors {
|
|
result.Spec.Template.Spec.NodeSelector[k] = v
|
|
}
|
|
|
|
if _, err = deployments.Update(ctx, result, metav1.UpdateOptions{}); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|