Refactor backend: Split models and proxmox_client into modules, add alembic
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 2m27s
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 2m27s
This commit is contained in:
220
backend/app/models/proxmox.py
Normal file
220
backend/app/models/proxmox.py
Normal file
@@ -0,0 +1,220 @@
|
||||
from .base import *
|
||||
|
||||
class OSTemplateGroup(Base):
|
||||
"""Group of OS templates"""
|
||||
__tablename__ = "os_template_groups"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(100), nullable=False, index=True)
|
||||
icon = Column(String(200), nullable=True)
|
||||
description = Column(Text, nullable=True)
|
||||
sort_order = Column(Integer, nullable=False, default=0)
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<OSTemplateGroup(id={self.id}, name='{self.name}')>"
|
||||
|
||||
class OSTemplate(Base):
|
||||
"""OS Template"""
|
||||
__tablename__ = "os_templates"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
group_id = Column(Integer, nullable=False, index=True)
|
||||
server_id = Column(Integer, nullable=False, index=True)
|
||||
|
||||
name = Column(String(100), nullable=False)
|
||||
vmid = Column(Integer, nullable=True)
|
||||
vm_type = Column(String(10), nullable=False, default="qemu", server_default="qemu")
|
||||
volid = Column(String(500), nullable=True)
|
||||
node = Column(String(100), nullable=True)
|
||||
|
||||
source_node = Column(String(100), nullable=True)
|
||||
replicated_nodes = Column(JSON, nullable=True, default={})
|
||||
|
||||
default_cores = Column(Integer, nullable=False, default=1)
|
||||
default_memory = Column(Integer, nullable=False, default=1024)
|
||||
default_disk = Column(Integer, nullable=False, default=10)
|
||||
min_cores = Column(Integer, nullable=False, default=1)
|
||||
min_memory = Column(Integer, nullable=False, default=512)
|
||||
min_disk = Column(Integer, nullable=False, default=5)
|
||||
|
||||
description = Column(Text, nullable=True)
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
sort_order = Column(Integer, nullable=False, default=0)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_os_template_group', 'group_id'),
|
||||
Index('idx_os_template_server', 'server_id'),
|
||||
Index('idx_os_template_vmid', 'server_id', 'vmid'),
|
||||
)
|
||||
|
||||
def get_source_node(self) -> str:
|
||||
return self.source_node or self.node
|
||||
|
||||
def get_vmid_for_node(self, node_name: str) -> Optional[int]:
|
||||
source = self.get_source_node()
|
||||
if node_name == source:
|
||||
return self.vmid
|
||||
if self.replicated_nodes and node_name in self.replicated_nodes:
|
||||
return self.replicated_nodes[node_name]
|
||||
return None
|
||||
|
||||
def add_replicated_node(self, node_name: str, vmid: int):
|
||||
if not self.replicated_nodes:
|
||||
self.replicated_nodes = {}
|
||||
self.replicated_nodes[node_name] = vmid
|
||||
|
||||
def __repr__(self):
|
||||
return f"<OSTemplate(id={self.id}, name='{self.name}', vmid={self.vmid})>"
|
||||
|
||||
class ProxmoxServer(Base):
|
||||
"""Proxmox VE server"""
|
||||
__tablename__ = "proxmox_servers"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(100), nullable=False, index=True)
|
||||
hostname = Column(String(255), nullable=False, index=True)
|
||||
ip_address = Column(String(50), nullable=False, index=True)
|
||||
port = Column(Integer, nullable=False, default=8006)
|
||||
|
||||
api_user = Column(String(100), nullable=False, default="root@pam")
|
||||
api_token_name = Column(String(100), nullable=True)
|
||||
api_token_value = Column(String(255), nullable=True)
|
||||
|
||||
use_password = Column(Boolean, nullable=False, default=False)
|
||||
password = Column(EncryptedString(255), nullable=True)
|
||||
|
||||
verify_ssl = Column(Boolean, nullable=False, default=True)
|
||||
cluster_name = Column(String(100), nullable=True, index=True)
|
||||
|
||||
description = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
last_check = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
is_online = Column(Boolean, nullable=True, default=None)
|
||||
last_error = Column(Text, nullable=True)
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_proxmox_status', 'is_online', 'last_check'),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ProxmoxServer(id={self.id}, name='{self.name}', ip='{self.ip_address}')>"
|
||||
|
||||
@property
|
||||
def connection_info(self) -> dict:
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'hostname': self.hostname,
|
||||
'ip_address': self.ip_address,
|
||||
'port': self.port,
|
||||
'api_user': self.api_user,
|
||||
'verify_ssl': self.verify_ssl,
|
||||
'is_online': self.is_online,
|
||||
'last_check': self.last_check
|
||||
}
|
||||
|
||||
def update_status(self, is_online: bool, error: str = None):
|
||||
self.is_online = is_online
|
||||
self.last_check = utcnow()
|
||||
if error:
|
||||
self.last_error = error
|
||||
elif is_online:
|
||||
self.last_error = None
|
||||
|
||||
assigned_users = relationship("User", secondary="user_servers", back_populates="assigned_servers", lazy="select")
|
||||
|
||||
class VMInstance(Base):
|
||||
"""VM/Container instance cache"""
|
||||
__tablename__ = "vm_instances"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
server_id = Column(Integer, nullable=False, index=True)
|
||||
vmid = Column(Integer, nullable=False, index=True)
|
||||
node = Column(String(100), nullable=False)
|
||||
vm_type = Column(String(20), nullable=False)
|
||||
name = Column(String(100), nullable=False)
|
||||
|
||||
owner_id = Column(Integer, ForeignKey('users.id'), nullable=True, index=True)
|
||||
owner = relationship("User", backref="instances", foreign_keys=[owner_id])
|
||||
|
||||
status = Column(String(20), default='unknown')
|
||||
is_template = Column(Boolean, default=False)
|
||||
|
||||
cores = Column(Integer, nullable=True)
|
||||
memory = Column(BigInteger, nullable=True)
|
||||
disk_size = Column(BigInteger, nullable=True)
|
||||
|
||||
os_type = Column(String(50), nullable=True)
|
||||
|
||||
ip_address = Column(String(50), nullable=True)
|
||||
ip_prefix = Column(Integer, nullable=True, default=24)
|
||||
gateway = Column(String(50), nullable=True)
|
||||
nameserver = Column(String(50), nullable=True)
|
||||
|
||||
cloud_init_user = Column(String(100), nullable=True)
|
||||
cloud_init_password = Column(EncryptedString(255), nullable=True)
|
||||
ssh_keys = Column(Text, nullable=True)
|
||||
|
||||
template_id = Column(Integer, nullable=True)
|
||||
template_name = Column(String(100), nullable=True)
|
||||
|
||||
description = Column(Text, nullable=True)
|
||||
tags = Column(String(255), nullable=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
||||
last_sync_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
extra_config = Column(JSON, nullable=True)
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_vm_instance_server_vmid', 'server_id', 'vmid', unique=True),
|
||||
Index('idx_vm_instance_active', 'server_id', 'deleted_at'),
|
||||
Index('idx_vm_instance_owner', 'owner_id'),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<VMInstance(id={self.id}, server_id={self.server_id}, vmid={self.vmid}, name='{self.name}')>"
|
||||
|
||||
class VMSnapshotArchive(Base):
|
||||
"""Archive of VM/Container snapshots"""
|
||||
__tablename__ = "vm_snapshot_archives"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
server_id = Column(Integer, nullable=False, index=True)
|
||||
server_name = Column(String(100), nullable=True)
|
||||
vmid = Column(Integer, nullable=False, index=True)
|
||||
vm_name = Column(String(100), nullable=True)
|
||||
vm_type = Column(String(20), nullable=False)
|
||||
node = Column(String(100), nullable=False)
|
||||
|
||||
snapname = Column(String(100), nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
snaptime = Column(BigInteger, nullable=True)
|
||||
parent = Column(String(100), nullable=True)
|
||||
|
||||
vmstate = Column(Boolean, default=False, nullable=False)
|
||||
|
||||
snapshot_config = Column(JSON, nullable=True)
|
||||
|
||||
deleted_by = Column(String(100), nullable=True)
|
||||
deletion_reason = Column(Text, nullable=True)
|
||||
archived_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_snapshot_archive_server_vmid', 'server_id', 'vmid'),
|
||||
Index('idx_snapshot_archive_archived', 'archived_at'),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<VMSnapshotArchive(id={self.id}, vmid={self.vmid}, snapname='{self.snapname}')>"
|
||||
Reference in New Issue
Block a user