Files
wild-cli/cmd/instance.go
2025-10-11 17:19:11 +00:00

277 lines
7.0 KiB
Go

package cmd
import (
"fmt"
"os"
"path/filepath"
"github.com/spf13/cobra"
"github.com/wild-cloud/wild-central/wild/internal/config"
)
var instanceCmd = &cobra.Command{
Use: "instance",
Short: "Manage instances",
Long: `Create, list, and manage Wild Cloud instances.`,
}
var instanceCreateCmd = &cobra.Command{
Use: "create <name>",
Short: "Create a new instance",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
resp, err := apiClient.Post("/api/v1/instances", map[string]string{
"name": name,
})
if err != nil {
return err
}
fmt.Printf("Instance '%s' created successfully\n", name)
if msg, ok := resp.Data["message"].(string); ok && msg != "" {
fmt.Println(msg)
}
return nil
},
}
var instanceListCmd = &cobra.Command{
Use: "list",
Short: "List all instances",
RunE: func(cmd *cobra.Command, args []string) error {
resp, err := apiClient.Get("/api/v1/instances")
if err != nil {
return err
}
if outputFormat == "json" {
return printJSON(resp.Data)
}
if outputFormat == "yaml" {
return printYAML(resp.Data)
}
instances := resp.GetArray("instances")
if len(instances) == 0 {
fmt.Println("No instances found")
return nil
}
fmt.Println("INSTANCES:")
for _, inst := range instances {
if name, ok := inst.(string); ok {
fmt.Printf(" - %s\n", name)
}
}
return nil
},
}
var instanceShowCmd = &cobra.Command{
Use: "show <name>",
Short: "Show instance details",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s", name))
if err != nil {
return err
}
if outputFormat == "json" {
return printJSON(resp.Data)
}
if outputFormat == "yaml" {
return printYAML(resp.Data)
}
// Pretty print instance info
instanceName := resp.GetString("name")
if instanceName != "" {
fmt.Printf("Instance: %s\n", instanceName)
}
// Show key config values
if config := resp.GetMap("config"); config != nil {
// Check for cloud config (test-cloud structure)
if cloud, ok := config["cloud"].(map[string]interface{}); ok {
if domain, ok := cloud["domain"].(string); ok && domain != "" {
fmt.Printf("Domain: %s\n", domain)
}
if baseDomain, ok := cloud["baseDomain"].(string); ok && baseDomain != "" {
fmt.Printf("Base Domain: %s\n", baseDomain)
}
} else {
// Check for direct config fields (test-cli structure)
if domain, ok := config["domain"].(string); ok && domain != "" {
fmt.Printf("Domain: %s\n", domain)
}
if baseDomain, ok := config["baseDomain"].(string); ok && baseDomain != "" {
fmt.Printf("Base Domain: %s\n", baseDomain)
}
}
// Show cluster info if available
if cluster, ok := config["cluster"].(map[string]interface{}); ok {
if clusterName, ok := cluster["name"].(string); ok && clusterName != "" {
fmt.Printf("Cluster Name: %s\n", clusterName)
}
}
}
fmt.Println("\nUse -o json or -o yaml for full configuration")
return nil
},
}
var instanceDeleteCmd = &cobra.Command{
Use: "delete <name>",
Short: "Delete an instance",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
// Confirm deletion
fmt.Printf("Are you sure you want to delete instance '%s'? (yes/no): ", name)
var confirm string
fmt.Scanln(&confirm)
if confirm != "yes" {
fmt.Println("Deletion cancelled")
return nil
}
resp, err := apiClient.Delete(fmt.Sprintf("/api/v1/instances/%s", name))
if err != nil {
return err
}
fmt.Printf("Instance '%s' deleted successfully\n", name)
if msg, ok := resp.Data["message"].(string); ok && msg != "" {
fmt.Println(msg)
}
return nil
},
}
var instanceCurrentCmd = &cobra.Command{
Use: "current",
Short: "Show current instance",
Long: `Display the instance that would be used by commands.
Resolution order:
1. --instance flag
2. ~/.wildcloud/current_instance file
3. Auto-select first available instance`,
Run: func(cmd *cobra.Command, args []string) {
inst, err := getInstanceName()
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
fmt.Println(inst)
},
}
var instanceUseCmd = &cobra.Command{
Use: "use <name>",
Short: "Set the default instance",
Long: `Set the default instance to use for all commands.
This persists the instance selection to ~/.wildcloud/current_instance.
The instance can still be overridden with the --instance flag.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
instanceToSet := args[0]
// Validate instance exists by calling API
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s", instanceToSet))
if err != nil {
return fmt.Errorf("instance '%s' not found: %w", instanceToSet, err)
}
// Verify we got a valid response
if name := resp.GetString("name"); name != instanceToSet {
return fmt.Errorf("instance '%s' not found", instanceToSet)
}
// Persist the selection
if err := config.SetCurrentInstance(instanceToSet); err != nil {
return fmt.Errorf("failed to set current instance: %w", err)
}
fmt.Printf("Switched to instance: %s\n", instanceToSet)
// Check for config files and provide hint
dataDir := config.GetWildCLIDataDir()
instanceDir := filepath.Join(dataDir, "instances", instanceToSet)
var hasConfigs bool
if _, err := os.Stat(filepath.Join(instanceDir, "talosconfig")); err == nil {
hasConfigs = true
}
if _, err := os.Stat(filepath.Join(instanceDir, "kubeconfig")); err == nil {
hasConfigs = true
}
if hasConfigs {
fmt.Println("\nTo configure your environment, run:")
fmt.Println(" source <(wild instance env)")
}
return nil
},
}
var instanceEnvCmd = &cobra.Command{
Use: "env",
Short: "Output environment variables for current instance",
Long: `Output export commands for TALOSCONFIG and KUBECONFIG.
Usage:
source <(wild instance env)
This will set environment variables for the current instance's talosconfig and kubeconfig files if they exist.`,
RunE: func(cmd *cobra.Command, args []string) error {
// Get current instance
inst, err := getInstanceName()
if err != nil {
return err
}
// Check for talosconfig and kubeconfig files
dataDir := config.GetWildCLIDataDir()
instanceDir := filepath.Join(dataDir, "instances", inst)
// Check for talosconfig
talosconfigPath := filepath.Join(instanceDir, "talosconfig")
if _, err := os.Stat(talosconfigPath); err == nil {
fmt.Printf("export TALOSCONFIG=%s\n", talosconfigPath)
}
// Check for kubeconfig
kubeconfigPath := filepath.Join(instanceDir, "kubeconfig")
if _, err := os.Stat(kubeconfigPath); err == nil {
fmt.Printf("export KUBECONFIG=%s\n", kubeconfigPath)
}
return nil
},
}
func init() {
instanceCmd.AddCommand(instanceCreateCmd)
instanceCmd.AddCommand(instanceListCmd)
instanceCmd.AddCommand(instanceShowCmd)
instanceCmd.AddCommand(instanceDeleteCmd)
instanceCmd.AddCommand(instanceCurrentCmd)
instanceCmd.AddCommand(instanceUseCmd)
instanceCmd.AddCommand(instanceEnvCmd)
}