mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-09 05:24:49 +09:00
Multiple coordinated changes: backend - Ensure JWT identity is stringified (PyJWT 2.10+ compatibility). - Allow relaxed CSP in debug (unsafe-inline + localhost/ws) for Vite dev tooling. - Rename CloudServer.metadata -> server_metadata and update usages to avoid property conflicts. - Enhance MigrationService to auto-add missing columns (SQLite-aware type mapping), create missing tables and log results. - Add run_command helper that returns a simple stdout/stderr/returncode dict. Frontend - Rename numerous ApiService methods for clarity (e.g. getGitStatus -> getGitServerStatus, triggerDeploy -> triggerAppDeploy/triggerGitDeploy, getProcesses -> getSystemProcesses, nginx advanced test/reload renamed) and update pages to call the new APIs. - Import Activity icon in WorkflowBuilder. Styles - Add Tailwind-like utilities.less and import it in main.less. - Add spacing/color aliases to variables.less, new badge component styles, and layout/sidebar tweaks (page-container, header helpers, spacing/opac adjustments). Overall: fixes compatibility issues, improves schema migration resiliency, clarifies API method names, and adds utility styles for newer pages.
127 lines
4.3 KiB
Python
127 lines
4.3 KiB
Python
from datetime import datetime
|
|
from app import db
|
|
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(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 json.loads(self.metadata_json) if self.metadata_json else {}
|
|
|
|
@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(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)
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'id': self.id,
|
|
'server_id': self.server_id,
|
|
'external_id': self.external_id,
|
|
'name': self.name,
|
|
'size_gb': self.size_gb,
|
|
'status': self.status,
|
|
'created_at': self.created_at.isoformat() if self.created_at else None,
|
|
}
|