package cluster import ( "fmt" "os" "path/filepath" "github.com/spf13/cobra" "github.com/wild-cloud/wild-cli/internal/config" "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 newConfigCommand() *cobra.Command { cmd := &cobra.Command{ Use: "config", Short: "Manage cluster configuration", Long: `Generate and manage cluster configuration files.`, } cmd.AddCommand( newConfigGenerateCommand(), ) return cmd } func newConfigGenerateCommand() *cobra.Command { return &cobra.Command{ Use: "generate", Short: "Generate cluster configuration", Long: `Generate Talos configuration files for the cluster. This command creates initial cluster secrets and configuration files using talosctl. Examples: wild cluster config generate`, RunE: runConfigGenerate, } } func runConfigGenerate(cmd *cobra.Command, args []string) error { output.Header("Talos Cluster Configuration Generation") // 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{"talosctl"}); err != nil { return fmt.Errorf("required tools not available: %w", err) } // Load configuration configMgr := config.NewManager(env.ConfigPath(), env.SecretsPath()) // Ensure required directories exist nodeSetupDir := filepath.Join(env.WildCloudDir(), "setup", "cluster-nodes") generatedDir := filepath.Join(nodeSetupDir, "generated") // Check if generated directory already exists and has content if entries, err := os.ReadDir(generatedDir); err == nil && len(entries) > 0 { output.Success("Cluster configuration already exists in " + generatedDir) output.Info("Skipping cluster configuration generation") return nil } if err := os.MkdirAll(generatedDir, 0755); err != nil { return fmt.Errorf("creating generated directory: %w", err) } // Get required configuration values clusterName, err := getRequiredConfig(configMgr, "cluster.name", "wild-cluster") if err != nil { return err } vip, err := getRequiredConfig(configMgr, "cluster.nodes.control.vip", "") if err != nil { return err } output.Info("Generating new cluster secrets...") // Remove existing secrets directory if it exists if _, err := os.Stat(generatedDir); err == nil { output.Warning("Removing existing secrets directory...") if err := os.RemoveAll(generatedDir); err != nil { return fmt.Errorf("removing existing generated directory: %w", err) } } if err := os.MkdirAll(generatedDir, 0755); err != nil { return fmt.Errorf("creating generated directory: %w", err) } // Generate cluster configuration output.Info("Generating initial cluster configuration...") output.Info("Cluster name: " + clusterName) output.Info("Control plane endpoint: https://" + vip + ":6443") // Change to generated directory for talosctl operations oldDir, err := os.Getwd() if err != nil { return fmt.Errorf("getting current directory: %w", err) } if err := os.Chdir(generatedDir); err != nil { return fmt.Errorf("changing to generated directory: %w", err) } defer func() { _ = os.Chdir(oldDir) }() talosctl := toolManager.Talosctl() // Generate secrets first if err := talosctl.GenerateSecrets(cmd.Context()); err != nil { return fmt.Errorf("generating secrets: %w", err) } // Generate configuration with secrets endpoint := "https://" + vip + ":6443" if err := talosctl.GenerateConfigWithSecrets(cmd.Context(), clusterName, endpoint, "secrets.yaml"); err != nil { return fmt.Errorf("generating config with secrets: %w", err) } output.Success("Cluster configuration generation completed!") output.Info("Generated files in: " + generatedDir) output.Info(" - controlplane.yaml # Control plane node configuration") output.Info(" - worker.yaml # Worker node configuration") output.Info(" - talosconfig # Talos client configuration") output.Info(" - secrets.yaml # Cluster secrets") return nil } // getRequiredConfig gets a required configuration value, prompting if not set func getRequiredConfig(configMgr *config.Manager, path, defaultValue string) (string, error) { value, err := configMgr.Get(path) if err != nil || value == nil || value.(string) == "" { if defaultValue != "" { output.Warning(fmt.Sprintf("Config '%s' not set, using default: %s", path, defaultValue)) return defaultValue, nil } else { return "", fmt.Errorf("required configuration '%s' not set", path) } } strValue, ok := value.(string) if !ok { return "", fmt.Errorf("configuration '%s' is not a string", path) } return strValue, nil }