-
Notifications
You must be signed in to change notification settings - Fork 0
feat(nativedb): add native database cli support #519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: devel
Are you sure you want to change the base?
Changes from all commits
ae180e9
9c36f07
3afbbc3
d8e4f2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| apiVersion: "api.rapyuta.io/v2" | ||
| kind: "Database" | ||
| metadata: | ||
| name: "my-postgres-db" | ||
| labels: | ||
| app: my-app | ||
| spec: | ||
| type: "postgres" # Required. Only supported engine: postgres | ||
| postgres: | ||
| version: "" # Required. Use `rio database versions` to list supported versions. | ||
| primary: | ||
| deviceName: "my-device" # Required. Name of the primary device. | ||
| dataDirectory: "" # Optional. Defaults to /opt/rapyuta/volumes/postgres_<name>/<version> | ||
| credentials: | ||
| username: "admin" # Required. | ||
| password: "changeme" # Required. | ||
| multipleDatabase: # Optional. Additional databases to create inside the instance. | ||
| - "app_db" | ||
| parameters: # Optional. PostgreSQL server configuration parameters. | ||
| max_connections: "200" | ||
| shared_buffers: "256MB" | ||
| migration: # Optional. In-place data migration from an older data directory. | ||
| enabled: false | ||
| sourceDataDirectory: "" | ||
| standby: # Optional. Standby (replication) configuration. | ||
| primaryInterface: "eth0" | ||
| devices: | ||
| - deviceName: "my-standby-device" | ||
| dataDirectory: "" # Optional. Defaults to /opt/rapyuta/volumes/postgres_<name>/standby/<version> | ||
| backup: # Optional. Backup configuration. | ||
| enabled: true | ||
| schedule: "0 2 * * *" # Required when enabled. Standard cron format. | ||
| directory: "/backups/my-postgres-db" # Optional. Defaults to /backups/<name> | ||
| credentials: # Required when enabled. | ||
| username: "replicator" | ||
| password: "changeme" | ||
| recovery: # Optional. Point-in-time recovery from an existing backup. | ||
| sourceBackupID: "" # Required when recovery block is present. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,7 @@ | |
| from riocli.config.context import cli_context | ||
| from riocli.configtree import config_trees | ||
| from riocli.constants import Colors, Symbols | ||
| from riocli.database import database | ||
| from riocli.deployment import deployment | ||
| from riocli.device import device | ||
| from riocli.disk import disk | ||
|
|
@@ -66,6 +67,7 @@ | |
| "sr": "static-route", | ||
| "ug": "usergroup", | ||
| "sa": "service-account", | ||
| "db": "database", | ||
| }, | ||
| help_headers_color=Colors.YELLOW, | ||
| help_options_color=Colors.GREEN, | ||
|
|
@@ -175,3 +177,4 @@ def update(silent: bool) -> None: | |
| cli.add_command(role) | ||
| cli.add_command(service_account) | ||
| cli.add_command(permission) | ||
| cli.add_command(database) | ||
|
Comment on lines
177
to
+180
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import click | ||
|
|
||
| from riocli.constants import Colors | ||
| from riocli.database.backup import backup | ||
| from riocli.database.delete import delete_database | ||
| from riocli.database.inspect import inspect_database | ||
| from riocli.database.list import list_databases | ||
| from riocli.database.versions import list_database_versions | ||
| from riocli.utils import AliasedGroup | ||
|
|
||
|
|
||
| @click.group( | ||
| invoke_without_command=False, | ||
| cls=AliasedGroup, | ||
| help_headers_color=Colors.YELLOW, | ||
| help_options_color=Colors.GREEN, | ||
| ) | ||
| def database() -> None: | ||
| """Manage database resources.""" | ||
| pass | ||
|
|
||
|
|
||
| database.add_command(list_databases) | ||
| database.add_command(inspect_database) | ||
| database.add_command(delete_database) | ||
| database.add_command(list_database_versions) | ||
| database.add_command(backup) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,190 @@ | ||
| import click | ||
| from click_help_colors import HelpColorsCommand | ||
|
|
||
| from riocli.config import new_v2_client | ||
| from riocli.constants import Colors, Symbols | ||
| from riocli.utils import AliasedGroup, inspect_with_format, tabulate_data | ||
| from riocli.utils.spinner import with_spinner | ||
|
|
||
|
|
||
| @click.group( | ||
| "backup", | ||
| invoke_without_command=False, | ||
| cls=AliasedGroup, | ||
| help_headers_color=Colors.YELLOW, | ||
| help_options_color=Colors.GREEN, | ||
| ) | ||
| def backup() -> None: | ||
| """Manage backups for a database.""" | ||
| pass | ||
|
|
||
|
|
||
| @backup.command( | ||
| "list", | ||
| cls=HelpColorsCommand, | ||
| help_headers_color=Colors.YELLOW, | ||
| help_options_color=Colors.GREEN, | ||
| ) | ||
| @click.argument("database-name") | ||
| def list_backups(database_name: str) -> None: | ||
| """List backups for a database. | ||
|
|
||
| Usage Examples: | ||
|
|
||
| $ rio database backup list DATABASE_NAME | ||
| """ | ||
| try: | ||
| client = new_v2_client(with_project=True) | ||
| result = client.list_backups(database_name=database_name) | ||
| backups = result.items or [] | ||
| _display_backup_list(backups, show_header=True) | ||
| except Exception as e: | ||
| click.secho(str(e), fg=Colors.RED) | ||
| raise SystemExit(1) | ||
|
|
||
|
|
||
| def _display_backup_list(backups: list, show_header: bool = True) -> None: | ||
| headers = [] | ||
| if show_header: | ||
| headers = ["Backup ID", "Database", "Type", "Version", "Upload Status"] | ||
|
|
||
| data = [] | ||
| for b in backups: | ||
| data.append( | ||
| [ | ||
| b.spec.id if b.spec else "", | ||
| b.spec.databaseName if b.spec else "", | ||
| b.spec.type if b.spec else "", | ||
| b.spec.version if b.spec else "", | ||
| b.spec.status if b.spec else "", | ||
| ] | ||
| ) | ||
|
|
||
| tabulate_data(data, headers) | ||
|
|
||
|
|
||
| @backup.command( | ||
| "inspect", | ||
| cls=HelpColorsCommand, | ||
| help_headers_color=Colors.YELLOW, | ||
| help_options_color=Colors.GREEN, | ||
| ) | ||
| @click.option( | ||
| "--format", | ||
| "-f", | ||
| "format_type", | ||
| default="yaml", | ||
| type=click.Choice(["json", "yaml"], case_sensitive=False), | ||
| ) | ||
| @click.argument("database-name") | ||
| @click.argument("backup-id") | ||
| def inspect_backup(format_type: str, database_name: str, backup_id: str) -> None: | ||
| """Inspect a database backup. | ||
|
|
||
| Prints the backup resource in the specified format. | ||
| The supported formats are ``json`` and ``yaml``. Default is ``yaml``. | ||
|
|
||
| Usage Examples: | ||
|
|
||
| $ rio database backup inspect DATABASE_NAME BACKUP_ID | ||
| """ | ||
| try: | ||
| client = new_v2_client() | ||
| b = client.get_backup(database_name=database_name, backup_id=backup_id) | ||
|
|
||
| if not b: | ||
| click.secho("backup not found", fg=Colors.RED) | ||
| raise SystemExit(1) | ||
|
|
||
| inspect_with_format(b.model_dump(exclude_none=True, by_alias=True), format_type) | ||
| except Exception as e: | ||
| click.secho(str(e), fg=Colors.RED) | ||
| raise SystemExit(1) | ||
|
|
||
|
|
||
| @backup.command( | ||
| "delete", | ||
| cls=HelpColorsCommand, | ||
| help_headers_color=Colors.YELLOW, | ||
| help_options_color=Colors.GREEN, | ||
| ) | ||
| @click.option( | ||
| "--force", "-f", "--silent", is_flag=True, default=False, help="Skip confirmation" | ||
| ) | ||
| @click.argument("database-name") | ||
| @click.argument("backup-id") | ||
| @with_spinner(text="Deleting backup...") | ||
| def delete_backup( | ||
| force: bool, | ||
| database_name: str, | ||
| backup_id: str, | ||
| spinner=None, | ||
| ) -> None: | ||
| """Delete a backup for a database. | ||
|
|
||
| Usage Examples: | ||
|
|
||
| $ rio database backup delete DATABASE_NAME BACKUP_ID | ||
| """ | ||
| client = new_v2_client() | ||
|
|
||
| if not force: | ||
| with spinner.hidden(): | ||
| click.confirm( | ||
| f"Do you want to delete backup {backup_id!r} for database {database_name!r}?", | ||
| default=True, | ||
| abort=True, | ||
| ) | ||
|
|
||
| try: | ||
| client.delete_backup(database_name=database_name, backup_id=backup_id) | ||
| spinner.text = click.style("Backup deleted successfully.", Colors.GREEN) | ||
| spinner.ok(click.style(Symbols.SUCCESS, Colors.GREEN)) | ||
| except Exception as e: | ||
| spinner.text = click.style(f"Failed to delete backup: {e}", Colors.RED) | ||
| spinner.red.fail(Symbols.ERROR) | ||
| raise SystemExit(1) from e | ||
|
|
||
|
|
||
| @backup.command( | ||
| "restore", | ||
| cls=HelpColorsCommand, | ||
| help_headers_color=Colors.YELLOW, | ||
| help_options_color=Colors.GREEN, | ||
| ) | ||
| @click.option( | ||
| "--force", "-f", "--silent", is_flag=True, default=False, help="Skip confirmation" | ||
| ) | ||
| @click.argument("database-name") | ||
| @click.argument("backup-id") | ||
| @with_spinner(text="Restoring backup...") | ||
| def restore_backup( | ||
| force: bool, | ||
| database_name: str, | ||
| backup_id: str, | ||
| spinner=None, | ||
| ) -> None: | ||
| """Restore a database from a backup. | ||
|
|
||
| Usage Examples: | ||
|
|
||
| $ rio database backup restore DATABASE_NAME BACKUP_ID | ||
| """ | ||
| client = new_v2_client() | ||
|
|
||
| if not force: | ||
| with spinner.hidden(): | ||
| click.confirm( | ||
| f"Do you want to restore database {database_name!r} from backup {backup_id!r}?", | ||
| default=True, | ||
| abort=True, | ||
| ) | ||
|
|
||
| try: | ||
| client.restore_backup(database_name=database_name, backup_id=backup_id) | ||
| spinner.text = click.style("Restore initiated successfully.", Colors.GREEN) | ||
| spinner.ok(click.style(Symbols.SUCCESS, Colors.GREEN)) | ||
| except Exception as e: | ||
| spinner.text = click.style(f"Failed to restore backup: {e}", Colors.RED) | ||
| spinner.red.fail(Symbols.ERROR) | ||
| raise SystemExit(1) from e |
Uh oh!
There was an error while loading. Please reload this page.