Skip to content

Enable db commands for externally-managed databases - #173

Open
blsmth wants to merge 5 commits into
mainfrom
issue-146-external-database
Open

Enable db commands for externally-managed databases#173
blsmth wants to merge 5 commits into
mainfrom
issue-146-external-database

Conversation

@blsmth

@blsmth blsmth commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Closes #146.

Adds --external-database <postgres|mysql> to apppack create app, which sets a new ExternalDatabaseEngine CloudFormation parameter so db shell/db dump/db load can target an externally-managed database (Neon, Crunchy, etc.) reachable via the app's DATABASE_URL config variable. Also adds a matching interactive prompt in AskForDatabase (for apppack modify app), client-side validation (mutually exclusive with --addon-database/--addon-database-name, engine must be postgres or mysql), and replaces the unhelpful "unknown database engine " error with a targeted message pointing users at either apppack modify app/--external-database or apppack create database.

Depends on the formations change (apppack-backend) landing and being released first — until formations emits dbutils.engine for externally-configured apps, setting this flag has no effect.

Caveat carried over from the spec: apppack db load's load-from-s3.sh script likely does a DROP/CREATE of the target database, which some managed providers (e.g. Neon) may not permit for the app's role. db shell and db dump are the confident wins here; db load may not reach full parity even after this lands.

Happy path (DBShellTaskInfo/DBDumpLocation/DBDumpLoadFamily, isPostgres in cmd/db.go) is unchanged.

Want a Test Plan section added, or is this concise enough as-is?

@ipmb

ipmb commented Aug 12, 2026 via email

Copy link
Copy Markdown
Member

blsmth added a commit that referenced this pull request Aug 19, 2026
ipmb reviewed #173 and pointed out the user should never have to type
the database engine -- it's inferable from the DATABASE_URL scheme.
Delete --external-database and both interactive prompts; SetInternalFields
now auto-detects the engine from the app's DATABASE_URL config variable
via SSM, for both `create app` and `modify app`.

A managed AppPack database and pipelines/review apps always force the
field back to "", so this is idempotent no matter how many times
`modify app` runs. Any SSM/parse failure is silent (the common case,
since `create app` runs before the app exists); an unrecognized scheme
still gets one warning line, since there's no longer a flag to fall
back on.

The formations-side CloudFormation parameter and condition are unchanged
-- every db-utils resource is still gated on DatabaseEnabled, and there
is no task definition to run for an external DB without it.
@blsmth

blsmth commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Pushed an update that addresses your review: --external-database and both interactive prompts (enable? / which engine?) are gone. SetInternalFields now infers ExternalDatabaseEngine from the app's DATABASE_URL config variable (read from SSM), comparing only the URL scheme -- postgres/postgresql/pgsql/psql -> postgres, mysql/mysql2/mariadb -> mysql. This runs for both create app and modify app, so the resulting workflow is:

apppack create app ...
apppack config set DATABASE_URL=...
apppack modify app <name>   # picks up the engine automatically

A managed AppPack database (--addon-database/--addon-database-name) always wins and forces the field back to "", and pipelines/review apps are excluded, since the CloudFormation condition requires IsApp -- so detection is idempotent no matter how many times modify app runs.

On the "no CloudFormation changes" half of your comment: that part isn't achievable. Every db-utils resource (task definitions, execution/task roles, log group, S3 bucket) is gated behind DatabaseEnabled, and app.StartTask only ever does DescribeTaskDefinition -> RunTask -- there's no task-definition family to run against for an external DB without the formations change. That half of the PR is unchanged.

One tradeoff worth flagging: since there's no flag anymore, there's also no escape hatch for a DATABASE_URL with a scheme we don't recognize -- we print one warning and leave db shell/db dump disabled rather than failing the deploy. Happy to add --external-database back as a hidden override for that case if you'd rather have one. Let me know.

@ipmb

ipmb commented Aug 19, 2026 via email

Copy link
Copy Markdown
Member

blsmth added 2 commits August 24, 2026 12:07
Registers ExternalDatabaseEngine as a CloudFormation parameter on
apppack create app (postgres|mysql), validates it is mutually
exclusive with --addon-database/--addon-database-name, and adds a
matching interactive prompt in AskForDatabase for apppack modify app.

Also replaces the unhelpful "unknown database engine " error (empty
engine) with a targeted message that checks for a DATABASE_URL config
variable and tells the user how to enable db utils or create a
database.
ipmb reviewed #173 and pointed out the user should never have to type
the database engine -- it's inferable from the DATABASE_URL scheme.
Delete --external-database and both interactive prompts; SetInternalFields
now auto-detects the engine from the app's DATABASE_URL config variable
via SSM, for both `create app` and `modify app`.

A managed AppPack database and pipelines/review apps always force the
field back to "", so this is idempotent no matter how many times
`modify app` runs. Any SSM/parse failure is silent (the common case,
since `create app` runs before the app exists); an unrecognized scheme
still gets one warning line, since there's no longer a flag to fall
back on.

The formations-side CloudFormation parameter and condition are unchanged
-- every db-utils resource is still gated on DatabaseEnabled, and there
is no task definition to run for an external DB without it.
@blsmth
blsmth force-pushed the issue-146-external-database branch from 79c368f to b31a056 Compare August 24, 2026 16:07
blsmth added 2 commits August 24, 2026 12:16
The engine is now inferred from DATABASE_URL, so the "no database
configured" error was pointing users at a flag that no longer exists --
following its advice would fail with "unknown flag". Drop the
parenthetical and let `apppack modify app` be the single answer.

Turn the test that asserted on the flag name into a negative assertion,
so a stale reference can't creep back into user-facing text.
The previous commit was made against an index that already held staged
deletions from a concurrent rebase in this worktree, so it removed the
go vet/fmt CI gate, the flag-shorthand collision tests, and unrelated
CHANGELOG and config entries. Restore all five from main; none of them
have anything to do with this branch.
@blsmth blsmth changed the title Add --external-database flag for externally-managed databases Enable db commands for externally-managed databases Aug 24, 2026
Setting DATABASE_URL is the obvious move when pointing an app at an
externally-managed database, but on its own it does nothing for
`apppack db shell`/`db dump`/`db load` -- those need the db-utils
resources, which only appear when the stack is updated. Nothing told the
user that second step existed, so the discoverable path dead-ended at a
config variable that looked sufficient.

Print a follow-up hint from `config set` and `config import` when
DATABASE_URL lands on an app whose db utils aren't enabled yet. Stays
quiet when an engine is already set (managed database, or a previous
`modify app`), and for pipelines/review apps, where external databases
are gated off in CloudFormation anyway.

Advisory only: the variable is already stored by the time we're called,
so a settings-load failure just skips the hint rather than failing a
command that succeeded.

Suggested by ipmb in review of #173.
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.

Allow DB commands against external databases

2 participants