140 lines
5.2 KiB
Python
140 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Wallarm Docker Node Manager"""
|
|
|
|
import json, os, sys, time, subprocess, shutil
|
|
|
|
VERSION = "2.0.0"
|
|
BASE = "/opt/fw"
|
|
APP = f"{BASE}/app"
|
|
CONF = f"{APP}/fw.conf"
|
|
STATE = f"{APP}/state.json"
|
|
WALLARM_IMAGE = "wallarm/node:6.13.0"
|
|
DOCKER_BIN_URL = "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/docker/binaries/docker-29.2.1.tgz"
|
|
|
|
def run(cmd, timeout=120):
|
|
return subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
|
|
|
|
def load_config():
|
|
if not os.path.exists(CONF): return {}
|
|
with open(CONF) as f: return json.load(f)
|
|
|
|
def load_state():
|
|
if not os.path.exists(STATE): return {"nodes": []}
|
|
with open(STATE) as f: return json.load(f)
|
|
|
|
def save_state(s):
|
|
os.makedirs(APP, exist_ok=True)
|
|
with open(STATE, "w") as f: json.dump(s, f, indent=2)
|
|
|
|
# ─── Docker ────────────────────────────────────────────────────────────
|
|
|
|
def install_docker():
|
|
if shutil.which("docker"):
|
|
return
|
|
print("Installing Docker...")
|
|
run("apt-get update -qq && apt-get install -y -qq docker.io 2>/dev/null || yum install -y -q docker 2>/dev/null", timeout=120)
|
|
run("systemctl enable docker && systemctl start docker")
|
|
|
|
def deploy_container(name, token, cloud, port, upstream_ip, upstream_port, labels, mode):
|
|
api_host = "us1.api.wallarm.com" if cloud == "US" else "api.wallarm.com"
|
|
|
|
# Ensure Docker is running
|
|
install_docker()
|
|
|
|
# Pull image if needed
|
|
if run(f"docker images -q {WALLARM_IMAGE}").stdout.strip() == "":
|
|
print(f"[{name}] Pulling Wallarm image...")
|
|
run(f"docker pull {WALLARM_IMAGE}", timeout=300)
|
|
|
|
# Remove old container if exists
|
|
container = f"wallarm-{name}"
|
|
run(f"docker rm -f {container} 2>/dev/null", timeout=10)
|
|
|
|
# Run container
|
|
monitoring_port = int(port) + 10
|
|
print(f"[{name}] Starting container on port {port}...")
|
|
cmd = f"""docker run -d \
|
|
--name {container} \
|
|
--restart unless-stopped \
|
|
-p {port}:{port} \
|
|
-p {monitoring_port}:{monitoring_port} \
|
|
-e WALLARM_API_TOKEN={token} \
|
|
-e WALLARM_API_HOST={api_host} \
|
|
-e WALLARM_MODE={mode} \
|
|
-e NGINX_PORT={port}"""
|
|
if upstream_ip:
|
|
cmd += f" -e WALLARM_UPSTREAM=http://{upstream_ip}:{upstream_port}"
|
|
cmd += f" {WALLARM_IMAGE}"
|
|
|
|
r = run(cmd, timeout=30)
|
|
if r.returncode != 0:
|
|
print(f"❌ {name}: {r.stderr}")
|
|
return False
|
|
|
|
# Save state
|
|
s = load_state()
|
|
s.setdefault("nodes", []).append({
|
|
"name": name, "type": "docker", "port": int(port),
|
|
"upstream_ip": upstream_ip, "upstream_port": int(upstream_port),
|
|
"status": "running", "created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
})
|
|
save_state(s)
|
|
print(f"✅ {name} running on port {port} (docker ps --filter name={container})")
|
|
return True
|
|
|
|
def remove_container(name):
|
|
container = f"wallarm-{name}"
|
|
run(f"docker rm -f {container} 2>/dev/null", timeout=10)
|
|
shutil.rmtree(f"/opt/wallarm-{name}", ignore_errors=True)
|
|
s = load_state()
|
|
s["nodes"] = [n for n in s.get("nodes", []) if n["name"] != name]
|
|
save_state(s)
|
|
print(f"✅ {name} removed")
|
|
|
|
def container_status():
|
|
r = run("docker ps --filter 'name=wallarm-' --format '{{.Names}}\t{{.Status}}\t{{.Ports}}'")
|
|
if not r.stdout.strip():
|
|
print("No containers running.")
|
|
return
|
|
print("\n─── Containers ───")
|
|
for line in r.stdout.strip().split("\n"):
|
|
print(f" {line}")
|
|
|
|
# ─── Deploy All ───────────────────────────────────────────────────────
|
|
|
|
def deploy_all():
|
|
cfg = load_config()
|
|
nodes = cfg.get("nodes", cfg) # support both {"nodes":{...}} and flat format
|
|
if not nodes:
|
|
print("No nodes in fw.conf")
|
|
return
|
|
for name, nc in nodes.items():
|
|
if not isinstance(nc, dict): continue
|
|
deploy_container(name, nc["token"], nc.get("cloud","EU"),
|
|
str(nc.get("port","8081")), nc.get("upstream_ip","127.0.0.1"),
|
|
str(nc.get("upstream_port","80")), nc.get("labels",""),
|
|
nc.get("mode","monitoring"))
|
|
|
|
# ─── Menu ─────────────────────────────────────────────────────────────
|
|
|
|
def main():
|
|
if len(sys.argv) > 1 and sys.argv[1] == "--deploy-all":
|
|
return deploy_all()
|
|
|
|
print(f"═══ Wallarm Docker Manager v{VERSION} ═══\n")
|
|
while True:
|
|
print("\n─── Menu ───")
|
|
print(" [1] Deploy all [2] Status [3] Remove [q] Quit")
|
|
c = input("\nChoice: ").strip()
|
|
if c == "1": deploy_all()
|
|
elif c == "2": container_status()
|
|
elif c == "3":
|
|
print("\nContainers:")
|
|
for n in load_state().get("nodes", []):
|
|
print(f" [{n['name']}]")
|
|
name = input("Name to remove: ").strip()
|
|
if name: remove_container(name)
|
|
elif c.lower() == "q": break
|
|
|
|
if __name__ == "__main__":
|
|
main()
|