-
Notifications
You must be signed in to change notification settings - Fork 5
feat: add dremio space commands and reject single-component paths in folder create
#24
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
Open
sandhyasun
wants to merge
7
commits into
dremio:main
Choose a base branch
from
sandhyasun:fix/issue-13-space-commands
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
d2f3f18
feat: add `dremio space` commands and reject single-component paths i…
sandhyasun 3901116
style: apply ruff formatting to space.py
sandhyasun e5d44eb
fix: fall back to CREATE FOLDER on pre-Space-Plugin clusters
sandhyasun 149e47d
fix: tighten space/folder boundary guards and error propagation
sandhyasun cc8f927
fix: verify containerType == SPACE before delete_space
sandhyasun 48fe2df
fix: align folder/space command contracts and expand introspect schema
sandhyasun 00764c9
docs: update README for dremio space command group
sandhyasun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| # | ||
| # Copyright (C) 2017-2026 Dremio Corporation | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| # | ||
| """dremio space — manage spaces in the Dremio catalog.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import asyncio | ||
|
|
||
| import typer | ||
|
|
||
| from drs.client import DremioClient | ||
| from drs.commands.folder import delete_entity, get_entity, list_catalog | ||
| from drs.commands.query import run_query | ||
| from drs.output import OutputFormat, error, output | ||
| from drs.utils import DremioAPIError, parse_path | ||
|
|
||
| app = typer.Typer(help="Manage spaces in the Dremio catalog.", context_settings={"help_option_names": ["-h", "--help"]}) | ||
|
|
||
|
|
||
| async def list_spaces(client: DremioClient) -> dict: | ||
| """List all spaces in the catalog.""" | ||
| result = await list_catalog(client) | ||
| spaces = [e for e in result.get("entities", []) if e.get("containerType") == "SPACE"] | ||
| return {"entities": spaces} | ||
|
|
||
|
|
||
| _LEGACY_SPACE_NOT_SUPPORTED = "Legacy spaces are not supported" | ||
|
|
||
|
|
||
| async def create_space(client: DremioClient, name: str) -> dict: | ||
| """Create a space. | ||
|
|
||
| Uses CREATE SPACE SQL. On pre-Space-Plugin clusters that reject it with | ||
| "Legacy spaces are not supported", falls back to CREATE FOLDER with a | ||
| single-component path. All other failures are propagated as DremioAPIError. | ||
| """ | ||
| result = await run_query(client, f'CREATE SPACE "{name}"') | ||
| if result.get("state") == "FAILED": | ||
| err = result.get("error", "") | ||
| if _LEGACY_SPACE_NOT_SUPPORTED in err: | ||
| fallback = await run_query(client, f'CREATE FOLDER "{name}"') | ||
| if fallback.get("state") == "FAILED": | ||
| fallback_err = fallback.get("error", "") | ||
| if "already exists" in fallback_err: | ||
| raise DremioAPIError(0, f"Space [{name}] already exists.") | ||
| raise DremioAPIError(0, fallback_err) | ||
| return fallback | ||
| raise DremioAPIError(0, err) | ||
| return result | ||
|
|
||
|
|
||
| async def get_space(client: DremioClient, name: str) -> dict: | ||
| """Get space metadata by name.""" | ||
| if len(parse_path(name)) > 1: | ||
| raise ValueError(f"'{name}' is a nested path. Use `dremio folder get {name}` for folders.") | ||
| return await get_entity(client, name) | ||
|
|
||
|
|
||
| async def delete_space(client: DremioClient, name: str) -> dict: | ||
| """Delete a space by name.""" | ||
| if len(parse_path(name)) > 1: | ||
| raise ValueError(f"'{name}' is a nested path. Use `dremio folder delete {name}` for folders.") | ||
| entity = await get_entity(client, name) | ||
| if entity.get("containerType") != "SPACE": | ||
| kind = entity.get("containerType", "entity").lower() | ||
| raise ValueError(f"'{name}' is a {kind}, not a space.") | ||
| return await delete_entity(client, name) | ||
|
|
||
|
|
||
| # -- CLI wrappers -- | ||
|
|
||
|
|
||
| def _get_client() -> DremioClient: | ||
| from drs.cli import get_client | ||
|
|
||
| return get_client() | ||
|
|
||
|
|
||
| def _run_command(coro, client, fmt: OutputFormat = OutputFormat.json, fields: str | None = None) -> None: | ||
| async def _execute(): | ||
| try: | ||
| return await coro | ||
| finally: | ||
| await client.close() | ||
|
|
||
| try: | ||
| result = asyncio.run(_execute()) | ||
| except Exception as exc: | ||
| from drs.utils import DremioAPIError | ||
|
|
||
| if isinstance(exc, DremioAPIError): | ||
| error(str(exc)) | ||
| raise typer.Exit(1) | ||
| if isinstance(exc, ValueError): | ||
| error(str(exc)) | ||
| raise typer.Exit(1) | ||
| raise | ||
| output(result, fmt, fields=fields) | ||
|
|
||
|
|
||
| @app.command("list") | ||
| def cli_list( | ||
| fmt: OutputFormat = typer.Option(OutputFormat.json, "--output", "-o", help="Output format"), | ||
| fields: str = typer.Option(None, "--fields", "-f", help="Comma-separated fields to include"), | ||
| ) -> None: | ||
| """List all spaces in the catalog.""" | ||
| client = _get_client() | ||
| _run_command(list_spaces(client), client, fmt, fields=fields) | ||
|
|
||
|
|
||
| @app.command("get") | ||
| def cli_get( | ||
| name: str = typer.Argument(help="Space name"), | ||
| fmt: OutputFormat = typer.Option(OutputFormat.json, "--output", "-o", help="Output format"), | ||
| fields: str = typer.Option(None, "--fields", "-f", help="Comma-separated fields to include"), | ||
| ) -> None: | ||
| """Get metadata for a space by name.""" | ||
| client = _get_client() | ||
| _run_command(get_space(client, name), client, fmt, fields=fields) | ||
|
|
||
|
|
||
| @app.command("create") | ||
| def cli_create( | ||
| name: str = typer.Argument(help="Space name to create"), | ||
| fmt: OutputFormat = typer.Option(OutputFormat.json, "--output", "-o", help="Output format"), | ||
| ) -> None: | ||
| """Create a new space.""" | ||
| client = _get_client() | ||
| _run_command(create_space(client, name), client, fmt) | ||
|
|
||
|
|
||
| @app.command("delete") | ||
| def cli_delete( | ||
| name: str = typer.Argument(help="Space name to delete"), | ||
| dry_run: bool = typer.Option(False, "--dry-run", help="Show what would be deleted without deleting"), | ||
| fmt: OutputFormat = typer.Option(OutputFormat.json, "--output", "-o", help="Output format"), | ||
| ) -> None: | ||
| """Delete a space. Cannot be undone.""" | ||
| client = _get_client() | ||
| if dry_run: | ||
| _run_command(get_space(client, name), client, fmt) | ||
| return | ||
| _run_command(delete_space(client, name), client, fmt) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.