Add RuntimeSettingsRead/RuntimeSettingsUpdate schemas with auto_node_sync_enabled/auto_node_sync_interval_minutes/auto_ipam_sync_enabled/auto_ipam_sync_interval_minutes/last_node_auto_sync_at/last_ipam_auto_sync_at fields, implement firewall_log_lines_from_files to parse /var/log/pve-firewall.log with max_lines limit and error collection, extend collect_firewall_log
386 lines
8.0 KiB
Python
386 lines
8.0 KiB
Python
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
|
|
class OrmModel(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class TokenPair(BaseModel):
|
|
access_token: str
|
|
refresh_token: str
|
|
token_type: str = "bearer"
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
email: str
|
|
password: str
|
|
|
|
|
|
class SetupStatus(BaseModel):
|
|
complete: bool
|
|
has_users: bool
|
|
has_clusters: bool
|
|
|
|
|
|
class SetupCompleteRequest(BaseModel):
|
|
admin_email: str
|
|
admin_name: str
|
|
admin_password: str = Field(min_length=12)
|
|
cluster_name: str | None = None
|
|
cluster_api_url: str | None = None
|
|
cluster_api_token: str | None = None
|
|
cluster_provider: str = "proxmox"
|
|
cluster_mode: str = "read_only"
|
|
verify_tls: bool = True
|
|
|
|
|
|
class UserRead(OrmModel):
|
|
id: str
|
|
email: str
|
|
display_name: str
|
|
is_active: bool
|
|
|
|
|
|
class UserCreate(BaseModel):
|
|
email: str
|
|
display_name: str
|
|
password: str = Field(min_length=12)
|
|
role_ids: list[str] = []
|
|
|
|
|
|
class RoleCreate(BaseModel):
|
|
name: str
|
|
permissions: list[str] = []
|
|
|
|
|
|
class RoleRead(OrmModel):
|
|
id: str
|
|
name: str
|
|
permissions: list[str]
|
|
|
|
|
|
class ClusterCreate(BaseModel):
|
|
name: str
|
|
api_url: str
|
|
api_token: str = Field(min_length=8)
|
|
provider: str = "proxmox"
|
|
mode: str = "read_only"
|
|
verify_tls: bool = True
|
|
|
|
|
|
class ClusterUpdate(BaseModel):
|
|
name: str
|
|
api_url: str
|
|
api_token: str | None = Field(default=None, min_length=8)
|
|
provider: str = "proxmox"
|
|
mode: str = "read_only"
|
|
verify_tls: bool = True
|
|
|
|
|
|
class TenantCreate(BaseModel):
|
|
name: str
|
|
description: str | None = None
|
|
|
|
|
|
class ProjectCreate(BaseModel):
|
|
tenant_id: str
|
|
name: str
|
|
description: str | None = None
|
|
|
|
|
|
class NetworkCreate(BaseModel):
|
|
cluster_id: str
|
|
project_id: str | None = None
|
|
name: str
|
|
kind: str = "bridge"
|
|
vlan_id: int | None = None
|
|
mtu: int = 1500
|
|
gateway: str | None = None
|
|
dns: list[str] = []
|
|
dhcp_enabled: bool = False
|
|
tags: list[str] = []
|
|
description: str | None = None
|
|
|
|
|
|
class SubnetCreate(BaseModel):
|
|
network_id: str
|
|
cidr: str
|
|
gateway: str | None = None
|
|
dns: list[str] = []
|
|
dhcp_enabled: bool = False
|
|
|
|
|
|
class SubnetUpdate(BaseModel):
|
|
network_id: str | None = None
|
|
cidr: str | None = None
|
|
gateway: str | None = None
|
|
dns: list[str] | None = None
|
|
dhcp_enabled: bool | None = None
|
|
|
|
|
|
class SecurityGroupCreate(BaseModel):
|
|
project_id: str | None = None
|
|
name: str
|
|
description: str | None = None
|
|
|
|
|
|
class SecurityRuleCreate(BaseModel):
|
|
security_group_id: str
|
|
direction: str = "ingress"
|
|
action: str = "allow"
|
|
protocol: str = "tcp"
|
|
source: str = "any"
|
|
destination: str = "any"
|
|
port: str | None = None
|
|
priority: int = 1000
|
|
logging: bool = False
|
|
description: str | None = None
|
|
|
|
|
|
class PolicyCreate(BaseModel):
|
|
project_id: str | None = None
|
|
name: str
|
|
enabled: bool = True
|
|
definition: dict[str, Any]
|
|
|
|
|
|
class IpReservationCreate(BaseModel):
|
|
subnet_id: str
|
|
address: str
|
|
status: str = "reserved"
|
|
note: str | None = None
|
|
|
|
|
|
class ServiceCatalogCreate(BaseModel):
|
|
name: str
|
|
protocol: str
|
|
ports: str
|
|
editable: bool = True
|
|
|
|
|
|
class FirewallApplyRequest(BaseModel):
|
|
policy_id: str
|
|
cluster_id: str | None = None
|
|
confirm: bool = False
|
|
dry_run: bool = True
|
|
|
|
|
|
class RuntimeSettingsRead(BaseModel):
|
|
product: str = "NexaFabric"
|
|
firewall_apply_requires_preview: bool = True
|
|
agent_optional: bool = True
|
|
flow_retention_hours: int = 24
|
|
auto_node_sync_enabled: bool = False
|
|
auto_node_sync_interval_minutes: int = 60
|
|
auto_ipam_sync_enabled: bool = False
|
|
auto_ipam_sync_interval_minutes: int = 60
|
|
last_node_auto_sync_at: datetime | None = None
|
|
last_ipam_auto_sync_at: datetime | None = None
|
|
|
|
|
|
class RuntimeSettingsUpdate(BaseModel):
|
|
flow_retention_hours: int | None = Field(default=None, ge=1, le=8760)
|
|
auto_node_sync_enabled: bool | None = None
|
|
auto_node_sync_interval_minutes: int | None = Field(default=None, ge=1, le=10080)
|
|
auto_ipam_sync_enabled: bool | None = None
|
|
auto_ipam_sync_interval_minutes: int | None = Field(default=None, ge=1, le=10080)
|
|
|
|
|
|
class ClusterRead(OrmModel):
|
|
id: str
|
|
name: str
|
|
api_url: str
|
|
provider: str
|
|
mode: str
|
|
verify_tls: bool
|
|
last_sync_at: datetime | None
|
|
last_sync_status: str | None
|
|
last_sync_error: str | None
|
|
|
|
|
|
class NodeRead(OrmModel):
|
|
id: str
|
|
cluster_id: str
|
|
name: str
|
|
status: str
|
|
cpu_count: int
|
|
memory_mb: int
|
|
|
|
|
|
class NodeAgentRead(BaseModel):
|
|
node_id: str
|
|
status: str
|
|
version: str | None = None
|
|
last_seen_at: datetime | None = None
|
|
install_count: int = 0
|
|
last_payload: dict[str, Any] | None = None
|
|
|
|
|
|
class NodeWithAgentRead(NodeRead):
|
|
agent: NodeAgentRead | None = None
|
|
|
|
|
|
class AgentHeartbeat(BaseModel):
|
|
version: str
|
|
node_name: str | None = None
|
|
collected_at: datetime | None = None
|
|
hostname: str | None = None
|
|
kernel: str | None = None
|
|
uptime_seconds: float | None = None
|
|
loadavg: list[float] = []
|
|
interfaces: list[dict[str, Any]] = []
|
|
interface_traffic: list[dict[str, Any]] = []
|
|
flows: list[dict[str, Any]] = []
|
|
conntrack: dict[str, Any] = {}
|
|
firewall: dict[str, Any] = {}
|
|
extra: dict[str, Any] = {}
|
|
|
|
|
|
class WorkloadRead(OrmModel):
|
|
id: str
|
|
cluster_id: str
|
|
node_id: str
|
|
project_id: str | None
|
|
external_id: str
|
|
name: str
|
|
kind: str
|
|
status: str
|
|
tags: list[str]
|
|
|
|
|
|
class NetworkRead(OrmModel):
|
|
id: str
|
|
cluster_id: str
|
|
project_id: str | None
|
|
name: str
|
|
kind: str
|
|
vlan_id: int | None
|
|
mtu: int
|
|
gateway: str | None
|
|
dns: list[str]
|
|
dhcp_enabled: bool
|
|
tags: list[str]
|
|
description: str | None
|
|
|
|
|
|
class SubnetRead(OrmModel):
|
|
id: str
|
|
network_id: str
|
|
cidr: str
|
|
gateway: str | None
|
|
dns: list[str]
|
|
dhcp_enabled: bool
|
|
|
|
|
|
class IpAddressRead(OrmModel):
|
|
id: str
|
|
subnet_id: str
|
|
subnet_cidr: str | None = None
|
|
address: str
|
|
status: str
|
|
workload_id: str | None
|
|
workload_name: str | None = None
|
|
workload_external_id: str | None = None
|
|
note: str | None
|
|
|
|
|
|
class TenantRead(OrmModel):
|
|
id: str
|
|
name: str
|
|
description: str | None
|
|
|
|
|
|
class ProjectRead(OrmModel):
|
|
id: str
|
|
tenant_id: str
|
|
name: str
|
|
description: str | None
|
|
|
|
|
|
class SecurityGroupRead(OrmModel):
|
|
id: str
|
|
project_id: str | None
|
|
name: str
|
|
description: str | None
|
|
|
|
|
|
class SecurityRuleRead(OrmModel):
|
|
id: str
|
|
security_group_id: str
|
|
direction: str
|
|
action: str
|
|
protocol: str
|
|
source: str
|
|
destination: str
|
|
port: str | None
|
|
priority: int
|
|
logging: bool
|
|
description: str | None
|
|
|
|
|
|
class PolicyRead(OrmModel):
|
|
id: str
|
|
project_id: str | None
|
|
name: str
|
|
version: int
|
|
enabled: bool
|
|
enforcement_mode: str
|
|
definition: dict[str, Any]
|
|
last_compiled: dict[str, Any] | None
|
|
deployment_status: dict[str, Any] | None = None
|
|
|
|
|
|
class WorkloadInsight(BaseModel):
|
|
workload: WorkloadRead
|
|
assigned_ips: list[IpAddressRead]
|
|
traffic: list[dict[str, Any]]
|
|
active_firewall_rules: list[dict[str, Any]] = []
|
|
matching_policies: list[PolicyRead]
|
|
effective_decision: str
|
|
audit_mode_notes: list[str]
|
|
|
|
|
|
class ServiceCatalogRead(OrmModel):
|
|
id: str
|
|
name: str
|
|
protocol: str
|
|
ports: str
|
|
editable: bool
|
|
|
|
|
|
class FirewallPreview(BaseModel):
|
|
policy_id: str
|
|
dry_run: bool = True
|
|
generated_rules: list[dict[str, Any]]
|
|
warnings: list[str]
|
|
conflicts: list[str]
|
|
|
|
|
|
class JobRead(OrmModel):
|
|
id: str
|
|
kind: str
|
|
status: str
|
|
progress: int
|
|
started_at: datetime | None
|
|
finished_at: datetime | None
|
|
logs: list[str]
|
|
error: str | None
|
|
|
|
|
|
class AuditLogRead(OrmModel):
|
|
id: str
|
|
created_at: datetime
|
|
user_id: str | None
|
|
action: str
|
|
object_type: str
|
|
object_id: str | None
|
|
old_values: dict[str, Any] | None
|
|
new_values: dict[str, Any] | None
|
|
ip_address: str | None
|
|
user_agent: str | None
|
|
result: str
|
|
error_text: str | None
|