177 lines
4.9 KiB
Go
177 lines
4.9 KiB
Go
package native
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.sechpoint.app/customer-engineering/wallarm/internal/state"
|
|
)
|
|
|
|
const (
|
|
BaseDir = "/opt/fw"
|
|
DeployTo = "/opt/wallarm" // setup.sh hardcodes this, deploy here then move
|
|
)
|
|
|
|
func installerURL() string {
|
|
if u := os.Getenv("WALLARM_INSTALLER_URL"); u != "" {
|
|
return u
|
|
}
|
|
return "https://storage.googleapis.com/meganode_storage/6.12/wallarm-6.12.5.x86_64-glibc.sh"
|
|
}
|
|
|
|
func InstallNode(node state.Node, apiToken, apiHost, labels string) error {
|
|
if apiToken == "" {
|
|
return fmt.Errorf("API token required")
|
|
}
|
|
_ = labels
|
|
|
|
instanceDir := filepath.Join(BaseDir, node.Name, "wallarm")
|
|
installerPath := filepath.Join(BaseDir, "wallarm-aio.sh")
|
|
|
|
// 1. Prepare clean /opt/wallarm for this deployment
|
|
os.RemoveAll(DeployTo)
|
|
os.MkdirAll(DeployTo, 0755)
|
|
|
|
// 2. Kill any existing process on the target port, then start per-instance NGINX
|
|
port := "80"
|
|
if idx := strings.LastIndex(node.Address, ":"); idx != -1 {
|
|
port = node.Address[idx+1:]
|
|
}
|
|
killPort(port)
|
|
copyNginx(DeployTo)
|
|
startNginx(DeployTo, node, port)
|
|
|
|
// 3. Download AIO once
|
|
if _, err := os.Stat(installerPath); os.IsNotExist(err) {
|
|
fmt.Printf("[%s] Downloading installer...\n", node.Name)
|
|
cmd := exec.Command("curl", "-fsSL", "-o", installerPath, installerURL())
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("download: %w\n%s", err, string(out))
|
|
}
|
|
os.Chmod(installerPath, 0755)
|
|
}
|
|
|
|
// 4. Extract AIO to /opt/wallarm
|
|
fmt.Printf("[%s] Extracting...\n", node.Name)
|
|
cmd := exec.Command("bash", installerPath, "--noexec", "--keep", "--target", DeployTo, "--noprogress", "--accept")
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("extract: %w\n%s", err, string(out))
|
|
}
|
|
|
|
// 5. Fix: recreate env.list in background while setup.sh runs
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
for {
|
|
select {
|
|
case <-done:
|
|
return
|
|
default:
|
|
os.WriteFile(filepath.Join(DeployTo, "env.list"),
|
|
[]byte("# wallarm env\n"), 0644)
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
}
|
|
}()
|
|
|
|
// 6. Load Wallarm NGINX module + register node
|
|
fmt.Printf("[%s] Configuring NGINX module...\n", node.Name)
|
|
exec.Command("bash", filepath.Join(DeployTo, "pick-module.sh")).Run()
|
|
|
|
fmt.Printf("[%s] Registering node...\n", node.Name)
|
|
registerCmd := exec.Command(filepath.Join(DeployTo, "register-node"),
|
|
"-token", apiToken,
|
|
"-host", apiHost,
|
|
)
|
|
registerCmd.Dir = DeployTo
|
|
|
|
out, regErr := registerCmd.CombinedOutput()
|
|
if regErr != nil {
|
|
return fmt.Errorf("register: %w\n%s", regErr, string(out))
|
|
}
|
|
|
|
// 7. Move /opt/wallarm → /opt/fw/{name}/wallarm
|
|
os.MkdirAll(filepath.Join(BaseDir, node.Name), 0755)
|
|
os.RemoveAll(instanceDir)
|
|
os.Rename(DeployTo, instanceDir)
|
|
fmt.Printf("[%s] Done. Installed to %s\n", node.Name, instanceDir)
|
|
return nil
|
|
}
|
|
|
|
func copyNginx(dir string) {
|
|
dst := filepath.Join(dir, "nginx", "sbin", "nginx")
|
|
if _, err := os.Stat(dst); err == nil {
|
|
return
|
|
}
|
|
os.MkdirAll(filepath.Dir(dst), 0755)
|
|
if path, err := exec.LookPath("nginx"); err == nil {
|
|
exec.Command("cp", path, dst).Run()
|
|
return
|
|
}
|
|
for _, pm := range [][]string{
|
|
{"apt-get", "install", "-y", "-qq", "nginx"},
|
|
{"yum", "install", "-y", "-q", "nginx"},
|
|
} {
|
|
if _, err := exec.LookPath(pm[0]); err == nil {
|
|
exec.Command(pm[0], pm[1:]...).Run()
|
|
if path, err := exec.LookPath("nginx"); err == nil {
|
|
exec.Command("cp", path, dst).Run()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func cloudFromHost(host string) string {
|
|
if strings.Contains(host, "us1") {
|
|
return "US"
|
|
}
|
|
return "EU"
|
|
}
|
|
|
|
func CreateNodesDir() error { return os.MkdirAll(BaseDir, 0755) }
|
|
func GenerateSystemdTemplate() error { return nil }
|
|
func RemoveNode(name string) error { return nil }
|
|
func Status(name string) (string, error) { return "", nil }
|
|
|
|
func startNginx(dir string, node state.Node, port string) {
|
|
nginxDir := filepath.Join(dir, "nginx")
|
|
confDir := filepath.Join(nginxDir, "conf")
|
|
os.MkdirAll(confDir, 0755)
|
|
confPath := filepath.Join(confDir, "nginx.conf")
|
|
os.WriteFile(confPath, []byte(fmt.Sprintf(`
|
|
worker_processes auto;
|
|
pid %s/nginx.pid;
|
|
error_log %s/error.log;
|
|
events { worker_connections 10240; }
|
|
http {
|
|
access_log %s/access.log;
|
|
server {
|
|
listen %s;
|
|
server_name _;
|
|
location /health { return 200; }
|
|
}
|
|
}
|
|
`, nginxDir, nginxDir, nginxDir, port)), 0644)
|
|
|
|
bin := filepath.Join(nginxDir, "sbin", "nginx")
|
|
cmd := exec.Command(bin, "-c", confPath, "-p", nginxDir)
|
|
cmd.Dir = nginxDir
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
fmt.Printf("[%s] NGINX start: %v\n%s\n", node.Name, err, string(out))
|
|
} else {
|
|
fmt.Printf("[%s] NGINX started on port %s\n", node.Name, port)
|
|
}
|
|
}
|
|
|
|
func killPort(port string) {
|
|
// Find and kill any process listening on the target port
|
|
out, _ := exec.Command("fuser", "-k", port+"/tcp").CombinedOutput()
|
|
if len(out) > 0 {
|
|
fmt.Printf(" Killed existing process on port %s\n", port)
|
|
}
|
|
}
|