|
17 | 17 |
|
18 | 18 | import cortexapps_cli.commands.scorecards as scorecards |
19 | 19 | import cortexapps_cli.commands.catalog as catalog |
| 20 | +import cortexapps_cli.commands.catalogs as catalogs |
20 | 21 | import cortexapps_cli.commands.entity_types as entity_types |
21 | 22 | import cortexapps_cli.commands.entity_relationship_types as entity_relationship_types |
22 | 23 | import cortexapps_cli.commands.entity_relationships as entity_relationships |
@@ -206,16 +207,30 @@ def _export_workflows(ctx, directory): |
206 | 207 | except Exception as e: |
207 | 208 | print(f"Failed to export workflow {tag}: {e}") |
208 | 209 |
|
209 | | -backupTypes = { |
| 210 | +def _export_catalog_pages(ctx, directory): |
| 211 | + directory = _directory_name(directory, "catalogs") |
| 212 | + |
| 213 | + data = catalogs.list(ctx, _print=False) |
| 214 | + pages = sorted(data.get("catalogPages", []), key=lambda x: x["slug"]) |
| 215 | + |
| 216 | + for page in pages: |
| 217 | + slug = page["slug"] |
| 218 | + try: |
| 219 | + _file_name(directory, slug, json.dumps(page, indent=2), "json") |
| 220 | + except Exception as e: |
| 221 | + print(f"Failed to export catalog page {slug}: {e}") |
| 222 | + |
| 223 | +backupTypes = sorted([ |
210 | 224 | "catalog", |
211 | | - "entity-types", |
| 225 | + "catalogs", |
212 | 226 | "entity-relationship-types", |
213 | 227 | "entity-relationships", |
| 228 | + "entity-types", |
214 | 229 | "ip-allowlist", |
215 | 230 | "plugins", |
216 | 231 | "scorecards", |
217 | | - "workflows" |
218 | | -} |
| 232 | + "workflows", |
| 233 | +]) |
219 | 234 | backupString = ','.join(backupTypes) |
220 | 235 |
|
221 | 236 | def _parse_export_types(value: str) -> List[str]: |
@@ -257,6 +272,7 @@ def export( |
257 | 272 |
|
258 | 273 | Exports the following objects: |
259 | 274 | - catalog |
| 275 | + - catalogs |
260 | 276 | - entity-types |
261 | 277 | - entity-relationship-types |
262 | 278 | - entity-relationships |
@@ -310,6 +326,8 @@ def export( |
310 | 326 | _export_scorecards(ctx, directory) |
311 | 327 | if "workflows" in export_types: |
312 | 328 | _export_workflows(ctx, directory) |
| 329 | + if "catalogs" in export_types: |
| 330 | + _export_catalog_pages(ctx, directory) |
313 | 331 |
|
314 | 332 | print("\nExport complete!") |
315 | 333 | print("Contents available in " + directory) |
@@ -744,6 +762,44 @@ def import_scorecard_file(file_info): |
744 | 762 |
|
745 | 763 | return ("scorecards", len(results) - failed_count, [(fp, et, em) for fn, fp, et, em in results if et]) |
746 | 764 |
|
| 765 | +def _import_catalog_pages(ctx, directory): |
| 766 | + results = [] |
| 767 | + failed_count = 0 |
| 768 | + if os.path.isdir(directory): |
| 769 | + print("Processing: " + directory) |
| 770 | + files = [(filename, os.path.join(directory, filename)) |
| 771 | + for filename in sorted(os.listdir(directory)) |
| 772 | + if os.path.isfile(os.path.join(directory, filename))] |
| 773 | + |
| 774 | + def import_catalog_page_file(file_info): |
| 775 | + filename, file_path = file_info |
| 776 | + try: |
| 777 | + with open(file_path) as f: |
| 778 | + catalogs.create(ctx, file_input=f, _print=False) |
| 779 | + return (filename, file_path, None, None) |
| 780 | + except typer.Exit as e: |
| 781 | + return (filename, file_path, "HTTP", "Validation or HTTP error") |
| 782 | + except Exception as e: |
| 783 | + return (filename, file_path, type(e).__name__, str(e)) |
| 784 | + |
| 785 | + # Import all files in parallel |
| 786 | + with ThreadPoolExecutor(max_workers=10) as executor: |
| 787 | + futures = {executor.submit(import_catalog_page_file, file_info): file_info[0] for file_info in files} |
| 788 | + results = [] |
| 789 | + for future in as_completed(futures): |
| 790 | + results.append(future.result()) |
| 791 | + |
| 792 | + # Print results in alphabetical order |
| 793 | + failed_count = 0 |
| 794 | + for filename, file_path, error_type, error_msg in sorted(results, key=lambda x: x[0]): |
| 795 | + if error_type: |
| 796 | + print(f" Failed to import {filename}: {error_type} - {error_msg}") |
| 797 | + failed_count += 1 |
| 798 | + else: |
| 799 | + print(f" Importing: {filename}") |
| 800 | + |
| 801 | + return ("catalogs", len(results) - failed_count, [(fp, et, em) for fn, fp, et, em in results if et]) |
| 802 | + |
747 | 803 | def _import_workflows(ctx, directory): |
748 | 804 | results = [] |
749 | 805 | failed_count = 0 |
@@ -805,6 +861,7 @@ def import_tenant( |
805 | 861 | all_stats.append(_import_plugins(ctx, directory + "/plugins")) |
806 | 862 | all_stats.append(_import_scorecards(ctx, directory + "/scorecards")) |
807 | 863 | all_stats.append(_import_workflows(ctx, directory + "/workflows")) |
| 864 | + all_stats.append(_import_catalog_pages(ctx, directory + "/catalogs")) |
808 | 865 |
|
809 | 866 | # Print summary |
810 | 867 | print("\n" + "="*80) |
@@ -861,6 +918,8 @@ def import_tenant( |
861 | 918 | print(f"cortex scorecards create -f \"{file_path}\"") |
862 | 919 | elif import_type == "workflows": |
863 | 920 | print(f"cortex workflows create -f \"{file_path}\"") |
| 921 | + elif import_type == "catalogs": |
| 922 | + print(f"cortex catalogs create -f \"{file_path}\"") |
864 | 923 |
|
865 | 924 | # Exit with non-zero code if any imports failed |
866 | 925 | if total_failed > 0: |
|
0 commit comments