Files
wild-cloud/wild-cli/cmd/wild/util/dashboard.go

158 lines
4.6 KiB
Go

package util
import (
"context"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/wild-cloud/wild-cli/internal/environment"
"github.com/wild-cloud/wild-cli/internal/external"
"github.com/wild-cloud/wild-cli/internal/output"
)
func NewDashboardCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "dashboard",
Short: "Manage Kubernetes dashboard",
Long: `Manage access to the Kubernetes dashboard.`,
}
cmd.AddCommand(
newDashboardTokenCommand(),
)
return cmd
}
func newDashboardTokenCommand() *cobra.Command {
return &cobra.Command{
Use: "token",
Short: "Get dashboard access token",
Long: `Get an access token for the Kubernetes dashboard.
This command retrieves the authentication token needed to access the Kubernetes dashboard.
Examples:
wild dashboard token`,
RunE: runDashboardToken,
}
}
func runDashboardToken(cmd *cobra.Command, args []string) error {
output.Header("Kubernetes Dashboard Token")
// Initialize environment
env := environment.New()
if err := env.RequiresProject(); err != nil {
return err
}
// Check external tools
toolManager := external.NewManager()
if err := toolManager.CheckTools(cmd.Context(), []string{"kubectl"}); err != nil {
return fmt.Errorf("required tools not available: %w", err)
}
kubectl := toolManager.Kubectl()
// The namespace where the dashboard is installed
namespace := "kubernetes-dashboard"
secretName := "dashboard-admin-token"
// Try to get the token from the secret
token, err := getDashboardToken(cmd.Context(), kubectl, namespace, secretName)
if err != nil {
return fmt.Errorf("failed to get dashboard token: %w", err)
}
// Print the token with nice formatting
output.Success("Use this token to authenticate to the Kubernetes Dashboard:")
output.Info("")
output.Printf("%s\n", token)
output.Info("")
// Additional instructions
output.Info("Instructions:")
output.Info("1. Copy the token above")
output.Info("2. Navigate to your Kubernetes Dashboard URL")
output.Info("3. Select 'Token' authentication method")
output.Info("4. Paste the token and click 'Sign In'")
return nil
}
// getDashboardToken retrieves the dashboard token from Kubernetes
func getDashboardToken(ctx context.Context, kubectl *external.KubectlTool, namespace, secretName string) (string, error) {
// Try to get the secret directly
secretData, err := kubectl.GetResource(ctx, "secret", secretName, namespace)
if err != nil {
// If secret doesn't exist, try to find any admin-related secret
output.Warning("Dashboard admin token secret not found, searching for available tokens...")
return findDashboardToken(ctx, kubectl, namespace)
}
// Extract token from secret data
// The secret data is in YAML format, we need to parse it
secretStr := string(secretData)
lines := strings.Split(secretStr, "\n")
for _, line := range lines {
if strings.Contains(line, "token:") {
// Extract the base64 encoded token
parts := strings.Fields(line)
if len(parts) >= 2 {
encodedToken := parts[1]
// Decode base64 token using kubectl
tokenBytes, err := kubectl.Execute(ctx, "exec", "deploy/coredns", "-n", "kube-system", "--", "base64", "-d")
if err != nil {
// Try alternative method with echo and base64
echoCmd := fmt.Sprintf("echo '%s' | base64 -d", encodedToken)
tokenBytes, err = kubectl.Execute(ctx, "exec", "deploy/coredns", "-n", "kube-system", "--", "sh", "-c", echoCmd)
if err != nil {
// Return the encoded token as fallback
return encodedToken, nil
}
}
return strings.TrimSpace(string(tokenBytes)), nil
}
}
}
return "", fmt.Errorf("token not found in secret data")
}
// findDashboardToken searches for available dashboard tokens
func findDashboardToken(ctx context.Context, kubectl *external.KubectlTool, namespace string) (string, error) {
// List all secrets in the dashboard namespace
secrets, err := kubectl.GetResource(ctx, "secrets", "", namespace)
if err != nil {
return "", fmt.Errorf("failed to list secrets in namespace %s: %w", namespace, err)
}
// Look for tokens in the secret list
secretsStr := string(secrets)
lines := strings.Split(secretsStr, "\n")
var tokenSecrets []string
for _, line := range lines {
if strings.Contains(line, "token") && strings.Contains(line, "dashboard") {
parts := strings.Fields(line)
if len(parts) > 0 {
tokenSecrets = append(tokenSecrets, parts[0])
}
}
}
if len(tokenSecrets) == 0 {
return "", fmt.Errorf("no dashboard token secrets found in namespace %s", namespace)
}
// Try the first available token secret
secretName := tokenSecrets[0]
output.Info("Using token secret: " + secretName)
return getDashboardToken(ctx, kubectl, namespace, secretName)
}