feat: .env file support — skip prompts on repeat deploys

- /opt/fw/.env stores token, cloud, node, port, upstream
- If .env exists with WALLARM_TOKEN, all prompts are skipped
- Saved automatically after successful deployment
- Perfect for testing: edit .env once, deploy repeatedly
This commit is contained in:
admin 2026-08-01 19:20:51 +00:00
parent cbe6d51ac6
commit e9dff30d84

View file

@ -37,94 +37,128 @@ func runDeployFlow(r preflight.Result) {
var s state.State
s.DeploymentType = "native"
// Step 1: Cloud region
fmt.Println()
fmt.Println("─── Cloud Region ───")
if r.USReachable && r.EUReachable {
fmt.Println(" [1] US (us1.api.wallarm.com)")
fmt.Println(" [2] EU (api.wallarm.com)")
fmt.Print("Choose region [1/2]: ")
choice, _ := reader.ReadString('\n')
choice = strings.TrimSpace(choice)
if choice == "2" {
s.CloudRegion = "EU"
s.APIHost = "api.wallarm.com"
// Check for .env file — skip prompts if present
envPath := "/opt/fw/.env"
envData, _ := os.ReadFile(envPath)
envMap := parseEnv(string(envData))
skipPrompts := envMap["WALLARM_TOKEN"] != ""
if skipPrompts {
fmt.Println()
fmt.Println("Using saved configuration from /opt/fw/.env")
s.CloudRegion = envMap["WALLARM_CLOUD"]
if s.CloudRegion == "US" {
s.APIHost = "us1.api.wallarm.com"
} else {
s.APIHost = "api.wallarm.com"
}
s.APIToken = envMap["WALLARM_TOKEN"]
} else {
// Step 1: Cloud region
fmt.Println()
fmt.Println("─── Cloud Region ───")
if r.USReachable && r.EUReachable {
fmt.Println(" [1] US (us1.api.wallarm.com)")
fmt.Println(" [2] EU (api.wallarm.com)")
fmt.Print("Choose region [1/2]: ")
choice, _ := reader.ReadString('\n')
choice = strings.TrimSpace(choice)
if choice == "2" {
s.CloudRegion = "EU"
s.APIHost = "api.wallarm.com"
} else {
s.CloudRegion = "US"
s.APIHost = "us1.api.wallarm.com"
}
} else if r.USReachable {
fmt.Println(" US (us1.api.wallarm.com) — only reachable region")
s.CloudRegion = "US"
s.APIHost = "us1.api.wallarm.com"
} else {
fmt.Println(" EU (api.wallarm.com) — only reachable region")
s.CloudRegion = "EU"
s.APIHost = "api.wallarm.com"
}
} else if r.USReachable {
fmt.Println(" US (us1.api.wallarm.com) — only reachable region")
s.CloudRegion = "US"
s.APIHost = "us1.api.wallarm.com"
} else {
fmt.Println(" EU (api.wallarm.com) — only reachable region")
s.CloudRegion = "EU"
s.APIHost = "api.wallarm.com"
}
// Step 2: API Token
fmt.Println()
fmt.Print("Wallarm API Token (Deploy role): ")
token, _ := reader.ReadString('\n')
s.APIToken = strings.TrimSpace(token)
if s.APIToken == "" {
fmt.Println("Token cannot be empty.")
return
// Step 2: API Token
fmt.Println()
fmt.Print("Wallarm API Token (Deploy role): ")
token, _ := reader.ReadString('\n')
s.APIToken = strings.TrimSpace(token)
if s.APIToken == "" {
fmt.Println("Token cannot be empty.")
return
}
}
// Step 3: Node configuration
fmt.Println()
fmt.Print("Node name: ")
nodeName, _ := reader.ReadString('\n')
nodeName = strings.TrimSpace(nodeName)
if nodeName == "" {
fmt.Println("Node name required.")
return
var nodeName, port, upstreamIP, upstreamPort, labels string
if skipPrompts {
nodeName = envMap["WALLARM_NODE"]
port = envMap["WALLARM_PORT"]
upstreamIP = envMap["WALLARM_UPSTREAM_IP"]
upstreamPort = envMap["WALLARM_UPSTREAM_PORT"]
labels = envMap["WALLARM_LABELS"]
fmt.Printf("\n Node: %s | Port: %s | Upstream: %s:%s | Cloud: %s\n",
nodeName, port, upstreamIP, upstreamPort, s.CloudRegion)
} else {
fmt.Println()
fmt.Print("Node name: ")
nodeName, _ = reader.ReadString('\n')
nodeName = strings.TrimSpace(nodeName)
if nodeName == "" {
fmt.Println("Node name required.")
return
}
fmt.Print("Listen port [8081]: ")
port, _ = reader.ReadString('\n')
port = strings.TrimSpace(port)
if port == "" {
port = "8081"
}
fmt.Print("Upstream IP [127.0.0.1]: ")
upstreamIP, _ = reader.ReadString('\n')
upstreamIP = strings.TrimSpace(upstreamIP)
if upstreamIP == "" {
upstreamIP = "127.0.0.1"
}
fmt.Print("Upstream port [80]: ")
upstreamPort, _ = reader.ReadString('\n')
upstreamPort = strings.TrimSpace(upstreamPort)
if upstreamPort == "" {
upstreamPort = "80"
}
fmt.Print("Labels [group=" + nodeName + "]: ")
labels, _ = reader.ReadString('\n')
labels = strings.TrimSpace(labels)
if labels == "" {
labels = "group=" + nodeName
}
fmt.Println()
fmt.Printf(" Node: %s\n", nodeName)
fmt.Printf(" Listen: %s\n", "0.0.0.0:"+port)
fmt.Printf(" Upstream: %s:%s\n", upstreamIP, upstreamPort)
fmt.Printf(" Region: %s (%s)\n", s.CloudRegion, s.APIHost)
fmt.Print("\nProceed with deployment? [Y/n]: ")
confirm, _ := reader.ReadString('\n')
confirm = strings.TrimSpace(strings.ToLower(confirm))
if confirm != "" && confirm != "y" && confirm != "yes" {
fmt.Println("Cancelled.")
return
}
}
fmt.Print("Listen port [8081]: ")
port, _ := reader.ReadString('\n')
port = strings.TrimSpace(port)
if port == "" {
port = "8081"
}
if port == "" { port = "8081" }
if upstreamIP == "" { upstreamIP = "127.0.0.1" }
if upstreamPort == "" { upstreamPort = "80" }
if labels == "" { labels = "group=" + nodeName }
address := "0.0.0.0:" + port
fmt.Print("Upstream IP [127.0.0.1]: ")
upstreamIP, _ := reader.ReadString('\n')
upstreamIP = strings.TrimSpace(upstreamIP)
if upstreamIP == "" {
upstreamIP = "127.0.0.1"
}
fmt.Print("Upstream port [80]: ")
upstreamPort, _ := reader.ReadString('\n')
upstreamPort = strings.TrimSpace(upstreamPort)
if upstreamPort == "" {
upstreamPort = "80"
}
fmt.Print("Labels [group=" + nodeName + "]: ")
labels, _ := reader.ReadString('\n')
labels = strings.TrimSpace(labels)
if labels == "" {
labels = "group=" + nodeName
}
fmt.Println()
fmt.Printf(" Node: %s\n", nodeName)
fmt.Printf(" Listen: %s\n", address)
fmt.Printf(" Upstream: %s:%s\n", upstreamIP, upstreamPort)
fmt.Printf(" Region: %s (%s)\n", s.CloudRegion, s.APIHost)
fmt.Print("\nProceed with deployment? [Y/n]: ")
confirm, _ := reader.ReadString('\n')
confirm = strings.TrimSpace(strings.ToLower(confirm))
if confirm != "" && confirm != "y" && confirm != "yes" {
fmt.Println("Cancelled.")
return
}
baseDir := "/opt/fw"
instanceDir := baseDir + "/" + nodeName + "/wallarm"
@ -178,6 +212,11 @@ WALLARM_REGION=%s
fmt.Fprintf(os.Stderr, "Warning: could not save state: %v\n", err)
}
// Save .env for future runs
os.WriteFile(envPath, []byte(fmt.Sprintf(
"WALLARM_TOKEN=%s\nWALLARM_CLOUD=%s\nWALLARM_NODE=%s\nWALLARM_PORT=%s\nWALLARM_UPSTREAM_IP=%s\nWALLARM_UPSTREAM_PORT=%s\nWALLARM_LABELS=%s\n",
s.APIToken, s.CloudRegion, nodeName, port, upstreamIP, upstreamPort, labels)), 0644)
fmt.Println()
fmt.Println("✅ Deployment complete!")
fmt.Println()
@ -334,3 +373,18 @@ deployment. On subsequent runs, it shows your existing deployments.
}
}
}
func parseEnv(data string) map[string]string {
m := map[string]string{}
for _, line := range strings.Split(data, "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 {
m[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
}
}
return m
}