maidn-cli/internal/ui/wizard.go

165 lines
6.8 KiB
Go

package ui
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"github.com/Pingu-Studio/MaidnCLI/internal/config"
)
func RunBootstrapWizard() (config.Config, error) {
reader := bufio.NewReader(os.Stdin)
cfg := config.Config{}
cfg.WorkspaceDir = prompt(reader, "Workspace directory", ".\\maidn-workspace")
cfg.GitHub.Org = prompt(reader, "GitHub organization", "Pingu-Studio")
cfg.Flux.Owner = cfg.GitHub.Org
cfg.Flux.RepoName = prompt(reader, "Flux repo name", "mcast-maidn-cd-cluster")
cfg.Flux.Branch = prompt(reader, "Flux branch", "main")
cfg.Flux.ClusterPath = prompt(reader, "Flux cluster path", "./clusters/maidn-cd-0")
cfg.Flux.ClusterDomain = prompt(reader, "Flux cluster domain", "dev01.nid3.com")
cfg.Talos.RepoURL = prompt(reader, "Talos IaC repo URL", "https://github.com/Pingu-Studio/maidn-talos-proxmox.git")
cfg.Talos.RepoRef = prompt(reader, "Talos IaC repo ref", "main")
cfg.Talos.RepoDirName = prompt(reader, "Talos IaC checkout directory", "maidn-talos-proxmox")
cfg.Talos.TerraformDir = prompt(reader, "Terraform subdirectory", "terraform")
cfg.Talos.GeneratedDir = prompt(reader, "Generated subdirectory", "generated")
cfg.Talos.ConfigFileName = prompt(reader, "Terraform config filename", "terraform.tfvars")
cfg.Talos.AutoRunTerraform = promptBool(reader, "Run terraform automatically", true)
cfg.Talos.AutoBootstrap = promptBool(reader, "Run talos bootstrap automatically", true)
cfg.Talos.AutoBootstrapFlux = promptBool(reader, "Run flux bootstrap automatically", true)
cfg.Talos.Proxmox.APIURL = prompt(reader, "Proxmox API URL", "https://192.168.0.9:8006/api2/json")
cfg.Talos.Proxmox.APIToken = prompt(reader, "Proxmox API token", "")
cfg.Talos.Proxmox.DefaultNode = prompt(reader, "Default Proxmox node", "pingu4")
cfg.Talos.Proxmox.Pool = prompt(reader, "Proxmox pool", "")
cfg.Talos.Proxmox.NodeInterfaces = promptMap(reader, "Node interfaces map (node=iface,comma separated)", map[string]string{"pingu4": "enp6s0"})
cfg.Talos.Cluster.Name = prompt(reader, "Talos cluster name", "proxmox-talos-dev01-cluster")
cfg.Talos.Cluster.Domain = prompt(reader, "Talos cluster domain", "dev01.nid3.com")
cfg.Talos.Cluster.ControlPlaneVIP = prompt(reader, "Control plane VIP", "192.168.43.7")
cfg.Talos.Cluster.CNI = prompt(reader, "CNI", "flannel")
cfg.Talos.Cluster.DNSServers = promptList(reader, "DNS servers (comma separated)", []string{"192.168.0.222", "1.1.1.1"})
cfg.Talos.Cluster.DiskStorage = prompt(reader, "Primary disk storage", "local-lvm")
cfg.Talos.Cluster.AdditionalStorage = prompt(reader, "Additional disk storage", "local-lvm")
cfg.Talos.Cluster.CreateVLANInterface = promptBool(reader, "Create VLAN interfaces", true)
cfg.Talos.Image.FactorySchematicID = prompt(reader, "Talos factory schematic ID", "ddf38e55e30aa9b2bb0b765054ed63444dc00244ab8bb4ad4ad92486602285f8")
cfg.Talos.Image.TalosVersion = prompt(reader, "Talos version", "v1.11.1")
cfg.Talos.Image.TalosISOFile = prompt(reader, "Talos ISO file", "local:iso/talos-1.11.1.iso")
cfg.Talos.Image.UpdateMode = prompt(reader, "Talos image update mode (manual/download)", "manual")
cfg.Talos.Image.Storage = prompt(reader, "Talos image storage", "local")
cfg.Talos.Image.Architecture = prompt(reader, "Talos image architecture", "amd64")
cfg.Talos.Nodes = promptNodes(reader, cfg.Talos.Proxmox.DefaultNode)
if len(cfg.Talos.Nodes) > 0 {
cfg.Talos.BootstrapNode = prompt(reader, "Talos bootstrap node IP", cfg.Talos.Nodes[0].Networks[0].IP)
cfg.Talos.KubeconfigNode = prompt(reader, "Talos kubeconfig node IP", cfg.Talos.Nodes[0].Networks[0].IP)
}
return cfg, nil
}
func prompt(reader *bufio.Reader, label, fallback string) string {
if fallback != "" {
fmt.Printf("%s [%s]: ", label, fallback)
} else {
fmt.Printf("%s: ", label)
}
value, _ := reader.ReadString('\n')
value = strings.TrimSpace(value)
if value == "" {
return fallback
}
return value
}
func promptBool(reader *bufio.Reader, label string, fallback bool) bool {
defaultValue := "y"
if !fallback {
defaultValue = "n"
}
fmt.Printf("%s [y/n, default %s]: ", label, defaultValue)
value, _ := reader.ReadString('\n')
value = strings.TrimSpace(strings.ToLower(value))
if value == "" {
return fallback
}
return value == "y" || value == "yes"
}
func promptList(reader *bufio.Reader, label string, fallback []string) []string {
value := prompt(reader, label, strings.Join(fallback, ","))
parts := strings.Split(value, ",")
out := make([]string, 0, len(parts))
for _, part := range parts {
part = strings.TrimSpace(part)
if part != "" {
out = append(out, part)
}
}
return out
}
func promptMap(reader *bufio.Reader, label string, fallback map[string]string) map[string]string {
pairs := make([]string, 0, len(fallback))
for key, value := range fallback {
pairs = append(pairs, key+"="+value)
}
value := prompt(reader, label, strings.Join(pairs, ","))
result := map[string]string{}
for _, pair := range strings.Split(value, ",") {
parts := strings.SplitN(strings.TrimSpace(pair), "=", 2)
if len(parts) == 2 && parts[0] != "" && parts[1] != "" {
result[parts[0]] = parts[1]
}
}
return result
}
func promptNodes(reader *bufio.Reader, defaultNode string) []config.TalosNode {
countValue := prompt(reader, "Number of Talos nodes", "3")
count, err := strconv.Atoi(countValue)
if err != nil || count < 1 {
count = 3
}
result := make([]config.TalosNode, 0, count)
for i := 0; i < count; i++ {
name := prompt(reader, fmt.Sprintf("Node %d name", i+1), fmt.Sprintf("talos-node-%02d", i+1))
role := prompt(reader, fmt.Sprintf("Node %d role", i+1), map[bool]string{i == 0: "controlplane", i != 0: "worker"}[true])
vmid, _ := strconv.Atoi(prompt(reader, fmt.Sprintf("Node %d VMID", i+1), fmt.Sprintf("10%d", 50+i)))
cores, _ := strconv.Atoi(prompt(reader, fmt.Sprintf("Node %d cores", i+1), "4"))
memory, _ := strconv.Atoi(prompt(reader, fmt.Sprintf("Node %d memory MB", i+1), "8192"))
diskSize := prompt(reader, fmt.Sprintf("Node %d disk size", i+1), "64G")
proxmoxNode := prompt(reader, fmt.Sprintf("Node %d Proxmox node", i+1), defaultNode)
tags := promptList(reader, fmt.Sprintf("Node %d tags", i+1), []string{"talos", role})
mac := prompt(reader, fmt.Sprintf("Node %d primary MAC", i+1), "")
cidr := prompt(reader, fmt.Sprintf("Node %d primary CIDR", i+1), "192.168.43.0/28")
ip := prompt(reader, fmt.Sprintf("Node %d primary IP", i+1), "")
gateway := prompt(reader, fmt.Sprintf("Node %d gateway", i+1), "192.168.43.1")
vlanID, _ := strconv.Atoi(prompt(reader, fmt.Sprintf("Node %d VLAN ID", i+1), "43"))
result = append(result, config.TalosNode{
Name: name,
VMID: vmid,
Role: role,
Cores: cores,
Memory: memory,
DiskSize: diskSize,
Tags: tags,
ProxmoxNode: proxmoxNode,
Networks: []config.TalosNetwork{{
MACAddress: mac,
CIDR: cidr,
IP: ip,
Gateway: gateway,
VLANID: vlanID,
}},
})
}
return result
}