Skip to content

console: create db if not exists during init#234

Merged
vishnurk6247 merged 2 commits into
developfrom
feat/console-server-init
Mar 3, 2026
Merged

console: create db if not exists during init#234
vishnurk6247 merged 2 commits into
developfrom
feat/console-server-init

Conversation

@vishnurk6247
Copy link
Copy Markdown
Member

@vishnurk6247 vishnurk6247 commented Mar 3, 2026

Summary by CodeRabbit

  • Chores
    • Restructured container init to use an automated startup script and unified startup flow
    • Automated PostgreSQL database provisioning at container launch if missing
    • CI: added Amazon ECR publishing steps and related environment variables, plus ECR image cleanup alongside existing registry publishing

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 3, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Replaces build-time startup in the floconsole Dockerfile with an entrypoint-driven init script that ensures the PostgreSQL database exists and then launches the Uvicorn server; GitHub Actions workflows were extended to push images to AWS ECR in addition to GCP.

Changes

Cohort / File(s) Summary
Dockerfile / Init script
wavefront/server/docker/floconsole.Dockerfile, wavefront/server/scripts/console-server-init.sh
Dockerfile now copies console-server-init.sh to /app/scripts, makes it executable, and sets it as the ENTRYPOINT; removed previous build-time WORKDIR/CMD. New init script reads DB env vars, creates Postgres DB if missing (via inline Python), then starts the server with uv run server.py.
CI — Web / Floware / Floconsole workflows
.github/workflows/build-wavefront-web-develop.yaml, .github/workflows/build-wavefront-floware-develop.yaml, .github/workflows/build-wavefront-floconsole-develop.yaml
Added AWS ECR env vars (AWS_REGION, ECR_REGISTRY, ECR_REPOSITORY) and steps to configure AWS credentials, login to ECR, tag and push images to ECR, and clean up ECR image tags alongside existing GCP Artifact Registry pushes.

Sequence Diagram

sequenceDiagram
    participant Container as Docker Container
    participant Init as console-server-init.sh
    participant Postgres as PostgreSQL
    participant Python as Python Runtime / uvicorn

    Container->>Init: ENTRYPOINT (execute script)
    activate Init
    Init->>Init: set -e, prepend venv to PATH
    Init->>Postgres: connect using env vars
    activate Postgres
    alt DB exists
        Postgres-->>Init: exists
    else DB missing
        Init->>Postgres: CREATE DATABASE
        Postgres-->>Init: created
    end
    deactivate Postgres
    Init->>Python: run `uv run server.py`
    deactivate Init
    activate Python
    Python-->>Container: server running (accept requests)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • vizsatiz

Poem

🐰 A little script hopped into place,
It sniffed for a database, quickened the pace,
If missing, it planted a brand-new seed,
Then woke the server to answer each need —
Hops, logs, and a container full of grace. 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title describes a database initialization feature, but the changeset is significantly broader—it also modifies Docker configuration, adds an initialization script, and extends CI/CD workflows to support AWS ECR deployment across three additional workflows. Update the title to reflect the full scope of changes, such as 'Add console-server init script and extend CI/CD to AWS ECR' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/console-server-init

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
wavefront/server/docker/floconsole.Dockerfile (1)

20-23: Improve Docker cache reuse by reordering script copy after dependency sync.

When the script on lines 20–21 changes, line 23's expensive uv sync layer is unnecessarily invalidated and re-executed. Reorder to run uv sync first, then use COPY --chmod=755 to copy the script; this prevents cache invalidation when script contents change. Your CI setup (docker/setup-buildx-action@v3) supports BuildKit and COPY --chmod.

Proposed refactor
-COPY wavefront/server/scripts/console-server-init.sh /app/scripts/console-server-init.sh
-RUN chmod +x /app/scripts/console-server-init.sh
-
 RUN uv sync --package floconsole --frozen --no-dev
 
+COPY --chmod=755 wavefront/server/scripts/console-server-init.sh /app/scripts/console-server-init.sh
+
 ENTRYPOINT ["/app/scripts/console-server-init.sh"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wavefront/server/docker/floconsole.Dockerfile` around lines 20 - 23, Reorder
the Dockerfile steps so the expensive dependency installation RUN uv sync
--package floconsole --frozen --no-dev runs before copying the script, and
replace the current COPY + chmod sequence with a single COPY --chmod=755
/app/scripts/console-server-init.sh (i.e. move the RUN uv sync line above the
COPY and use COPY --chmod=755 to make /app/scripts/console-server-init.sh
executable) to avoid invalidating the uv sync cache when the script changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wavefront/server/scripts/console-server-init.sh`:
- Around line 15-22: Add a connection timeout to psycopg2.connect by passing
connect_timeout (e.g., connect_timeout=5) to avoid hangs, and replace the
SELECT-then-CREATE pattern with a safe try/except around the CREATE DATABASE
call: use psycopg2.sql.Identifier to build the identifier for dbname when
calling cur.execute(sql.SQL('CREATE DATABASE {}').format(Identifier(dbname)))
and catch the specific duplicate-database error
(psycopg2.errors.DuplicateDatabase or the appropriate DatabaseError SQLSTATE) to
ignore it while re-raising other exceptions; ensure conn.autocommit remains True
so CREATE runs outside transactions.

---

Nitpick comments:
In `@wavefront/server/docker/floconsole.Dockerfile`:
- Around line 20-23: Reorder the Dockerfile steps so the expensive dependency
installation RUN uv sync --package floconsole --frozen --no-dev runs before
copying the script, and replace the current COPY + chmod sequence with a single
COPY --chmod=755 /app/scripts/console-server-init.sh (i.e. move the RUN uv sync
line above the COPY and use COPY --chmod=755 to make
/app/scripts/console-server-init.sh executable) to avoid invalidating the uv
sync cache when the script changes.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c22cc40 and b88703d.

📒 Files selected for processing (2)
  • wavefront/server/docker/floconsole.Dockerfile
  • wavefront/server/scripts/console-server-init.sh

Comment on lines +15 to +22
conn = psycopg2.connect(host=host, user=user, password=password, dbname='postgres')
conn.autocommit = True
cur = conn.cursor()
cur.execute(\"SELECT 1 FROM pg_database WHERE datname = %s\", (dbname,))

if not cur.fetchone():
cur.execute('CREATE DATABASE \"' + dbname.replace('\"', '\"\"') + '\"')
print('Database created')
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and read the relevant lines
cat -n wavefront/server/scripts/console-server-init.sh | head -80

Repository: rootflo/wavefront

Length of output: 1022


🏁 Script executed:

# Check for psycopg2 version in requirements/dependencies
fd -t f -e txt -e pip -e in requirements
fd -t f -e py -e txt setup.py setup.cfg pyproject.toml
rg -l "psycopg2" --type py --type txt

Repository: rootflo/wavefront

Length of output: 218


🏁 Script executed:

# Find requirements files
fd requirements
fd "\.txt$|\.txt$|setup\.py" | head -20
rg -l "psycopg2" | head -10

Repository: rootflo/wavefront

Length of output: 322


🏁 Script executed:

# Check the floconsole pyproject.toml for psycopg2
cat wavefront/server/apps/floconsole/pyproject.toml | rg -A 5 -B 5 "psycopg2|dependencies"

Repository: rootflo/wavefront

Length of output: 625


🌐 Web query:

psycopg2 connect_timeout parameter documentation

💡 Result:

connect_timeout in psycopg2 is not a psycopg2-specific option; it’s a libpq connection parameter that psycopg2 passes through.

  • How to use (keyword arg):

    psycopg2.connect(host="...", dbname="...", user="...", password="...", connect_timeout=10)

    Psycopg2 passes “any other keyword parameter” through to the underlying client library (libpq), so connect_timeout is accepted this way. [2]

  • How to use (DSN string):

    psycopg2.connect("host=... dbname=... user=... password=... connect_timeout=10")

    Libpq documents connect_timeout as the maximum time to wait while connecting, in seconds; 0/negative/omitted means wait indefinitely, and the timeout is applied per host when multiple hosts are provided. [1]

Docs:

  • libpq connection parameters (includes connect_timeout) [1]
  • psycopg2 connect() parameters / pass-through behavior [2]

Sources:
[1] PostgreSQL libpq connection parameters documentation (libpq-connect / parameter keywords) (postgresql.org)
[2] Psycopg2 connect() documentation (“any other keyword parameter will be passed to the underlying client library”) (access.crunchydata.com)

Citations:


🌐 Web query:

psycopg2 sql module Identifier DuplicateDatabase exception

💡 Result:

In psycopg2 you can’t pass a database name as a %s parameter (placeholders are for values, not identifiers). For CREATE DATABASE, compose the identifier with psycopg2.sql.Identifier, then catch psycopg2.errors.DuplicateDatabase (SQLSTATE 42P04, base class ProgrammingError). [1][2]

import psycopg2
from psycopg2 import sql, errors

db_name = "mydb"

conn = psycopg2.connect("dbname=postgres user=postgres password=...")
conn.autocommit = True  # CREATE DATABASE must not run inside a transaction
cur = conn.cursor()

try:
    cur.execute(sql.SQL("CREATE DATABASE {}").format(sql.Identifier(db_name)))
except errors.DuplicateDatabase:
    # db already exists (42P04)
    pass
finally:
    cur.close()
    conn.close()

If you need a qualified identifier elsewhere (e.g., "schema"."table"), pass multiple parts: sql.Identifier("schema", "table"). [1]

Sources: psycopg2 SQL composition / Identifier docs [1]; psycopg2 SQLSTATE-to-exception mapping showing 42P04 -> DuplicateDatabase [2].


Harden DB creation against concurrent startup and connection hangs.

Line 15 lacks a connection timeout, and lines 18–22 use a check-then-create sequence vulnerable to race conditions when multiple containers start concurrently. One contender can fail with a duplicate database error.

Add connect_timeout parameter to psycopg2.connect(), replace the check-then-create pattern with exception handling, and use psycopg2.sql.Identifier for safe identifier composition:

Proposed fix
-python3 -c "
-import psycopg2, os
+python3 -c "
+import os
+import psycopg2
+from psycopg2 import sql, errors
 
 host = os.environ['CONSOLE_DB_HOST']
 user = os.environ['CONSOLE_DB_USERNAME']
 password = os.environ['CONSOLE_DB_PASSWORD']
 dbname = os.environ['CONSOLE_DB_NAME']
+connect_timeout = int(os.getenv('CONSOLE_DB_CONNECT_TIMEOUT', '5'))
 
-conn = psycopg2.connect(host=host, user=user, password=password, dbname='postgres')
+conn = psycopg2.connect(
+    host=host,
+    user=user,
+    password=password,
+    dbname='postgres',
+    connect_timeout=connect_timeout,
+)
 conn.autocommit = True
 cur = conn.cursor()
-cur.execute(\"SELECT 1 FROM pg_database WHERE datname = %s\", (dbname,))
-
-if not cur.fetchone():
-    cur.execute('CREATE DATABASE \"' + dbname.replace('\"', '\"\"') + '\"')
-    print('Database created')
-else:
-    print('Database already exists, skipping')
+try:
+    cur.execute(sql.SQL('CREATE DATABASE {}').format(sql.Identifier(dbname)))
+    print('Database created')
+except errors.DuplicateDatabase:
+    print('Database already exists, skipping')
+finally:
+    cur.close()
 conn.close()
 "
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
conn = psycopg2.connect(host=host, user=user, password=password, dbname='postgres')
conn.autocommit = True
cur = conn.cursor()
cur.execute(\"SELECT 1 FROM pg_database WHERE datname = %s\", (dbname,))
if not cur.fetchone():
cur.execute('CREATE DATABASE \"' + dbname.replace('\"', '\"\"') + '\"')
print('Database created')
import os
import psycopg2
from psycopg2 import sql, errors
host = os.environ['CONSOLE_DB_HOST']
user = os.environ['CONSOLE_DB_USERNAME']
password = os.environ['CONSOLE_DB_PASSWORD']
dbname = os.environ['CONSOLE_DB_NAME']
connect_timeout = int(os.getenv('CONSOLE_DB_CONNECT_TIMEOUT', '5'))
conn = psycopg2.connect(
host=host,
user=user,
password=password,
dbname='postgres',
connect_timeout=connect_timeout,
)
conn.autocommit = True
cur = conn.cursor()
try:
cur.execute(sql.SQL('CREATE DATABASE {}').format(sql.Identifier(dbname)))
print('Database created')
except errors.DuplicateDatabase:
print('Database already exists, skipping')
finally:
cur.close()
conn.close()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wavefront/server/scripts/console-server-init.sh` around lines 15 - 22, Add a
connection timeout to psycopg2.connect by passing connect_timeout (e.g.,
connect_timeout=5) to avoid hangs, and replace the SELECT-then-CREATE pattern
with a safe try/except around the CREATE DATABASE call: use
psycopg2.sql.Identifier to build the identifier for dbname when calling
cur.execute(sql.SQL('CREATE DATABASE {}').format(Identifier(dbname))) and catch
the specific duplicate-database error (psycopg2.errors.DuplicateDatabase or the
appropriate DatabaseError SQLSTATE) to ignore it while re-raising other
exceptions; ensure conn.autocommit remains True so CREATE runs outside
transactions.

@vishnurk6247 vishnurk6247 merged commit 60ad6f1 into develop Mar 3, 2026
8 of 9 checks passed
@vishnurk6247 vishnurk6247 deleted the feat/console-server-init branch March 3, 2026 06:46
thomastomy5 pushed a commit that referenced this pull request Apr 27, 2026
* console: create db if not exists during init

* chore: push images to ECR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants