|
| 1 | +import argparse |
| 2 | +from typing import Any, Union |
| 3 | + |
| 4 | +from rich.table import Table |
| 5 | + |
| 6 | +from dstack._internal.cli.commands import APIBaseCommand |
| 7 | +from dstack._internal.cli.services.completion import ExportNameCompleter |
| 8 | +from dstack._internal.cli.utils.common import add_row_from_dict, confirm_ask, console |
| 9 | +from dstack._internal.core.models.exports import Export |
| 10 | + |
| 11 | + |
| 12 | +class ExportCommand(APIBaseCommand): |
| 13 | + NAME = "export" |
| 14 | + DESCRIPTION = "Manage exports" |
| 15 | + |
| 16 | + def _register(self): |
| 17 | + super()._register() |
| 18 | + self._parser.set_defaults(subfunc=self._list) |
| 19 | + subparsers = self._parser.add_subparsers(dest="action") |
| 20 | + |
| 21 | + list_parser = subparsers.add_parser( |
| 22 | + "list", help="List exports", formatter_class=self._parser.formatter_class |
| 23 | + ) |
| 24 | + list_parser.set_defaults(subfunc=self._list) |
| 25 | + |
| 26 | + create_parser = subparsers.add_parser( |
| 27 | + "create", help="Create an export", formatter_class=self._parser.formatter_class |
| 28 | + ) |
| 29 | + create_parser.add_argument( |
| 30 | + "name", |
| 31 | + help="The name of the export", |
| 32 | + ) |
| 33 | + create_parser.add_argument( |
| 34 | + "--importer", |
| 35 | + action="append", |
| 36 | + dest="importers", |
| 37 | + help="Importer project name (can be specified multiple times)", |
| 38 | + default=[], |
| 39 | + ) |
| 40 | + create_parser.add_argument( |
| 41 | + "--fleet", |
| 42 | + action="append", |
| 43 | + dest="fleets", |
| 44 | + help="Fleet name to export (can be specified multiple times)", |
| 45 | + default=[], |
| 46 | + ) |
| 47 | + create_parser.set_defaults(subfunc=self._create) |
| 48 | + |
| 49 | + update_parser = subparsers.add_parser( |
| 50 | + "update", help="Update an export", formatter_class=self._parser.formatter_class |
| 51 | + ) |
| 52 | + update_parser.add_argument( |
| 53 | + "name", |
| 54 | + help="The name of the export", |
| 55 | + ).completer = ExportNameCompleter() # type: ignore[attr-defined] |
| 56 | + update_parser.add_argument( |
| 57 | + "--add-importer", |
| 58 | + action="append", |
| 59 | + dest="add_importers", |
| 60 | + help="Importer project name to add (can be specified multiple times)", |
| 61 | + default=[], |
| 62 | + ) |
| 63 | + update_parser.add_argument( |
| 64 | + "--remove-importer", |
| 65 | + action="append", |
| 66 | + dest="remove_importers", |
| 67 | + help="Importer project name to remove (can be specified multiple times)", |
| 68 | + default=[], |
| 69 | + ) |
| 70 | + update_parser.add_argument( |
| 71 | + "--add-fleet", |
| 72 | + action="append", |
| 73 | + dest="add_fleets", |
| 74 | + help="Fleet name to add (can be specified multiple times)", |
| 75 | + default=[], |
| 76 | + ) |
| 77 | + update_parser.add_argument( |
| 78 | + "--remove-fleet", |
| 79 | + action="append", |
| 80 | + dest="remove_fleets", |
| 81 | + help="Fleet name to remove (can be specified multiple times)", |
| 82 | + default=[], |
| 83 | + ) |
| 84 | + update_parser.set_defaults(subfunc=self._update) |
| 85 | + |
| 86 | + delete_parser = subparsers.add_parser( |
| 87 | + "delete", help="Delete an export", formatter_class=self._parser.formatter_class |
| 88 | + ) |
| 89 | + delete_parser.add_argument( |
| 90 | + "name", |
| 91 | + help="The name of the export", |
| 92 | + ).completer = ExportNameCompleter() # type: ignore[attr-defined] |
| 93 | + delete_parser.add_argument( |
| 94 | + "-y", "--yes", help="Don't ask for confirmation", action="store_true" |
| 95 | + ) |
| 96 | + delete_parser.set_defaults(subfunc=self._delete) |
| 97 | + |
| 98 | + def _command(self, args: argparse.Namespace): |
| 99 | + super()._command(args) |
| 100 | + args.subfunc(args) |
| 101 | + |
| 102 | + def _list(self, args: argparse.Namespace): |
| 103 | + exports = self.api.client.exports.list(self.api.project) |
| 104 | + print_exports_table(exports) |
| 105 | + |
| 106 | + def _create(self, args: argparse.Namespace): |
| 107 | + with console.status("Creating export..."): |
| 108 | + export = self.api.client.exports.create( |
| 109 | + project_name=self.api.project, |
| 110 | + name=args.name, |
| 111 | + importer_projects=args.importers, |
| 112 | + exported_fleets=args.fleets, |
| 113 | + ) |
| 114 | + print_exports_table([export]) |
| 115 | + |
| 116 | + def _update(self, args: argparse.Namespace): |
| 117 | + with console.status("Updating export..."): |
| 118 | + export = self.api.client.exports.update( |
| 119 | + project_name=self.api.project, |
| 120 | + name=args.name, |
| 121 | + add_importer_projects=args.add_importers, |
| 122 | + remove_importer_projects=args.remove_importers, |
| 123 | + add_exported_fleets=args.add_fleets, |
| 124 | + remove_exported_fleets=args.remove_fleets, |
| 125 | + ) |
| 126 | + print_exports_table([export]) |
| 127 | + |
| 128 | + def _delete(self, args: argparse.Namespace): |
| 129 | + if not args.yes and not confirm_ask(f"Delete the export [code]{args.name}[/]?"): |
| 130 | + console.print("\nExiting...") |
| 131 | + return |
| 132 | + |
| 133 | + with console.status("Deleting export..."): |
| 134 | + self.api.client.exports.delete(project_name=self.api.project, name=args.name) |
| 135 | + |
| 136 | + console.print(f"Export [code]{args.name}[/] deleted") |
| 137 | + |
| 138 | + |
| 139 | +def print_exports_table(exports: list[Export]): |
| 140 | + table = Table(box=None) |
| 141 | + table.add_column("NAME", no_wrap=True) |
| 142 | + table.add_column("FLEETS") |
| 143 | + table.add_column("IMPORTERS") |
| 144 | + |
| 145 | + for export in exports: |
| 146 | + fleets = ( |
| 147 | + ", ".join([f.name for f in export.exported_fleets]) if export.exported_fleets else "-" |
| 148 | + ) |
| 149 | + importers = ", ".join([i.project_name for i in export.imports]) if export.imports else "-" |
| 150 | + |
| 151 | + row: dict[Union[str, int], Any] = { |
| 152 | + "NAME": export.name, |
| 153 | + "FLEETS": fleets, |
| 154 | + "IMPORTERS": importers, |
| 155 | + } |
| 156 | + add_row_from_dict(table, row) |
| 157 | + |
| 158 | + console.print(table) |
| 159 | + console.print() |
0 commit comments