200 lines
7.1 KiB
Python
200 lines
7.1 KiB
Python
from django.db import models
|
|
from django.contrib.auth.models import User
|
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
|
import json
|
|
|
|
|
|
class PostgresCluster(models.Model):
|
|
"""Model for managing Postgres cluster configurations."""
|
|
|
|
CLUSTER_TYPES = [
|
|
('single', 'Single Instance'),
|
|
('replica', 'Primary with Replicas'),
|
|
('standby', 'Standby Cluster'),
|
|
]
|
|
|
|
DEPLOYMENT_TYPES = [
|
|
('docker', 'Docker'),
|
|
('kubernetes', 'Kubernetes'),
|
|
('local', 'Local Linux'),
|
|
]
|
|
|
|
name = models.CharField(max_length=100, unique=True)
|
|
description = models.TextField(blank=True)
|
|
cluster_type = models.CharField(max_length=20, choices=CLUSTER_TYPES, default='single')
|
|
deployment_type = models.CharField(max_length=20, choices=DEPLOYMENT_TYPES, default='docker')
|
|
|
|
# PostgreSQL Configuration
|
|
postgres_version = models.CharField(max_length=10, default='15')
|
|
port = models.IntegerField(default=5432, validators=[MinValueValidator(1024), MaxValueValidator(65535)])
|
|
data_directory = models.CharField(max_length=255, default='/var/lib/postgresql/data')
|
|
|
|
# Resource Configuration
|
|
cpu_limit = models.CharField(max_length=20, default='2')
|
|
memory_limit = models.CharField(max_length=20, default='4Gi')
|
|
storage_size = models.CharField(max_length=20, default='10Gi')
|
|
|
|
# Network Configuration
|
|
host = models.CharField(max_length=255, default='localhost')
|
|
external_port = models.IntegerField(default=5432, validators=[MinValueValidator(1024), MaxValueValidator(65535)])
|
|
|
|
# Authentication
|
|
admin_user = models.CharField(max_length=50, default='postgres')
|
|
admin_password = models.CharField(max_length=255)
|
|
|
|
# Extensions and Libraries
|
|
extensions = models.JSONField(default=list, blank=True)
|
|
libraries = models.JSONField(default=list, blank=True)
|
|
|
|
# TLS Configuration
|
|
tls_enabled = models.BooleanField(default=False)
|
|
tls_cert_path = models.CharField(max_length=255, blank=True)
|
|
tls_key_path = models.CharField(max_length=255, blank=True)
|
|
tls_ca_path = models.CharField(max_length=255, blank=True)
|
|
|
|
# Connection Pooling
|
|
pgpool_enabled = models.BooleanField(default=False)
|
|
pgpool_instances = models.IntegerField(default=1, validators=[MinValueValidator(1), MaxValueValidator(10)])
|
|
|
|
# Status
|
|
status = models.CharField(max_length=20, default='stopped', choices=[
|
|
('running', 'Running'),
|
|
('stopped', 'Stopped'),
|
|
('starting', 'Starting'),
|
|
('stopping', 'Stopping'),
|
|
('error', 'Error'),
|
|
('updating', 'Updating'),
|
|
])
|
|
|
|
# Metadata
|
|
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class Meta:
|
|
ordering = ['-created_at']
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
def get_connection_string(self):
|
|
"""Get the connection string for this cluster."""
|
|
return f"postgresql://{self.admin_user}:{self.admin_password}@{self.host}:{self.external_port}/postgres"
|
|
|
|
def get_extensions_list(self):
|
|
"""Get the list of enabled extensions."""
|
|
return self.extensions if isinstance(self.extensions, list) else []
|
|
|
|
def get_libraries_list(self):
|
|
"""Get the list of enabled libraries."""
|
|
return self.libraries if isinstance(self.libraries, list) else []
|
|
|
|
|
|
class PostgresInstance(models.Model):
|
|
"""Model for managing individual Postgres instances within a cluster."""
|
|
|
|
INSTANCE_TYPES = [
|
|
('primary', 'Primary'),
|
|
('replica', 'Replica'),
|
|
('standby', 'Standby'),
|
|
]
|
|
|
|
cluster = models.ForeignKey(PostgresCluster, on_delete=models.CASCADE, related_name='instances')
|
|
name = models.CharField(max_length=100)
|
|
instance_type = models.CharField(max_length=20, choices=INSTANCE_TYPES, default='primary')
|
|
|
|
# Instance Configuration
|
|
host = models.CharField(max_length=255)
|
|
port = models.IntegerField(validators=[MinValueValidator(1024), MaxValueValidator(65535)])
|
|
data_directory = models.CharField(max_length=255)
|
|
|
|
# Status
|
|
status = models.CharField(max_length=20, default='stopped', choices=[
|
|
('running', 'Running'),
|
|
('stopped', 'Stopped'),
|
|
('starting', 'Starting'),
|
|
('stopping', 'Stopping'),
|
|
('error', 'Error'),
|
|
('syncing', 'Syncing'),
|
|
])
|
|
|
|
# Replication Configuration (for replicas)
|
|
replication_slot = models.CharField(max_length=100, blank=True)
|
|
lag_seconds = models.IntegerField(default=0)
|
|
|
|
# Resource Usage
|
|
cpu_usage = models.FloatField(default=0.0)
|
|
memory_usage = models.FloatField(default=0.0)
|
|
disk_usage = models.FloatField(default=0.0)
|
|
|
|
# Metadata
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class Meta:
|
|
unique_together = ['cluster', 'name']
|
|
ordering = ['instance_type', 'name']
|
|
|
|
def __str__(self):
|
|
return f"{self.cluster.name} - {self.name}"
|
|
|
|
|
|
class ClusterUser(models.Model):
|
|
"""Model for managing database users within clusters."""
|
|
|
|
cluster = models.ForeignKey(PostgresCluster, on_delete=models.CASCADE, related_name='users')
|
|
username = models.CharField(max_length=50)
|
|
password = models.CharField(max_length=255)
|
|
is_superuser = models.BooleanField(default=False)
|
|
can_create_db = models.BooleanField(default=False)
|
|
can_login = models.BooleanField(default=True)
|
|
|
|
# Permissions
|
|
permissions = models.JSONField(default=dict, blank=True)
|
|
|
|
# Metadata
|
|
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class Meta:
|
|
unique_together = ['cluster', 'username']
|
|
ordering = ['username']
|
|
|
|
def __str__(self):
|
|
return f"{self.cluster.name} - {self.username}"
|
|
|
|
|
|
class ClusterDatabase(models.Model):
|
|
"""Model for managing databases within clusters."""
|
|
|
|
cluster = models.ForeignKey(PostgresCluster, on_delete=models.CASCADE, related_name='databases')
|
|
name = models.CharField(max_length=50)
|
|
owner = models.ForeignKey(ClusterUser, on_delete=models.CASCADE)
|
|
|
|
# Configuration
|
|
encoding = models.CharField(max_length=20, default='UTF8')
|
|
collation = models.CharField(max_length=50, default='en_US.utf8')
|
|
ctype = models.CharField(max_length=50, default='en_US.utf8')
|
|
|
|
# Size tracking
|
|
size_bytes = models.BigIntegerField(default=0)
|
|
|
|
# Metadata
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class Meta:
|
|
unique_together = ['cluster', 'name']
|
|
ordering = ['name']
|
|
|
|
def __str__(self):
|
|
return f"{self.cluster.name} - {self.name}"
|
|
|
|
def get_size_mb(self):
|
|
"""Get database size in MB."""
|
|
return round(self.size_bytes / (1024 * 1024), 2)
|
|
|
|
def get_size_gb(self):
|
|
"""Get database size in GB."""
|
|
return round(self.size_bytes / (1024 * 1024 * 1024), 2) |