Skip to content

Commit

Permalink
Add create user/databse to syncmdl and remove second db container for…
Browse files Browse the repository at this point in the history
… local

Removing 2nd db container for local makes the environment more consistent with production as we use only 1 RDS instance for multiple dbs
  • Loading branch information
aloftus23 committed Jan 9, 2025
1 parent 8ba79fe commit e5c0233
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 50 deletions.
3 changes: 3 additions & 0 deletions backend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ syncdb:
syncdb-populate:
docker compose exec backend python manage.py syncdb --populate

syncdb-populate:
docker compose exec backend python manage.py syncdb --dangerouslyforce


# Synchronize and populate the database
syncmdl:
Expand Down
54 changes: 50 additions & 4 deletions backend/src/xfd_django/xfd_api/management/commands/syncmdl.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"""Populate command."""
# Standard Python Libraries
import os

# Third-Party Libraries
from django.core.management.base import BaseCommand
from django.db import connections
from xfd_api.tasks.syncdb_helpers import drop_all_tables, synchronize


Expand All @@ -22,11 +26,53 @@ def handle(self, *args, **options):
"""Handle method."""
dangerouslyforce = options["dangerouslyforce"]

# Step 1: Database Reset and Migration
mdl_username = os.getenv("MDL_USERNAME")
mdl_password = os.getenv("MDL_PASSWORD")
mdl_name = os.getenv("MDL_NAME")

if not (mdl_username and mdl_password and mdl_name):
self.stderr.write(
"Error: MDL_USERNAME, MDL_PASSWORD, and MDL_NAME must be set in the environment."
)
return

connection = connections["default"]

# Step 1: Database User and Database Setup
self.stdout.write("Setting up the MDL database and user...")

with connection.cursor() as cursor:
try:
cursor.execute(
f"CREATE USER {mdl_username} WITH PASSWORD '{mdl_password}';"
)
except Exception as e:
self.stdout.write(f"User creation failed (likely already exists): {e}")

try:
cursor.execute(f"GRANT {mdl_username} TO {os.getenv('DB_USERNAME')};")
except Exception as e:
self.stdout.write(f"Granting role failed: {e}")

try:
cursor.execute(f"CREATE DATABASE {mdl_name} OWNER {mdl_username};")
except Exception as e:
self.stdout.write(
f"Database creation failed (likely already exists): {e}"
)

try:
cursor.execute(
f"GRANT ALL PRIVILEGES ON DATABASE {mdl_name} TO {mdl_username};"
)
except Exception as e:
self.stdout.write(f"Granting privileges failed: {e}")

# Step 2: Synchronize or Reset the Database
self.stdout.write("Synchronizing the MDL database schema...")
if dangerouslyforce:
self.stdout.write("Dropping and recreating the database...")
drop_all_tables(app_label="xfd_mini_dl")
synchronize(target_app_label="xfd_mini_dl")
# else:
self.stdout.write("Applying migrations...")
synchronize(target_app_label="xfd_mini_dl")

self.stdout.write("Database synchronization complete.")
43 changes: 13 additions & 30 deletions backend/src/xfd_django/xfd_api/tasks/syncdb_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,47 +396,30 @@ def drop_all_tables(app_label=None):

if app_label is None:
raise ValueError(
"The 'app_label' parameter is required to synchronize specific models. "
"Please provide an app label."
"The 'app_label' parameter is required to synchronize specific models."
)

if app_label not in allowed_labels:
raise ValueError(
"Invalid 'app_label' provided. Must be one of: {}.".format(
", ".join(allowed_labels)
)
f"Invalid 'app_label' provided. Must be one of: {', '.join(allowed_labels)}."
)

database = db_mapping.get(app_label, "default")
print(
"Synchronizing database schema for app '{}' in database '{}'...".format(
app_label, database
)
f"Resetting database schema for app '{app_label}' in database '{database}'..."
)
with connections[database].cursor() as cursor:
if app_label:
# Get tables for the specified app
app_models = apps.get_app_config(app_label).get_models()
table_names = [model._meta.db_table for model in app_models]
else:
# Get all tables if no app is specified
cursor.execute(
"SELECT tablename FROM pg_tables WHERE schemaname = 'public';"
)
table_names = [row[0] for row in cursor.fetchall()]

for table in table_names:
try:
print(f"Dropping table: {table}")
cursor.execute(
"DROP TABLE IF EXISTS {} CASCADE;".format(
connections[database].ops.quote_name(table)
)
)
except Exception as e:
print(f"Error dropping table {table}: {e}")
with connections[database].cursor() as cursor:
try:
# Drop all constraints first to avoid foreign key dependency issues
cursor.execute("DROP SCHEMA public CASCADE;")
cursor.execute("CREATE SCHEMA public;")
cursor.execute("GRANT ALL ON SCHEMA public TO postgres;")
cursor.execute("GRANT ALL ON SCHEMA public TO public;")
except Exception as e:
print(f"Error resetting schema: {e}")

print("All specified tables dropped successfully.")
print("Database schema reset successfully.")


def chunked_iterable(iterable, size):
Expand Down
16 changes: 0 additions & 16 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,6 @@ services:
- POSTGRES_PASSWORD=${DB_PASSWORD}
command: ['postgres', '-c', 'log_statement=all', '-c', 'log_duration=on']

db_mdl:
image: postgres:15.3
volumes:
- ./postgres-data-mdl:/var/lib/postgresql/data
- ./backend/db-init-mdl:/docker-entrypoint-initdb.d
ports:
- '5433:5432'
env_file:
- ./.env
networks:
- backend
environment:
- POSTGRES_USER=${MDL_USERNAME}
- POSTGRES_PASSWORD=${MDL_PASSWORD}
command: ['postgres', '-c', 'log_statement=all', '-c', 'log_duration=on']

frontend:
build: ./frontend
volumes:
Expand Down

0 comments on commit e5c0233

Please sign in to comment.