227 lines
5.4 KiB
Go
227 lines
5.4 KiB
Go
package external
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// KubectlTool wraps kubectl operations
|
|
type KubectlTool struct {
|
|
*BaseTool
|
|
kubeconfig string
|
|
}
|
|
|
|
// NewKubectlTool creates a new kubectl tool wrapper
|
|
func NewKubectlTool() *KubectlTool {
|
|
return &KubectlTool{
|
|
BaseTool: NewBaseTool("kubectl", "kubectl"),
|
|
}
|
|
}
|
|
|
|
// SetKubeconfig sets the kubeconfig file path
|
|
func (k *KubectlTool) SetKubeconfig(path string) {
|
|
k.kubeconfig = path
|
|
}
|
|
|
|
// Apply applies Kubernetes manifests
|
|
func (k *KubectlTool) Apply(ctx context.Context, manifests []string, namespace string, dryRun bool) error {
|
|
for _, manifest := range manifests {
|
|
args := []string{"apply", "-f", "-"}
|
|
|
|
if namespace != "" {
|
|
args = append(args, "--namespace", namespace)
|
|
}
|
|
|
|
if dryRun {
|
|
args = append(args, "--dry-run=client")
|
|
}
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
_, err := k.ExecuteWithInput(ctx, manifest, args...)
|
|
if err != nil {
|
|
return fmt.Errorf("applying manifest: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ApplyKustomize applies using kustomize
|
|
func (k *KubectlTool) ApplyKustomize(ctx context.Context, path string, namespace string, dryRun bool) error {
|
|
args := []string{"apply", "-k", path}
|
|
|
|
if namespace != "" {
|
|
args = append(args, "--namespace", namespace)
|
|
}
|
|
|
|
if dryRun {
|
|
args = append(args, "--dry-run=client")
|
|
}
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
_, err := k.Execute(ctx, args...)
|
|
if err != nil {
|
|
return fmt.Errorf("applying kustomize: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Delete deletes Kubernetes resources
|
|
func (k *KubectlTool) Delete(ctx context.Context, resource, name, namespace string, ignoreNotFound bool) error {
|
|
args := []string{"delete", resource, name}
|
|
|
|
if namespace != "" {
|
|
args = append(args, "--namespace", namespace)
|
|
}
|
|
|
|
if ignoreNotFound {
|
|
args = append(args, "--ignore-not-found=true")
|
|
}
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
_, err := k.Execute(ctx, args...)
|
|
if err != nil {
|
|
return fmt.Errorf("deleting resource: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CreateSecret creates a Kubernetes secret
|
|
func (k *KubectlTool) CreateSecret(ctx context.Context, name, namespace string, data map[string]string) error {
|
|
// First try to delete existing secret
|
|
_ = k.Delete(ctx, "secret", name, namespace, true)
|
|
|
|
args := []string{"create", "secret", "generic", name}
|
|
|
|
for key, value := range data {
|
|
args = append(args, "--from-literal="+key+"="+value)
|
|
}
|
|
|
|
if namespace != "" {
|
|
args = append(args, "--namespace", namespace)
|
|
}
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
_, err := k.Execute(ctx, args...)
|
|
if err != nil {
|
|
return fmt.Errorf("creating secret: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetResource gets a Kubernetes resource
|
|
func (k *KubectlTool) GetResource(ctx context.Context, resource, name, namespace string) ([]byte, error) {
|
|
args := []string{"get", resource}
|
|
|
|
if name != "" {
|
|
args = append(args, name)
|
|
}
|
|
|
|
if namespace != "" {
|
|
args = append(args, "--namespace", namespace)
|
|
}
|
|
|
|
args = append(args, "-o", "yaml")
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
output, err := k.Execute(ctx, args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting resource: %w", err)
|
|
}
|
|
|
|
return output, nil
|
|
}
|
|
|
|
// WaitForDeletion waits for a resource to be deleted
|
|
func (k *KubectlTool) WaitForDeletion(ctx context.Context, resource, name, namespace string, timeout string) error {
|
|
args := []string{"wait", "--for=delete", resource + "/" + name}
|
|
|
|
if namespace != "" {
|
|
args = append(args, "--namespace", namespace)
|
|
}
|
|
|
|
if timeout != "" {
|
|
args = append(args, "--timeout="+timeout)
|
|
}
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
_, err := k.Execute(ctx, args...)
|
|
if err != nil {
|
|
return fmt.Errorf("waiting for deletion: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetNodes returns information about cluster nodes
|
|
func (k *KubectlTool) GetNodes(ctx context.Context) ([]byte, error) {
|
|
args := []string{"get", "nodes", "-o", "wide"}
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
output, err := k.Execute(ctx, args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting nodes: %w", err)
|
|
}
|
|
|
|
return output, nil
|
|
}
|
|
|
|
// GetServiceAccount gets a service account token
|
|
func (k *KubectlTool) GetServiceAccountToken(ctx context.Context, serviceAccount, namespace string) (string, error) {
|
|
// Get the service account
|
|
args := []string{"get", "serviceaccount", serviceAccount, "--namespace", namespace, "-o", "jsonpath={.secrets[0].name}"}
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
secretName, err := k.Execute(ctx, args...)
|
|
if err != nil {
|
|
return "", fmt.Errorf("getting service account secret: %w", err)
|
|
}
|
|
|
|
secretNameStr := strings.TrimSpace(string(secretName))
|
|
if secretNameStr == "" {
|
|
return "", fmt.Errorf("no secret found for service account %s", serviceAccount)
|
|
}
|
|
|
|
// Get the token from the secret
|
|
args = []string{"get", "secret", secretNameStr, "--namespace", namespace, "-o", "jsonpath={.data.token}"}
|
|
|
|
if k.kubeconfig != "" {
|
|
args = append([]string{"--kubeconfig", k.kubeconfig}, args...)
|
|
}
|
|
|
|
tokenBytes, err := k.Execute(ctx, args...)
|
|
if err != nil {
|
|
return "", fmt.Errorf("getting token from secret: %w", err)
|
|
}
|
|
|
|
return string(tokenBytes), nil
|
|
}
|