mirror of
https://github.com/skoelle/kctl-tui.git
synced 2026-09-18 04:20:25 +00:00
Rework kubeexec to take explicit --context per call instead of mutating global kubectl state; drop functions superseded by config templates
This commit is contained in:
@@ -2,6 +2,12 @@
|
|||||||
// All functions here have side effects (they run external processes) and
|
// All functions here have side effects (they run external processes) and
|
||||||
// are therefore not covered by unit tests; the pure logic they depend on
|
// are therefore not covered by unit tests; the pure logic they depend on
|
||||||
// lives in the kctl package instead.
|
// lives in the kctl package instead.
|
||||||
|
//
|
||||||
|
// Every kubectl-related function takes an explicit context argument
|
||||||
|
// (passed as --context) instead of relying on/mutating the globally
|
||||||
|
// active kubectl context. This lets the panel act on multiple resolved
|
||||||
|
// contexts (e.g. beta and prod) without switching global state back and
|
||||||
|
// forth.
|
||||||
package kubeexec
|
package kubeexec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -21,45 +27,12 @@ func runOutput(name string, args ...string) (string, error) {
|
|||||||
return strings.TrimSpace(string(out)), nil
|
return strings.TrimSpace(string(out)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContexts returns all configured kubectl context names.
|
// kubectlArgs prepends a --context flag when context is non-empty.
|
||||||
func GetContexts() ([]string, error) {
|
func kubectlArgs(context string, args ...string) []string {
|
||||||
out, err := runOutput("kubectl", "config", "get-contexts", "-o", "name")
|
if context == "" {
|
||||||
if err != nil {
|
return args
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
if out == "" {
|
return append([]string{"--context", context}, args...)
|
||||||
return []string{}, nil
|
|
||||||
}
|
|
||||||
return strings.Split(out, "\n"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCurrentContext returns the currently active kubectl context, or an
|
|
||||||
// empty string if none is set.
|
|
||||||
func GetCurrentContext() string {
|
|
||||||
out, _ := runOutput("kubectl", "config", "current-context")
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCurrentNamespace returns the namespace bound to the current context,
|
|
||||||
// defaulting to "default" if unset.
|
|
||||||
func GetCurrentNamespace() string {
|
|
||||||
out, _ := runOutput("kubectl", "config", "view", "--minify", "-o", "jsonpath={..namespace}")
|
|
||||||
if out == "" {
|
|
||||||
return "default"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// UseContext switches the active kubectl context.
|
|
||||||
func UseContext(ctx string) error {
|
|
||||||
_, err := runOutput("kubectl", "config", "use-context", ctx)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNamespace binds a namespace to the current kubectl context.
|
|
||||||
func SetNamespace(ns string) error {
|
|
||||||
_, err := runOutput("kubectl", "config", "set-context", "--current", "--namespace="+ns)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type nsItem struct {
|
type nsItem struct {
|
||||||
@@ -74,9 +47,10 @@ type nsList struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetNamespacesWithLabels returns a map of namespace name -> labels for all
|
// GetNamespacesWithLabels returns a map of namespace name -> labels for all
|
||||||
// namespaces visible in the current context.
|
// namespaces visible in the given context.
|
||||||
func GetNamespacesWithLabels() (map[string]map[string]string, error) {
|
func GetNamespacesWithLabels(context string) (map[string]map[string]string, error) {
|
||||||
out, err := runOutput("kubectl", "get", "ns", "-o", "json")
|
args := kubectlArgs(context, "get", "ns", "-o", "json")
|
||||||
|
out, err := runOutput("kubectl", args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -91,10 +65,11 @@ func GetNamespacesWithLabels() (map[string]map[string]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDeployments lists deployment names in the given namespace.
|
// GetDeployments lists deployment names in the given context/namespace.
|
||||||
func GetDeployments(namespace string) ([]string, error) {
|
func GetDeployments(context, namespace string) ([]string, error) {
|
||||||
out, err := runOutput("kubectl", "-n", namespace, "get", "deploy",
|
args := kubectlArgs(context, "-n", namespace, "get", "deploy",
|
||||||
"-o", `jsonpath={range .items[*]}{.metadata.name}{"\n"}{end}`)
|
"-o", `jsonpath={range .items[*]}{.metadata.name}{"\n"}{end}`)
|
||||||
|
out, err := runOutput("kubectl", args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -105,26 +80,22 @@ func GetDeployments(namespace string) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RolloutRestart triggers a rolling restart of a deployment.
|
// RolloutRestart triggers a rolling restart of a deployment.
|
||||||
func RolloutRestart(namespace, deployment string) (string, error) {
|
func RolloutRestart(context, namespace, deployment string) (string, error) {
|
||||||
return runOutput("kubectl", "-n", namespace, "rollout", "restart", "deploy/"+deployment)
|
args := kubectlArgs(context, "-n", namespace, "rollout", "restart", "deploy/"+deployment)
|
||||||
|
return runOutput("kubectl", args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RolloutStatus waits for and returns the rollout status of a deployment.
|
// RolloutStatus waits for and returns the rollout status of a deployment.
|
||||||
func RolloutStatus(namespace, deployment string) (string, error) {
|
func RolloutStatus(context, namespace, deployment string) (string, error) {
|
||||||
return runOutput("kubectl", "-n", namespace, "rollout", "status", "deploy/"+deployment)
|
args := kubectlArgs(context, "-n", namespace, "rollout", "status", "deploy/"+deployment)
|
||||||
}
|
return runOutput("kubectl", args...)
|
||||||
|
|
||||||
// GetSecretValueBase64 returns the raw (still base64-encoded) value of a
|
|
||||||
// single field in a Kubernetes secret.
|
|
||||||
func GetSecretValueBase64(namespace, secretName, field string) (string, error) {
|
|
||||||
path := fmt.Sprintf("jsonpath={.data.%s}", field)
|
|
||||||
return runOutput("kubectl", "-n", namespace, "get", "secret", secretName, "-o", path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSecretAllFields returns all fields of a Kubernetes secret, already
|
// GetSecretAllFields returns all fields of a Kubernetes secret, already
|
||||||
// base64-decoded into plain values.
|
// base64-decoded into plain values.
|
||||||
func GetSecretAllFields(namespace, secretName string) (map[string]string, error) {
|
func GetSecretAllFields(context, namespace, secretName string) (map[string]string, error) {
|
||||||
out, err := runOutput("kubectl", "-n", namespace, "get", "secret", secretName, "-o", "json")
|
args := kubectlArgs(context, "-n", namespace, "get", "secret", secretName, "-o", "json")
|
||||||
|
out, err := runOutput("kubectl", args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -156,29 +127,16 @@ func DecodeBase64(value string) (string, error) {
|
|||||||
|
|
||||||
// AnnotateForceSync sets the force-sync annotation on an ExternalSecret
|
// AnnotateForceSync sets the force-sync annotation on an ExternalSecret
|
||||||
// object to trigger an immediate re-sync from the upstream secret store.
|
// object to trigger an immediate re-sync from the upstream secret store.
|
||||||
func AnnotateForceSync(namespace, externalSecretName string, unixTimestamp int64) (string, error) {
|
func AnnotateForceSync(context, namespace, externalSecretName string, unixTimestamp int64) (string, error) {
|
||||||
annotation := fmt.Sprintf("force-sync=%d", unixTimestamp)
|
annotation := fmt.Sprintf("force-sync=%d", unixTimestamp)
|
||||||
return runOutput("kubectl", "-n", namespace, "annotate", "externalsecret",
|
args := kubectlArgs(context, "-n", namespace, "annotate", "externalsecret",
|
||||||
externalSecretName, annotation, "--overwrite")
|
externalSecretName, annotation, "--overwrite")
|
||||||
}
|
return runOutput("kubectl", args...)
|
||||||
|
|
||||||
// ListAWSSecrets returns all AWS Secrets Manager secret names/IDs visible
|
|
||||||
// in the given region (subject to the caller's IAM permissions).
|
|
||||||
func ListAWSSecrets(region string) ([]string, error) {
|
|
||||||
out, err := runOutput("aws", "secretsmanager", "list-secrets",
|
|
||||||
"--region", region, "--query", "SecretList[].Name", "--output", "json")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var names []string
|
|
||||||
if err := json.Unmarshal([]byte(out), &names); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return names, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAWSSecretString fetches the SecretString of an AWS Secrets Manager
|
// GetAWSSecretString fetches the SecretString of an AWS Secrets Manager
|
||||||
// secret via the aws-cli.
|
// secret via the aws-cli. The secret ID is computed from config templates
|
||||||
|
// (see internal/config), not looked up interactively.
|
||||||
func GetAWSSecretString(secretID, region string) (string, error) {
|
func GetAWSSecretString(secretID, region string) (string, error) {
|
||||||
return runOutput("aws", "secretsmanager", "get-secret-value",
|
return runOutput("aws", "secretsmanager", "get-secret-value",
|
||||||
"--secret-id", secretID, "--region", region,
|
"--secret-id", secretID, "--region", region,
|
||||||
|
|||||||
Reference in New Issue
Block a user