Skip to content

Commit 3e52376

Browse files
authored
Better "dbos migrate" CLI (#419)
This command enables using the `dbos migrate` CLI command to create DBOS system tables. Usage is: ``` Usage: dbos migrate [OPTIONS] Create DBOS system tables. ╭─ Options ─────────────────────────────────────────────────────────────────────────────╮ │ --db-url -D TEXT Your DBOS application database URL [default: None] │ │ --sys-db-url -s TEXT Your DBOS system database URL [default: None] │ │ --help Show this message and exit. │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ```` This is most useful in settings where the application does not run with sufficient privilege to create the DBOS system database or system tables. Prior to deployment, the `dbos migrate` command can be run with a privileged user to create DBOS system tables. Then, the application can run with a less privileged user that has access to the system database but does not need CREATE privileges.
1 parent 51bd22b commit 3e52376

File tree

1 file changed

+39
-34
lines changed

1 file changed

+39
-34
lines changed

dbos/cli/cli.py

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -260,50 +260,52 @@ def _resolve_project_name_and_template(
260260
return project_name, template
261261

262262

263-
@app.command(
264-
help="Run your database schema migrations using the migration commands in 'dbos-config.yaml'"
265-
)
263+
@app.command(help="Create DBOS system tables.")
266264
def migrate(
267-
db_url: Annotated[
265+
app_database_url: Annotated[
268266
typing.Optional[str],
269267
typer.Option(
270268
"--db-url",
271269
"-D",
272270
help="Your DBOS application database URL",
273271
),
274272
] = None,
275-
sys_db_name: Annotated[
273+
system_database_url: Annotated[
276274
typing.Optional[str],
277275
typer.Option(
278-
"--sys-db-name",
276+
"--sys-db-url",
279277
"-s",
280-
help="Specify the name of the system database to reset",
278+
help="Your DBOS system database URL",
281279
),
282280
] = None,
283281
) -> None:
284-
config = load_config(run_process_config=False, silent=True)
285-
connection_string = _get_db_url(db_url)
286-
app_db_name = sa.make_url(connection_string).database
287-
assert app_db_name is not None, "Database name is required in URL"
288-
if sys_db_name is None:
289-
sys_db_name = app_db_name + SystemSchema.sysdb_suffix
282+
app_database_url = _get_db_url(app_database_url)
283+
system_database_url = get_system_database_url(
284+
{
285+
"system_database_url": system_database_url,
286+
"database_url": app_database_url,
287+
"database": {},
288+
}
289+
)
290290

291-
typer.echo(f"Starting schema migration for database {app_db_name}")
291+
typer.echo(f"Starting DBOS migrations")
292+
typer.echo(f"Application database: {sa.make_url(app_database_url)}")
293+
typer.echo(f"System database: {sa.make_url(system_database_url)}")
292294

293295
# First, run DBOS migrations on the system database and the application database
294296
app_db = None
295297
sys_db = None
296298
try:
297299
sys_db = SystemDatabase(
298-
system_database_url=get_system_database_url(config),
300+
system_database_url=system_database_url,
299301
engine_kwargs={
300302
"pool_timeout": 30,
301303
"max_overflow": 0,
302304
"pool_size": 2,
303305
},
304306
)
305307
app_db = ApplicationDatabase(
306-
database_url=connection_string,
308+
database_url=app_database_url,
307309
engine_kwargs={
308310
"pool_timeout": 30,
309311
"max_overflow": 0,
@@ -313,38 +315,41 @@ def migrate(
313315
sys_db.run_migrations()
314316
app_db.run_migrations()
315317
except Exception as e:
316-
typer.echo(f"DBOS system schema migration failed: {e}")
318+
typer.echo(f"DBOS migrations failed: {e}")
319+
raise typer.Exit(code=1)
317320
finally:
318321
if sys_db:
319322
sys_db.destroy()
320323
if app_db:
321324
app_db.destroy()
322325

326+
typer.echo(f"DBOS migrations successful")
327+
323328
# Next, run any custom migration commands specified in the configuration
324-
typer.echo("Executing migration commands from 'dbos-config.yaml'")
325-
try:
326-
# handle the case where the user has not specified migrations commands
329+
if os.path.exists("dbos-config.yaml"):
330+
config = load_config(run_process_config=False, silent=True)
327331
if "database" not in config:
328332
config["database"] = {}
329333
migrate_commands = (
330334
config["database"]["migrate"]
331335
if "migrate" in config["database"] and config["database"]["migrate"]
332336
else []
333337
)
334-
for command in migrate_commands:
335-
typer.echo(f"Executing migration command: {command}")
336-
result = subprocess.run(command, shell=True, text=True)
337-
if result.returncode != 0:
338-
typer.echo(f"Migration command failed: {command}")
339-
typer.echo(result.stderr)
340-
raise typer.Exit(1)
341-
if result.stdout:
342-
typer.echo(result.stdout.rstrip())
343-
except Exception as e:
344-
typer.echo(f"An error occurred during schema migration: {e}")
345-
raise typer.Exit(code=1)
346-
347-
typer.echo(f"Completed schema migration for database {app_db_name}")
338+
if migrate_commands:
339+
typer.echo("Executing migration commands from 'dbos-config.yaml'")
340+
try:
341+
for command in migrate_commands:
342+
typer.echo(f"Executing migration command: {command}")
343+
result = subprocess.run(command, shell=True, text=True)
344+
if result.returncode != 0:
345+
typer.echo(f"Migration command failed: {command}")
346+
typer.echo(result.stderr)
347+
raise typer.Exit(1)
348+
if result.stdout:
349+
typer.echo(result.stdout.rstrip())
350+
except Exception as e:
351+
typer.echo(f"An error occurred during schema migration: {e}")
352+
raise typer.Exit(code=1)
348353

349354

350355
@app.command(help="Reset the DBOS system database")

0 commit comments

Comments
 (0)