166 lines
4.5 KiB
Go
166 lines
4.5 KiB
Go
package native
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"git.sechpoint.app/customer-engineering/wallarm/internal/state"
|
|
)
|
|
|
|
const (
|
|
BaseDir = "/opt/fw"
|
|
Symlink = "/opt/wallarm"
|
|
)
|
|
|
|
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. Per-instance NGINX: copy binary, write config, start
|
|
nginxDir := filepath.Join(instanceDir, "nginx")
|
|
copyNginx(instanceDir)
|
|
|
|
// Write nginx.conf for this instance
|
|
port := "80"
|
|
if idx := strings.LastIndex(node.Address, ":"); idx != -1 {
|
|
port = node.Address[idx+1:]
|
|
}
|
|
nginxConf := filepath.Join(nginxDir, "conf", "nginx.conf")
|
|
os.MkdirAll(filepath.Dir(nginxConf), 0755)
|
|
os.WriteFile(nginxConf, []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 _;
|
|
allow 127.0.0.0/8;
|
|
deny all;
|
|
wallarm_mode off;
|
|
access_log off;
|
|
location /wallarm-status { wallarm_status on; }
|
|
}
|
|
}
|
|
`, nginxDir, nginxDir, nginxDir, port)), 0644)
|
|
|
|
// Start NGINX for this instance
|
|
exec.Command(filepath.Join(nginxDir, "sbin", "nginx"),
|
|
"-c", nginxConf, "-p", nginxDir).Run()
|
|
fmt.Printf("[%s] NGINX started on port %s\n", node.Name, port)
|
|
|
|
// 2. 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)
|
|
}
|
|
|
|
// 3. Create instance dir + symlink
|
|
os.MkdirAll(instanceDir, 0755)
|
|
os.Remove(Symlink)
|
|
if err := os.Symlink(instanceDir, Symlink); err != nil {
|
|
os.RemoveAll(Symlink)
|
|
os.Symlink(instanceDir, Symlink)
|
|
}
|
|
|
|
// 4. Extract AIO to instance
|
|
fmt.Printf("[%s] Extracting...\n", node.Name)
|
|
cmd := exec.Command("bash", installerPath, "--noexec", "--keep", "--target", instanceDir, "--noprogress", "--accept")
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("extract: %w\n%s", err, string(out))
|
|
}
|
|
|
|
// 5. Run setup.sh
|
|
fmt.Printf("[%s] Running setup...\n", node.Name)
|
|
cmd = exec.Command("bash", filepath.Join(instanceDir, "setup.sh"),
|
|
"--batch", "--token", apiToken, "--cloud", cloudFromHost(apiHost),
|
|
"--custom-ngx-build",
|
|
)
|
|
cmd.Dir = instanceDir
|
|
|
|
logFile, _ := os.Create(filepath.Join(instanceDir, "install.log"))
|
|
if logFile != nil {
|
|
cmd.Stdout = logFile
|
|
cmd.Stderr = logFile
|
|
}
|
|
runErr := cmd.Run()
|
|
if logFile != nil {
|
|
logFile.Close()
|
|
}
|
|
if runErr != nil {
|
|
if data, _ := os.ReadFile(filepath.Join(instanceDir, "install.log")); len(data) > 0 {
|
|
lines := strings.Split(string(data), "\n")
|
|
s := len(lines) - 5
|
|
if s < 0 {
|
|
s = 0
|
|
}
|
|
return fmt.Errorf("%s", strings.Join(lines[s:], "\n"))
|
|
}
|
|
return fmt.Errorf("setup failed: %v", runErr)
|
|
}
|
|
|
|
fmt.Printf("[%s] Done.\n", node.Name)
|
|
return nil
|
|
}
|
|
|
|
func copyNginx(instanceDir string) {
|
|
dst := filepath.Join(instanceDir, "nginx", "sbin", "nginx")
|
|
if _, err := os.Stat(dst); err == nil {
|
|
return
|
|
}
|
|
fmt.Println("Installing NGINX per instance...")
|
|
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 {
|
|
exec.Command("systemctl", "stop", "wallarm-node@"+name).Run()
|
|
exec.Command("systemctl", "disable", "wallarm-node@"+name).Run()
|
|
return nil
|
|
}
|
|
func Status(name string) (string, error) { return "", nil }
|