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 }