165 lines
6.8 KiB
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
|
|
}
|