Add setup wizard with status tracking via SystemSetting model, implement /setup/status and /setup/complete endpoints to create initial admin user and optional cluster configuration, add workload insights endpoint with traffic analysis and policy matching including audit mode detection, implement enforcement_mode property on Policy model with audit/enforced states, add Modal component for dialogs, create SetupWizard page with multi
187 lines
7.0 KiB
Python
187 lines
7.0 KiB
Python
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.config import get_settings
|
|
from app.core.security import hash_password
|
|
from app.models.domain import (
|
|
AuditLog,
|
|
Cluster,
|
|
IpAddress,
|
|
Network,
|
|
Node,
|
|
Policy,
|
|
Project,
|
|
Role,
|
|
SecurityGroup,
|
|
ServiceCatalogItem,
|
|
SystemSetting,
|
|
Subnet,
|
|
Tenant,
|
|
User,
|
|
Workload,
|
|
)
|
|
|
|
|
|
SERVICES = [
|
|
("SSH", "tcp", "22"),
|
|
("HTTP", "tcp", "80"),
|
|
("HTTPS", "tcp", "443"),
|
|
("DNS", "tcp/udp", "53"),
|
|
("LDAP", "tcp", "389"),
|
|
("LDAPS", "tcp", "636"),
|
|
("RDP", "tcp", "3389"),
|
|
("PostgreSQL", "tcp", "5432"),
|
|
("MySQL/MariaDB", "tcp", "3306"),
|
|
("MSSQL", "tcp", "1433"),
|
|
("Redis", "tcp", "6379"),
|
|
("SMB", "tcp", "445"),
|
|
("SMTP", "tcp", "25"),
|
|
("SMTPS", "tcp", "465"),
|
|
("IMAPS", "tcp", "993"),
|
|
("POP3S", "tcp", "995"),
|
|
("Proxmox API", "tcp", "8006"),
|
|
("Proxmox SPICE", "tcp", "3128"),
|
|
]
|
|
|
|
|
|
def seed_demo_data(db: Session) -> None:
|
|
if not db.get(SystemSetting, "setup"):
|
|
db.add(SystemSetting(key="setup", value={"complete": False}))
|
|
db.commit()
|
|
|
|
if db.scalar(select(User).where(User.email == "admin@nexafabric.local")):
|
|
return
|
|
|
|
super_admin = Role(name="Super Admin", permissions=["*"])
|
|
roles = [
|
|
super_admin,
|
|
Role(name="Network Admin", permissions=["networks:*", "ipam:*", "clusters:read"]),
|
|
Role(name="Security Admin", permissions=["policies:*", "firewall:*", "security-groups:*"]),
|
|
Role(name="Tenant Admin", permissions=["tenants:read", "projects:*"]),
|
|
Role(name="Auditor", permissions=["audit:read", "clusters:read", "policies:read"]),
|
|
Role(name="Read Only User", permissions=["*:read"]),
|
|
]
|
|
user = User(
|
|
email="admin@nexafabric.local",
|
|
display_name="NexaFabric Administrator",
|
|
password_hash=hash_password(get_settings().demo_admin_password),
|
|
roles=[super_admin],
|
|
)
|
|
db.add_all(roles + [user])
|
|
|
|
tenants = [
|
|
Tenant(name="Platform", description="Shared infrastructure and platform services"),
|
|
Tenant(name="Finance", description="Finance applications"),
|
|
Tenant(name="Research", description="Lab and engineering workloads"),
|
|
]
|
|
db.add_all(tenants)
|
|
db.flush()
|
|
|
|
projects = [
|
|
Project(tenant_id=tenants[0].id, name="Core Services", description="DNS, auth, monitoring"),
|
|
Project(tenant_id=tenants[1].id, name="ERP", description="Finance ERP workloads"),
|
|
Project(tenant_id=tenants[2].id, name="Lab", description="Research lab systems"),
|
|
]
|
|
db.add_all(projects)
|
|
db.flush()
|
|
|
|
cluster = Cluster(
|
|
name="Demo Proxmox Cluster",
|
|
api_url="https://pve-demo.local:8006",
|
|
token_ref="demo-token-reference",
|
|
last_sync_status="success",
|
|
)
|
|
db.add(cluster)
|
|
db.flush()
|
|
|
|
nodes = [
|
|
Node(cluster_id=cluster.id, name="pve-01", status="online", cpu_count=32, memory_mb=131072),
|
|
Node(cluster_id=cluster.id, name="pve-02", status="online", cpu_count=32, memory_mb=131072),
|
|
Node(cluster_id=cluster.id, name="pve-03", status="warning", cpu_count=24, memory_mb=98304),
|
|
]
|
|
db.add_all(nodes)
|
|
db.flush()
|
|
|
|
networks = [
|
|
Network(cluster_id=cluster.id, project_id=projects[0].id, name="mgmt", kind="bridge", vlan_id=10, gateway="10.10.10.1", dns=["10.10.10.10"], tags=["management"], description="Management bridge"),
|
|
Network(cluster_id=cluster.id, project_id=projects[0].id, name="services", kind="vlan", vlan_id=20, gateway="10.20.0.1", dns=["10.20.0.10"], tags=["shared"], description="Shared services"),
|
|
Network(cluster_id=cluster.id, project_id=projects[1].id, name="finance-app", kind="vxlan", vlan_id=120, gateway="10.120.0.1", dns=["10.20.0.10"], tags=["finance"], description="Finance application tier"),
|
|
Network(cluster_id=cluster.id, project_id=projects[2].id, name="research-lab", kind="vnet", vlan_id=220, gateway="10.220.0.1", dns=["10.20.0.10"], tags=["lab"], description="Research tenant network"),
|
|
]
|
|
db.add_all(networks)
|
|
db.flush()
|
|
|
|
subnets = [
|
|
Subnet(network_id=networks[0].id, cidr="10.10.10.0/24", gateway="10.10.10.1", dns=["10.10.10.10"]),
|
|
Subnet(network_id=networks[1].id, cidr="10.20.0.0/24", gateway="10.20.0.1", dns=["10.20.0.10"]),
|
|
Subnet(network_id=networks[2].id, cidr="10.120.0.0/24", gateway="10.120.0.1", dns=["10.20.0.10"]),
|
|
]
|
|
db.add_all(subnets)
|
|
db.flush()
|
|
|
|
workloads = []
|
|
for idx in range(10):
|
|
project = projects[idx % len(projects)]
|
|
workloads.append(
|
|
Workload(
|
|
cluster_id=cluster.id,
|
|
node_id=nodes[idx % len(nodes)].id,
|
|
project_id=project.id,
|
|
external_id=str(100 + idx),
|
|
name=f"{project.name.lower().replace(' ', '-')}-{idx + 1}",
|
|
kind="qemu" if idx % 3 else "lxc",
|
|
status="running" if idx != 7 else "stopped",
|
|
tags=["web"] if idx % 2 else ["db"],
|
|
)
|
|
)
|
|
db.add_all(workloads)
|
|
db.flush()
|
|
|
|
db.add_all(
|
|
[
|
|
IpAddress(subnet_id=subnets[0].id, address="10.10.10.20", status="assigned", workload_id=workloads[0].id),
|
|
IpAddress(subnet_id=subnets[1].id, address="10.20.0.50", status="reserved", note="Load balancer VIP"),
|
|
IpAddress(subnet_id=subnets[2].id, address="10.120.0.99", status="conflict", note="Duplicate detected during import"),
|
|
]
|
|
)
|
|
|
|
groups = [
|
|
SecurityGroup(project_id=projects[0].id, name="Management", description="Administrative access"),
|
|
SecurityGroup(project_id=projects[1].id, name="Finance Web", description="Finance web tier"),
|
|
SecurityGroup(project_id=projects[1].id, name="Finance DB", description="Finance database tier"),
|
|
]
|
|
db.add_all(groups)
|
|
|
|
db.add_all(
|
|
[
|
|
Policy(
|
|
project_id=projects[1].id,
|
|
name="Finance web to database",
|
|
definition={
|
|
"source": "sg:Finance Web",
|
|
"destination": "sg:Finance DB",
|
|
"service": {"protocol": "tcp", "ports": "5432"},
|
|
"action": "allow",
|
|
"direction": "egress",
|
|
"logging": True,
|
|
"description": "Allow PostgreSQL from finance web tier to database tier.",
|
|
},
|
|
),
|
|
Policy(
|
|
project_id=projects[0].id,
|
|
name="Management SSH",
|
|
definition={
|
|
"source": "network:mgmt",
|
|
"destination": "any",
|
|
"service": {"protocol": "tcp", "ports": "22"},
|
|
"action": "allow",
|
|
"direction": "ingress",
|
|
},
|
|
),
|
|
]
|
|
)
|
|
|
|
db.add_all([ServiceCatalogItem(name=name, protocol=proto, ports=ports, editable=True) for name, proto, ports in SERVICES])
|
|
db.add(AuditLog(user_id=user.id, action="seed.created", object_type="system", result="success"))
|
|
db.commit()
|