package utils
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
"time"
)
func requireKubeconfigFromEnv() error {
raw := strings.TrimSpace(os.Getenv("KUBECONFIG"))
if raw == "" {
return fmt.Errorf("KUBECONFIG 未设置,请设为 kubeconfig 文件路径后再跑混部套件")
}
first := strings.Split(raw, string(os.PathListSeparator))[0]
first = strings.TrimSpace(first)
fi, err := os.Stat(first)
if err != nil {
return fmt.Errorf("KUBECONFIG 路径 %q 不可用: %w", first, err)
}
if fi.IsDir() {
return fmt.Errorf("KUBECONFIG 路径 %q 是目录,应为文件", first)
}
return nil
}
func helmListJSON(ctx context.Context, namespace string) ([]map[string]interface{}, error) {
cmd := exec.CommandContext(ctx, "helm", "list", "-n", namespace, "-o", "json")
out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("helm list: %w", err)
}
out = bytes.TrimSpace(out)
if len(out) == 0 {
return nil, nil
}
var list []map[string]interface{}
if err := json.Unmarshal(out, &list); err != nil {
return nil, fmt.Errorf("parse helm list json: %w", err)
}
return list, nil
}
func HelmReleaseExists(ctx context.Context, helmConfig map[string]string) (bool, error) {
list, err := helmListJSON(ctx, helmConfig["namespace"])
if err != nil {
return false, err
}
for _, item := range list {
if name, ok := item["name"].(string); ok && name == helmConfig["releaseName"] {
return true, nil
}
}
return false, nil
}
func helmReleaseStatusDeployed(ctx context.Context, releaseName, namespace string) (bool, string, error) {
cmd := exec.CommandContext(ctx, "helm", "status", releaseName, "-n", namespace, "-o", "json")
out, err := cmd.Output()
if err != nil {
return false, "", err
}
var parsed struct {
Info struct {
Status string `json:"status"`
} `json:"info"`
}
if err := json.Unmarshal(bytes.TrimSpace(out), &parsed); err != nil {
return false, "", fmt.Errorf("parse helm status json: %w", err)
}
st := strings.ToLower(strings.TrimSpace(parsed.Info.Status))
return st == "deployed", st, nil
}
func WaitHelmReleaseDeployed(ctx context.Context, releaseName, namespace string, timeout, poll time.Duration) error {
deadline := time.Now().Add(timeout)
var last string
for time.Now().Before(deadline) {
ok, st, err := helmReleaseStatusDeployed(ctx, releaseName, namespace)
if err == nil && ok {
return nil
}
if err == nil {
last = st
}
time.Sleep(poll)
}
return fmt.Errorf("helm release %q in namespace %q not deployed within %v; last status: %q", releaseName, namespace, timeout, last)
}
func HelmInstallLocal(ctx context.Context, helmConfig map[string]string) error {
releaseName := helmConfig["releaseName"]
chartURL := helmConfig["helmUrl"]
version := helmConfig["version"]
namespace := helmConfig["namespace"]
args := []string{"install", releaseName, chartURL, "--version", version, "-n", namespace}
cmd := exec.CommandContext(ctx, "helm", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("helm install %s: %w", releaseName, err)
}
return nil
}
func HelmUninstallLocal(ctx context.Context, helmConfig map[string]string) error {
releaseName := helmConfig["releaseName"]
namespace := helmConfig["namespace"]
cmd := exec.CommandContext(ctx, "helm", "uninstall", releaseName, "-n", namespace)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("helm uninstall %s: %w", releaseName, err)
}
return nil
}