2022-03-22 11:03:15 -04:00
|
|
|
package kubectl
|
|
|
|
|
|
|
|
import (
|
2022-07-18 06:28:02 -04:00
|
|
|
"context"
|
2022-03-22 11:03:15 -04:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
2022-06-29 09:26:29 -04:00
|
|
|
"github.com/edgelesssys/constellation/bootstrapper/internal/kubernetes/k8sapi/resources"
|
2022-07-18 06:28:02 -04:00
|
|
|
corev1 "k8s.io/api/core/v1"
|
2022-03-22 11:03:15 -04:00
|
|
|
"k8s.io/cli-runtime/pkg/resource"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ErrKubeconfigNotSet is the error value returned by Kubectl.Apply when SetKubeconfig was not called first.
|
|
|
|
var ErrKubeconfigNotSet = errors.New("kubeconfig not set")
|
|
|
|
|
|
|
|
// Client wraps marshable k8s resources into resource.Info fields and applies them in a cluster.
|
|
|
|
type Client interface {
|
|
|
|
// ApplyOneObject applies a k8s resource similar to kubectl apply.
|
|
|
|
ApplyOneObject(info *resource.Info, forceConflicts bool) error
|
|
|
|
// GetObjects converts resources into prepared info fields for use in ApplyOneObject.
|
|
|
|
GetObjects(resources resources.Marshaler) ([]*resource.Info, error)
|
2022-07-18 06:28:02 -04:00
|
|
|
CreateConfigMap(ctx context.Context, configMap corev1.ConfigMap) error
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// clientGenerator can generate new clients from a kubeconfig.
|
|
|
|
type clientGenerator interface {
|
|
|
|
NewClient(kubeconfig []byte) (Client, error)
|
|
|
|
}
|
|
|
|
|
2022-04-26 05:22:21 -04:00
|
|
|
// Kubectl implements kubernetes.Apply interface and acts like the Kubernetes "kubectl" tool.
|
2022-03-22 11:03:15 -04:00
|
|
|
type Kubectl struct {
|
|
|
|
clientGenerator
|
|
|
|
kubeconfig []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a new kubectl using the real clientGenerator.
|
|
|
|
func New() *Kubectl {
|
|
|
|
return &Kubectl{
|
|
|
|
clientGenerator: &generator{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply will apply the given resources using server-side-apply.
|
|
|
|
func (k *Kubectl) Apply(resources resources.Marshaler, forceConflicts bool) error {
|
|
|
|
if k.kubeconfig == nil {
|
|
|
|
return ErrKubeconfigNotSet
|
|
|
|
}
|
|
|
|
client, err := k.clientGenerator.NewClient(k.kubeconfig)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// convert marshaler object into []*resource.info
|
|
|
|
infos, err := client.GetObjects(resources)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// apply each object, one by one
|
|
|
|
for i, resource := range infos {
|
|
|
|
if err := client.ApplyOneObject(resource, forceConflicts); err != nil {
|
2022-06-09 10:04:30 -04:00
|
|
|
return fmt.Errorf("kubectl apply of object %v/%v: %w", i, len(infos), err)
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetKubeconfig will store the kubeconfig to generate Clients using the clientGenerator later.
|
|
|
|
func (k *Kubectl) SetKubeconfig(kubeconfig []byte) {
|
|
|
|
k.kubeconfig = kubeconfig
|
|
|
|
}
|
2022-07-18 06:28:02 -04:00
|
|
|
|
|
|
|
func (k *Kubectl) CreateConfigMap(ctx context.Context, configMap corev1.ConfigMap) error {
|
|
|
|
client, err := k.clientGenerator.NewClient(k.kubeconfig)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = client.CreateConfigMap(ctx, configMap)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|