mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-09 05:24:49 +09:00
Opt-in to_dict over __table__.columns: auto-isoformat datetimes, *_encrypted always dropped, __serialize_exclude__ for redacted columns, serialize_extra() for computed fields (named to dodge ServerMetrics' literal 'extra' column). 20 purely-mechanical to_dicts across 15 files convert; genuinely custom shapes keep their hand-written methods (plan 75 §F's ruling stands). Field selection stays api/_query.py's job. Gate: key-for-key parity against the pre-conversion key sets frozen from git HEAD (only the Timestamp pair may be additive). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
119 lines
4.1 KiB
Python
119 lines
4.1 KiB
Python
from datetime import datetime
|
|
from app import db
|
|
from app.models.mixins import SerializableMixin
|
|
from app.models.json_column_mixin import JsonColumnMixin
|
|
import json
|
|
|
|
|
|
class CloudProvider(db.Model):
|
|
"""Cloud provider configuration (DigitalOcean, Hetzner, Vultr, Linode)."""
|
|
__tablename__ = 'cloud_providers'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(64), nullable=False)
|
|
provider_type = db.Column(db.String(32), nullable=False) # digitalocean, hetzner, vultr, linode
|
|
api_key_encrypted = db.Column(db.Text)
|
|
is_active = db.Column(db.Boolean, default=True)
|
|
created_by = db.Column(db.Integer, db.ForeignKey('users.id'))
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
servers = db.relationship('CloudServer', backref='provider', lazy='dynamic')
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'id': self.id,
|
|
'name': self.name,
|
|
'provider_type': self.provider_type,
|
|
'is_active': self.is_active,
|
|
'server_count': self.servers.count(),
|
|
'created_at': self.created_at.isoformat() if self.created_at else None,
|
|
}
|
|
|
|
|
|
class CloudServer(JsonColumnMixin, db.Model):
|
|
"""A cloud server provisioned through ServerKit."""
|
|
__tablename__ = 'cloud_servers'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
provider_id = db.Column(db.Integer, db.ForeignKey('cloud_providers.id'), nullable=False)
|
|
external_id = db.Column(db.String(128)) # provider's server ID
|
|
name = db.Column(db.String(128), nullable=False)
|
|
hostname = db.Column(db.String(256))
|
|
|
|
# Specs
|
|
region = db.Column(db.String(64))
|
|
size = db.Column(db.String(64))
|
|
image = db.Column(db.String(128)) # OS image
|
|
ip_address = db.Column(db.String(45))
|
|
ipv6_address = db.Column(db.String(64))
|
|
|
|
# Status
|
|
STATUS_CREATING = 'creating'
|
|
STATUS_ACTIVE = 'active'
|
|
STATUS_OFF = 'off'
|
|
STATUS_DESTROYED = 'destroyed'
|
|
STATUS_ERROR = 'error'
|
|
status = db.Column(db.String(32), default=STATUS_CREATING)
|
|
|
|
# Cost
|
|
monthly_cost = db.Column(db.Float, default=0)
|
|
currency = db.Column(db.String(3), default='USD')
|
|
|
|
# Auto-install agent
|
|
agent_installed = db.Column(db.Boolean, default=False)
|
|
|
|
# SSH key
|
|
ssh_key_id = db.Column(db.String(128))
|
|
|
|
# Metadata
|
|
metadata_json = db.Column(db.Text)
|
|
|
|
created_by = db.Column(db.Integer, db.ForeignKey('users.id'))
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
destroyed_at = db.Column(db.DateTime)
|
|
|
|
snapshots = db.relationship('CloudSnapshot', backref='server', lazy='dynamic', cascade='all, delete-orphan')
|
|
|
|
@property
|
|
def server_metadata(self):
|
|
return self._json_read('metadata_json')
|
|
|
|
@server_metadata.setter
|
|
def server_metadata(self, v):
|
|
self.metadata_json = json.dumps(v)
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'id': self.id,
|
|
'provider_id': self.provider_id,
|
|
'provider_name': self.provider.name if self.provider else None,
|
|
'provider_type': self.provider.provider_type if self.provider else None,
|
|
'external_id': self.external_id,
|
|
'name': self.name,
|
|
'hostname': self.hostname,
|
|
'region': self.region,
|
|
'size': self.size,
|
|
'image': self.image,
|
|
'ip_address': self.ip_address,
|
|
'ipv6_address': self.ipv6_address,
|
|
'status': self.status,
|
|
'monthly_cost': self.monthly_cost,
|
|
'currency': self.currency,
|
|
'agent_installed': self.agent_installed,
|
|
'created_at': self.created_at.isoformat() if self.created_at else None,
|
|
}
|
|
|
|
|
|
class CloudSnapshot(SerializableMixin, db.Model):
|
|
"""Snapshot of a cloud server."""
|
|
__tablename__ = 'cloud_snapshots'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
server_id = db.Column(db.Integer, db.ForeignKey('cloud_servers.id'), nullable=False)
|
|
external_id = db.Column(db.String(128))
|
|
name = db.Column(db.String(128))
|
|
size_gb = db.Column(db.Float)
|
|
status = db.Column(db.String(32), default='creating')
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|