Files
NexaFabric/backend/app/seed/demo.py
T
nessi 4554b00b73
CI / backend (push) Failing after 2s
CI / frontend (push) Failing after 31s
feat: improve setup wizard UX, add cluster sync error handling, and conditional demo data seeding
Add SEED_DEMO_DATA environment variable to control demo data population, enhance setup wizard with welcome screen and theme toggle, add smooth animations for wizard transitions, improve dashboard endpoint to return structured objects for last_syncs and faulty_nodes instead of raw models, implement comprehensive error handling in cluster sync with failed status tracking and audit logging, fix Proxmox provider
2026-07-09 12:57:07 +02:00

199 lines
7.2 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:
settings = get_settings()
if not db.get(SystemSetting, "setup"):
db.add(SystemSetting(key="setup", value={"complete": False}))
roles = {
"Super Admin": ["*"],
"Network Admin": ["networks:*", "ipam:*", "clusters:read"],
"Security Admin": ["policies:*", "firewall:*", "security-groups:*"],
"Tenant Admin": ["tenants:read", "projects:*"],
"Auditor": ["audit:read", "clusters:read", "policies:read"],
"Read Only User": ["*:read"],
}
for name, permissions in roles.items():
if not db.scalar(select(Role).where(Role.name == name)):
db.add(Role(name=name, permissions=permissions))
for name, proto, ports in SERVICES:
if not db.scalar(select(ServiceCatalogItem).where(ServiceCatalogItem.name == name)):
db.add(ServiceCatalogItem(name=name, protocol=proto, ports=ports, editable=True))
db.commit()
if not settings.seed_demo_data:
return
if db.scalar(select(User).where(User.email == "admin@nexafabric.local")):
return
super_admin = db.scalar(select(Role).where(Role.name == "Super Admin"))
user = User(
email="admin@nexafabric.local",
display_name="NexaFabric Administrator",
password_hash=hash_password(settings.demo_admin_password),
roles=[super_admin],
)
db.add(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(AuditLog(user_id=user.id, action="seed.created", object_type="system", result="success"))
db.commit()