Repository navigation
feat(package): Add dataset-manager scripts to support listing datasets, and deleting them entirely.
#1144
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
feat(package): Add dataset-manager scripts to support listing datasets, and deleting them entirely.
#1144
Changes from 13 commits
285420a
b1c8dc4
13816a5
083baba
48612e1
c9174fb
a9b057d
bde7e4d
d9a3f6d
48d66c3
062503f
c6f8913
f2a123f
c23f6e5
056a410
13e83d5
264d89e
6547695
4aabafa
7f8e6a8
f2d20eb
d242eb6
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,190 @@ | ||||||||||||||||||||||||||||||||||
| import argparse | ||||||||||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||||||||||
| import subprocess | ||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||||||||
| from typing import Final, List | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from clp_py_utils.clp_config import ( | ||||||||||||||||||||||||||||||||||
| ARCHIVE_MANAGER_PSEUDO_COMPONENT_NAME, | ||||||||||||||||||||||||||||||||||
| StorageEngine, | ||||||||||||||||||||||||||||||||||
| StorageType, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| from clp_py_utils.s3_utils import generate_container_auth_options | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from clp_package_utils.general import ( | ||||||||||||||||||||||||||||||||||
| CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, | ||||||||||||||||||||||||||||||||||
| dump_container_config, | ||||||||||||||||||||||||||||||||||
| generate_container_config, | ||||||||||||||||||||||||||||||||||
| generate_container_name, | ||||||||||||||||||||||||||||||||||
| generate_container_start_cmd, | ||||||||||||||||||||||||||||||||||
| get_clp_home, | ||||||||||||||||||||||||||||||||||
| load_config_file, | ||||||||||||||||||||||||||||||||||
| validate_and_load_db_credentials_file, | ||||||||||||||||||||||||||||||||||
| validate_dataset_name, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Command/Argument Constants | ||||||||||||||||||||||||||||||||||
| LIST_COMMAND: Final[str] = "list" | ||||||||||||||||||||||||||||||||||
| DEL_COMMAND: Final[str] = "del" | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| logger = logging.getLogger(__file__) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def main(argv: List[str]) -> int: | ||||||||||||||||||||||||||||||||||
| clp_home = get_clp_home() | ||||||||||||||||||||||||||||||||||
| default_config_file_path = clp_home / CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Top-level parser and options | ||||||||||||||||||||||||||||||||||
| args_parser = argparse.ArgumentParser( | ||||||||||||||||||||||||||||||||||
| description="Views the list of existing datasets or deletes dataset(s)." | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| args_parser.add_argument( | ||||||||||||||||||||||||||||||||||
| "--config", | ||||||||||||||||||||||||||||||||||
| "-c", | ||||||||||||||||||||||||||||||||||
| default=str(default_config_file_path), | ||||||||||||||||||||||||||||||||||
| help="CLP package configuration file.", | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| args_parser.add_argument( | ||||||||||||||||||||||||||||||||||
| "--verbose", | ||||||||||||||||||||||||||||||||||
| "-v", | ||||||||||||||||||||||||||||||||||
| action="store_true", | ||||||||||||||||||||||||||||||||||
| help="Enable debug logging.", | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Top-level commands | ||||||||||||||||||||||||||||||||||
| subparsers = args_parser.add_subparsers( | ||||||||||||||||||||||||||||||||||
| dest="subcommand", | ||||||||||||||||||||||||||||||||||
| required=True, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| subparsers.add_parser( | ||||||||||||||||||||||||||||||||||
| LIST_COMMAND, | ||||||||||||||||||||||||||||||||||
| help="Lists existing datasets.", | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Options for delete subcommand | ||||||||||||||||||||||||||||||||||
| del_parser = subparsers.add_parser( | ||||||||||||||||||||||||||||||||||
| DEL_COMMAND, | ||||||||||||||||||||||||||||||||||
| help="Deletes dataset(s) from the database and the file system.", | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| del_parser.add_argument( | ||||||||||||||||||||||||||||||||||
| "datasets", | ||||||||||||||||||||||||||||||||||
| nargs="*", | ||||||||||||||||||||||||||||||||||
| help="dataset(s) to delete.", | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| del_parser.add_argument( | ||||||||||||||||||||||||||||||||||
| "-a", | ||||||||||||||||||||||||||||||||||
| "--all", | ||||||||||||||||||||||||||||||||||
| dest="del_all", | ||||||||||||||||||||||||||||||||||
| action="store_true", | ||||||||||||||||||||||||||||||||||
| help="Delete all existing datasets.", | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| parsed_args = args_parser.parse_args(argv[1:]) | ||||||||||||||||||||||||||||||||||
| subcommand = parsed_args.subcommand | ||||||||||||||||||||||||||||||||||
| if parsed_args.verbose: | ||||||||||||||||||||||||||||||||||
| logger.setLevel(logging.DEBUG) | ||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||
| logger.setLevel(logging.INFO) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Validate and load config file | ||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| config_file_path = Path(parsed_args.config) | ||||||||||||||||||||||||||||||||||
| clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) | ||||||||||||||||||||||||||||||||||
| clp_config.validate_logs_dir() | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Validate and load necessary credentials | ||||||||||||||||||||||||||||||||||
| validate_and_load_db_credentials_file(clp_config, clp_home, False) | ||||||||||||||||||||||||||||||||||
| except: | ||||||||||||||||||||||||||||||||||
| logger.exception("Failed to load config.") | ||||||||||||||||||||||||||||||||||
| return -1 | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| storage_engine = clp_config.package.storage_engine | ||||||||||||||||||||||||||||||||||
| if StorageEngine.CLP_S != storage_engine: | ||||||||||||||||||||||||||||||||||
| logger.error(f"Datasets operation is not supported for storage engine: {storage_engine}.") | ||||||||||||||||||||||||||||||||||
|
haiqi96 marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||||||||||||
| return -1 | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Validate input depending on subcommands | ||||||||||||||||||||||||||||||||||
| if DEL_COMMAND == subcommand: | ||||||||||||||||||||||||||||||||||
| datasets = parsed_args.datasets | ||||||||||||||||||||||||||||||||||
| del_all_flag = parsed_args.del_all | ||||||||||||||||||||||||||||||||||
| if not del_all_flag and len(datasets) == 0: | ||||||||||||||||||||||||||||||||||
| args_parser.error("No dataset name is specified for deletion.") | ||||||||||||||||||||||||||||||||||
|
haiqi96 marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||||||||||||
| if del_all_flag and len(datasets) != 0: | ||||||||||||||||||||||||||||||||||
| args_parser.error( | ||||||||||||||||||||||||||||||||||
| "The -a/--all flag cannot be used together with specified dataset names." | ||||||||||||||||||||||||||||||||||
|
haiqi96 marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| clp_db_connection_params = clp_config.database.get_clp_connection_params_and_type(True) | ||||||||||||||||||||||||||||||||||
| table_prefix = clp_db_connection_params["table_prefix"] | ||||||||||||||||||||||||||||||||||
| for dataset in datasets: | ||||||||||||||||||||||||||||||||||
| validate_dataset_name(table_prefix, dataset) | ||||||||||||||||||||||||||||||||||
| except: | ||||||||||||||||||||||||||||||||||
| logger.exception("Invalid dataset name.") | ||||||||||||||||||||||||||||||||||
| return -1 | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
Comment on lines
+114
to
+122
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Catch the specific validation error for clearer diagnostics Use Apply: - except:
- logger.exception("Invalid dataset name.")
+ except ValueError:
+ logger.exception("Invalid dataset name.")
return -1📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| container_name = generate_container_name("dataset-manager") | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| container_clp_config, mounts = generate_container_config(clp_config, clp_home) | ||||||||||||||||||||||||||||||||||
| generated_config_path_on_container, generated_config_path_on_host = dump_container_config( | ||||||||||||||||||||||||||||||||||
| container_clp_config, clp_config, container_name | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| necessary_mounts = [ | ||||||||||||||||||||||||||||||||||
| mounts.clp_home, | ||||||||||||||||||||||||||||||||||
| mounts.logs_dir, | ||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||
| if clp_config.archive_output.storage.type == StorageType.FS: | ||||||||||||||||||||||||||||||||||
| necessary_mounts.append(mounts.archives_output_dir) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||||||||||||
| aws_mount, aws_env_vars = generate_container_auth_options( | ||||||||||||||||||||||||||||||||||
| clp_config, ARCHIVE_MANAGER_PSEUDO_COMPONENT_NAME | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| if aws_mount: | ||||||||||||||||||||||||||||||||||
| necessary_mounts.append(mounts.aws_config_dir) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| container_start_cmd = generate_container_start_cmd( | ||||||||||||||||||||||||||||||||||
| container_name, necessary_mounts, clp_config.execution_container | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if len(aws_env_vars) != 0: | ||||||||||||||||||||||||||||||||||
| for aws_env_var in aws_env_vars: | ||||||||||||||||||||||||||||||||||
| container_start_cmd.extend(["-e", aws_env_var]) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # fmt: off | ||||||||||||||||||||||||||||||||||
| dataset_manager_cmd = [ | ||||||||||||||||||||||||||||||||||
| "python3", | ||||||||||||||||||||||||||||||||||
| "-m", "clp_package_utils.scripts.native.dataset_manager", | ||||||||||||||||||||||||||||||||||
| "--config", str(generated_config_path_on_container), | ||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||
| # fmt: on | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| dataset_manager_cmd.append(subcommand) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||||||||||||
| # Add subcommand-specific arguments | ||||||||||||||||||||||||||||||||||
| if DEL_COMMAND == subcommand: | ||||||||||||||||||||||||||||||||||
| if parsed_args.del_all: | ||||||||||||||||||||||||||||||||||
| dataset_manager_cmd.append("--all") | ||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||
| dataset_manager_cmd.extend(parsed_args.datasets) | ||||||||||||||||||||||||||||||||||
| elif LIST_COMMAND != subcommand: | ||||||||||||||||||||||||||||||||||
| logger.error(f"Unsupported subcommand: `{subcommand}`.") | ||||||||||||||||||||||||||||||||||
| return -1 | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| cmd = container_start_cmd + dataset_manager_cmd | ||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| proc = subprocess.run(cmd) | ||||||||||||||||||||||||||||||||||
| ret_code = proc.returncode | ||||||||||||||||||||||||||||||||||
| if 0 != ret_code: | ||||||||||||||||||||||||||||||||||
| logger.error("Dataset manager failed.") | ||||||||||||||||||||||||||||||||||
| logger.debug(f"Docker command failed: {' '.join(cmd)}") | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
Comment on lines
+171
to
+178
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Handle subprocess failures explicitly to improve diagnostics Using Apply: - proc = subprocess.run(cmd)
- ret_code = proc.returncode
- if 0 != ret_code:
- logger.error("Dataset manager failed.")
- logger.debug(f"Docker command failed: {' '.join(cmd)}")
+ try:
+ proc = subprocess.run(cmd, check=True)
+ ret_code = proc.returncode
+ except subprocess.CalledProcessError as e:
+ ret_code = e.returncode
+ logger.error("Dataset manager failed.")
+ logger.debug(f"Docker command failed with rc={ret_code}: {' '.join(cmd)}")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| # Remove generated files | ||||||||||||||||||||||||||||||||||
| generated_config_path_on_host.unlink() | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
Comment on lines
+179
to
+181
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Guard removal of generated config file If creation failed or the file was already removed, this will raise and hide the original outcome. Guard the cleanup. Apply: - generated_config_path_on_host.unlink()
+ try:
+ generated_config_path_on_host.unlink()
+ except FileNotFoundError:
+ pass
+ except Exception:
+ logger.debug(f"Failed to remove generated config at {generated_config_path_on_host}")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| return ret_code | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if "__main__" == __name__: | ||||||||||||||||||||||||||||||||||
| sys.exit(main(sys.argv)) | ||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.