nextmv 0.18.0__py3-none-any.whl → 1.0.0.dev2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. nextmv/__about__.py +1 -1
  2. nextmv/__entrypoint__.py +8 -13
  3. nextmv/__init__.py +53 -0
  4. nextmv/_serialization.py +96 -0
  5. nextmv/base_model.py +54 -9
  6. nextmv/cli/CONTRIBUTING.md +511 -0
  7. nextmv/cli/__init__.py +0 -0
  8. nextmv/cli/cloud/__init__.py +47 -0
  9. nextmv/cli/cloud/acceptance/__init__.py +27 -0
  10. nextmv/cli/cloud/acceptance/create.py +393 -0
  11. nextmv/cli/cloud/acceptance/delete.py +68 -0
  12. nextmv/cli/cloud/acceptance/get.py +104 -0
  13. nextmv/cli/cloud/acceptance/list.py +62 -0
  14. nextmv/cli/cloud/acceptance/update.py +95 -0
  15. nextmv/cli/cloud/account/__init__.py +28 -0
  16. nextmv/cli/cloud/account/create.py +83 -0
  17. nextmv/cli/cloud/account/delete.py +60 -0
  18. nextmv/cli/cloud/account/get.py +66 -0
  19. nextmv/cli/cloud/account/update.py +70 -0
  20. nextmv/cli/cloud/app/__init__.py +35 -0
  21. nextmv/cli/cloud/app/create.py +141 -0
  22. nextmv/cli/cloud/app/delete.py +58 -0
  23. nextmv/cli/cloud/app/exists.py +44 -0
  24. nextmv/cli/cloud/app/get.py +66 -0
  25. nextmv/cli/cloud/app/list.py +61 -0
  26. nextmv/cli/cloud/app/push.py +137 -0
  27. nextmv/cli/cloud/app/update.py +124 -0
  28. nextmv/cli/cloud/batch/__init__.py +29 -0
  29. nextmv/cli/cloud/batch/create.py +454 -0
  30. nextmv/cli/cloud/batch/delete.py +68 -0
  31. nextmv/cli/cloud/batch/get.py +104 -0
  32. nextmv/cli/cloud/batch/list.py +63 -0
  33. nextmv/cli/cloud/batch/metadata.py +66 -0
  34. nextmv/cli/cloud/batch/update.py +95 -0
  35. nextmv/cli/cloud/data/__init__.py +26 -0
  36. nextmv/cli/cloud/data/upload.py +162 -0
  37. nextmv/cli/cloud/ensemble/__init__.py +31 -0
  38. nextmv/cli/cloud/ensemble/create.py +414 -0
  39. nextmv/cli/cloud/ensemble/delete.py +67 -0
  40. nextmv/cli/cloud/ensemble/get.py +65 -0
  41. nextmv/cli/cloud/ensemble/update.py +103 -0
  42. nextmv/cli/cloud/input_set/__init__.py +30 -0
  43. nextmv/cli/cloud/input_set/create.py +170 -0
  44. nextmv/cli/cloud/input_set/get.py +63 -0
  45. nextmv/cli/cloud/input_set/list.py +63 -0
  46. nextmv/cli/cloud/input_set/update.py +123 -0
  47. nextmv/cli/cloud/instance/__init__.py +35 -0
  48. nextmv/cli/cloud/instance/create.py +290 -0
  49. nextmv/cli/cloud/instance/delete.py +62 -0
  50. nextmv/cli/cloud/instance/exists.py +39 -0
  51. nextmv/cli/cloud/instance/get.py +62 -0
  52. nextmv/cli/cloud/instance/list.py +60 -0
  53. nextmv/cli/cloud/instance/update.py +216 -0
  54. nextmv/cli/cloud/managed_input/__init__.py +31 -0
  55. nextmv/cli/cloud/managed_input/create.py +146 -0
  56. nextmv/cli/cloud/managed_input/delete.py +65 -0
  57. nextmv/cli/cloud/managed_input/get.py +63 -0
  58. nextmv/cli/cloud/managed_input/list.py +60 -0
  59. nextmv/cli/cloud/managed_input/update.py +97 -0
  60. nextmv/cli/cloud/run/__init__.py +37 -0
  61. nextmv/cli/cloud/run/cancel.py +37 -0
  62. nextmv/cli/cloud/run/create.py +530 -0
  63. nextmv/cli/cloud/run/get.py +199 -0
  64. nextmv/cli/cloud/run/input.py +86 -0
  65. nextmv/cli/cloud/run/list.py +80 -0
  66. nextmv/cli/cloud/run/logs.py +167 -0
  67. nextmv/cli/cloud/run/metadata.py +67 -0
  68. nextmv/cli/cloud/run/track.py +501 -0
  69. nextmv/cli/cloud/scenario/__init__.py +29 -0
  70. nextmv/cli/cloud/scenario/create.py +451 -0
  71. nextmv/cli/cloud/scenario/delete.py +65 -0
  72. nextmv/cli/cloud/scenario/get.py +102 -0
  73. nextmv/cli/cloud/scenario/list.py +63 -0
  74. nextmv/cli/cloud/scenario/metadata.py +67 -0
  75. nextmv/cli/cloud/scenario/update.py +93 -0
  76. nextmv/cli/cloud/secrets/__init__.py +33 -0
  77. nextmv/cli/cloud/secrets/create.py +206 -0
  78. nextmv/cli/cloud/secrets/delete.py +67 -0
  79. nextmv/cli/cloud/secrets/get.py +66 -0
  80. nextmv/cli/cloud/secrets/list.py +60 -0
  81. nextmv/cli/cloud/secrets/update.py +147 -0
  82. nextmv/cli/cloud/shadow/__init__.py +33 -0
  83. nextmv/cli/cloud/shadow/create.py +184 -0
  84. nextmv/cli/cloud/shadow/delete.py +68 -0
  85. nextmv/cli/cloud/shadow/get.py +61 -0
  86. nextmv/cli/cloud/shadow/list.py +63 -0
  87. nextmv/cli/cloud/shadow/metadata.py +66 -0
  88. nextmv/cli/cloud/shadow/start.py +43 -0
  89. nextmv/cli/cloud/shadow/stop.py +43 -0
  90. nextmv/cli/cloud/shadow/update.py +95 -0
  91. nextmv/cli/cloud/upload/__init__.py +22 -0
  92. nextmv/cli/cloud/upload/create.py +39 -0
  93. nextmv/cli/cloud/version/__init__.py +33 -0
  94. nextmv/cli/cloud/version/create.py +97 -0
  95. nextmv/cli/cloud/version/delete.py +62 -0
  96. nextmv/cli/cloud/version/exists.py +39 -0
  97. nextmv/cli/cloud/version/get.py +62 -0
  98. nextmv/cli/cloud/version/list.py +60 -0
  99. nextmv/cli/cloud/version/update.py +92 -0
  100. nextmv/cli/community/__init__.py +24 -0
  101. nextmv/cli/community/clone.py +270 -0
  102. nextmv/cli/community/list.py +265 -0
  103. nextmv/cli/configuration/__init__.py +23 -0
  104. nextmv/cli/configuration/config.py +195 -0
  105. nextmv/cli/configuration/create.py +94 -0
  106. nextmv/cli/configuration/delete.py +67 -0
  107. nextmv/cli/configuration/list.py +77 -0
  108. nextmv/cli/main.py +188 -0
  109. nextmv/cli/message.py +153 -0
  110. nextmv/cli/options.py +206 -0
  111. nextmv/cli/version.py +38 -0
  112. nextmv/cloud/__init__.py +71 -17
  113. nextmv/cloud/acceptance_test.py +757 -51
  114. nextmv/cloud/account.py +406 -17
  115. nextmv/cloud/application/__init__.py +957 -0
  116. nextmv/cloud/application/_acceptance.py +419 -0
  117. nextmv/cloud/application/_batch_scenario.py +860 -0
  118. nextmv/cloud/application/_ensemble.py +251 -0
  119. nextmv/cloud/application/_input_set.py +227 -0
  120. nextmv/cloud/application/_instance.py +289 -0
  121. nextmv/cloud/application/_managed_input.py +227 -0
  122. nextmv/cloud/application/_run.py +1393 -0
  123. nextmv/cloud/application/_secrets.py +294 -0
  124. nextmv/cloud/application/_shadow.py +314 -0
  125. nextmv/cloud/application/_utils.py +54 -0
  126. nextmv/cloud/application/_version.py +303 -0
  127. nextmv/cloud/assets.py +48 -0
  128. nextmv/cloud/batch_experiment.py +294 -33
  129. nextmv/cloud/client.py +307 -66
  130. nextmv/cloud/ensemble.py +247 -0
  131. nextmv/cloud/input_set.py +120 -2
  132. nextmv/cloud/instance.py +133 -8
  133. nextmv/cloud/integration.py +533 -0
  134. nextmv/cloud/package.py +168 -53
  135. nextmv/cloud/scenario.py +410 -0
  136. nextmv/cloud/secrets.py +234 -0
  137. nextmv/cloud/shadow.py +190 -0
  138. nextmv/cloud/url.py +73 -0
  139. nextmv/cloud/version.py +132 -4
  140. nextmv/default_app/.gitignore +1 -0
  141. nextmv/default_app/README.md +32 -0
  142. nextmv/default_app/app.yaml +12 -0
  143. nextmv/default_app/input.json +5 -0
  144. nextmv/default_app/main.py +37 -0
  145. nextmv/default_app/requirements.txt +2 -0
  146. nextmv/default_app/src/__init__.py +0 -0
  147. nextmv/default_app/src/visuals.py +36 -0
  148. nextmv/deprecated.py +47 -0
  149. nextmv/input.py +861 -90
  150. nextmv/local/__init__.py +5 -0
  151. nextmv/local/application.py +1251 -0
  152. nextmv/local/executor.py +1042 -0
  153. nextmv/local/geojson_handler.py +323 -0
  154. nextmv/local/local.py +97 -0
  155. nextmv/local/plotly_handler.py +61 -0
  156. nextmv/local/runner.py +274 -0
  157. nextmv/logger.py +80 -9
  158. nextmv/manifest.py +1466 -0
  159. nextmv/model.py +241 -66
  160. nextmv/options.py +708 -115
  161. nextmv/output.py +1301 -274
  162. nextmv/polling.py +325 -0
  163. nextmv/run.py +1702 -0
  164. nextmv/safe.py +145 -0
  165. nextmv/status.py +122 -0
  166. nextmv-1.0.0.dev2.dist-info/METADATA +311 -0
  167. nextmv-1.0.0.dev2.dist-info/RECORD +170 -0
  168. {nextmv-0.18.0.dist-info → nextmv-1.0.0.dev2.dist-info}/WHEEL +1 -1
  169. nextmv-1.0.0.dev2.dist-info/entry_points.txt +2 -0
  170. nextmv/cloud/application.py +0 -1405
  171. nextmv/cloud/manifest.py +0 -234
  172. nextmv/cloud/status.py +0 -29
  173. nextmv-0.18.0.dist-info/METADATA +0 -770
  174. nextmv-0.18.0.dist-info/RECORD +0 -25
  175. {nextmv-0.18.0.dist-info → nextmv-1.0.0.dev2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,66 @@
1
+ """
2
+ This module defines the cloud batch metadata command for the Nextmv CLI.
3
+ """
4
+
5
+ import json
6
+ from typing import Annotated
7
+
8
+ import typer
9
+
10
+ from nextmv.cli.configuration.config import build_app
11
+ from nextmv.cli.message import in_progress, print_json, success
12
+ from nextmv.cli.options import AppIDOption, BatchExperimentIDOption, ProfileOption
13
+
14
+ # Set up subcommand application.
15
+ app = typer.Typer()
16
+
17
+
18
+ @app.command()
19
+ def metadata(
20
+ app_id: AppIDOption,
21
+ batch_experiment_id: BatchExperimentIDOption,
22
+ output: Annotated[
23
+ str | None,
24
+ typer.Option(
25
+ "--output",
26
+ "-o",
27
+ help="Saves the batch experiment metadata to this location.",
28
+ metavar="OUTPUT_PATH",
29
+ ),
30
+ ] = None,
31
+ profile: ProfileOption = None,
32
+ ) -> None:
33
+ """
34
+ Get metadata for a Nextmv Cloud batch experiment.
35
+
36
+ This command retrieves metadata for a specific batch experiment, including
37
+ status, creation date, and other high-level information without the full
38
+ run details.
39
+
40
+ [bold][underline]Examples[/underline][/bold]
41
+
42
+ - Get metadata for batch experiment [magenta]bunny-warren-optimization[/magenta] from application
43
+ [magenta]hare-app[/magenta].
44
+ $ [green]nextmv cloud batch metadata --app-id hare-app --batch-experiment-id bunny-warren-optimization[/green]
45
+
46
+ - Get metadata and save to a file.
47
+ $ [green]nextmv cloud batch metadata --app-id hare-app --batch-experiment-id lettuce-delivery \\
48
+ --output metadata.json[/green]
49
+
50
+ - Get metadata using a specific profile.
51
+ $ [green]nextmv cloud batch metadata --app-id hare-app --batch-experiment-id hop-schedule --profile prod[/green]
52
+ """
53
+
54
+ cloud_app = build_app(app_id=app_id, profile=profile)
55
+ in_progress(msg="Getting batch experiment metadata...")
56
+ batch_metadata = cloud_app.batch_experiment_metadata(batch_id=batch_experiment_id)
57
+ batch_metadata_dict = batch_metadata.to_dict()
58
+
59
+ if output is not None and output != "":
60
+ with open(output, "w") as f:
61
+ json.dump(batch_metadata_dict, f, indent=2)
62
+
63
+ success(msg=f"Batch experiment metadata saved to [magenta]{output}[/magenta].")
64
+ return
65
+
66
+ print_json(batch_metadata_dict)
@@ -0,0 +1,95 @@
1
+ """
2
+ This module defines the cloud batch update command for the Nextmv CLI.
3
+ """
4
+
5
+ import json
6
+ from typing import Annotated
7
+
8
+ import typer
9
+
10
+ from nextmv.cli.configuration.config import build_app
11
+ from nextmv.cli.message import in_progress, print_json, success
12
+ from nextmv.cli.options import AppIDOption, BatchExperimentIDOption, ProfileOption
13
+
14
+ # Set up subcommand application.
15
+ app = typer.Typer()
16
+
17
+
18
+ @app.command()
19
+ def update(
20
+ app_id: AppIDOption,
21
+ batch_experiment_id: BatchExperimentIDOption,
22
+ description: Annotated[
23
+ str | None,
24
+ typer.Option(
25
+ "--description",
26
+ "-d",
27
+ help="Updated description of the batch experiment.",
28
+ metavar="DESCRIPTION",
29
+ ),
30
+ ] = None,
31
+ name: Annotated[
32
+ str | None,
33
+ typer.Option(
34
+ "--name",
35
+ "-n",
36
+ help="Updated name of the batch experiment.",
37
+ metavar="NAME",
38
+ ),
39
+ ] = None,
40
+ output: Annotated[
41
+ str | None,
42
+ typer.Option(
43
+ "--output",
44
+ "-o",
45
+ help="Saves the updated batch experiment information to this location.",
46
+ metavar="OUTPUT_PATH",
47
+ ),
48
+ ] = None,
49
+ profile: ProfileOption = None,
50
+ ) -> None:
51
+ """
52
+ Update a Nextmv Cloud batch experiment.
53
+
54
+ Update the name and/or description of a batch experiment. Any fields not
55
+ specified will remain unchanged.
56
+
57
+ [bold][underline]Examples[/underline][/bold]
58
+
59
+ - Update the name of a batch experiment.
60
+ $ [green]nextmv cloud batch update --app-id hare-app --batch-experiment-id carrot-feast \\
61
+ --name "Spring Carrot Harvest"[/green]
62
+
63
+ - Update the description of a batch experiment.
64
+ $ [green]nextmv cloud batch update --app-id hare-app --batch-experiment-id bunny-hop-routes \\
65
+ --description "Optimizing hop paths through the meadow"[/green]
66
+
67
+ - Update both name and description and save the result.
68
+ $ [green]nextmv cloud batch update --app-id hare-app --batch-experiment-id lettuce-delivery \\
69
+ --name "Warren Lettuce Express" --description "Fast lettuce delivery to all burrows" \\
70
+ --output updated-batch.json[/green]
71
+ """
72
+
73
+ cloud_app = build_app(app_id=app_id, profile=profile)
74
+
75
+ in_progress(msg="Updating batch experiment...")
76
+ batch_experiment = cloud_app.update_batch_experiment(
77
+ batch_experiment_id=batch_experiment_id,
78
+ name=name,
79
+ description=description,
80
+ )
81
+
82
+ batch_experiment_dict = batch_experiment.to_dict()
83
+ success(
84
+ f"Batch experiment [magenta]{batch_experiment_id}[/magenta] updated successfully "
85
+ f"in application [magenta]{app_id}[/magenta]."
86
+ )
87
+
88
+ if output is not None and output != "":
89
+ with open(output, "w") as f:
90
+ json.dump(batch_experiment_dict, f, indent=2)
91
+
92
+ success(msg=f"Updated batch experiment information saved to [magenta]{output}[/magenta].")
93
+ return
94
+
95
+ print_json(batch_experiment_dict)
@@ -0,0 +1,26 @@
1
+ """
2
+ This module defines the cloud data command tree for the Nextmv CLI.
3
+ """
4
+
5
+ import typer
6
+
7
+ from nextmv.cli.cloud.data.upload import app as upload_app
8
+
9
+ # Set up subcommand application.
10
+ app = typer.Typer()
11
+ app.add_typer(upload_app)
12
+
13
+
14
+ @app.callback()
15
+ def callback() -> None:
16
+ """
17
+ Upload data for Nextmv Cloud application runs.
18
+
19
+ When data is too large (exceeds [magenta]5 MiB[/magenta]), or you are
20
+ working with the [magenta]multi-file[/magenta] content format, you can use
21
+ this command to upload information to Nextmv Cloud. Requires a pre-signed
22
+ upload URL, which can be obtained using the [code]nextmv cloud upload
23
+ create[/code] command. Use the [magenta].upload_url[/magenta] field from the
24
+ command output.
25
+ """
26
+ pass
@@ -0,0 +1,162 @@
1
+ """
2
+ This module defines the cloud data upload command for the Nextmv CLI.
3
+ """
4
+
5
+ import json
6
+ import sys
7
+ import tarfile
8
+ from pathlib import Path
9
+ from typing import Annotated, Any
10
+
11
+ import typer
12
+
13
+ from nextmv.cli.configuration.config import build_app
14
+ from nextmv.cli.message import error, in_progress, success
15
+ from nextmv.cli.options import AppIDOption, ProfileOption
16
+ from nextmv.cloud.application import Application
17
+
18
+ # Set up subcommand application.
19
+ app = typer.Typer()
20
+
21
+
22
+ @app.command()
23
+ def upload(
24
+ app_id: AppIDOption,
25
+ upload_url: Annotated[
26
+ str,
27
+ typer.Option(
28
+ "--upload-url",
29
+ "-u",
30
+ help="Pre-signed URL for uploading the data.",
31
+ metavar="UPLOAD_URL",
32
+ ),
33
+ ],
34
+ input: Annotated[
35
+ str | None,
36
+ typer.Option(
37
+ "--input",
38
+ "-i",
39
+ help="The input path to use. File or directory depending on content format. "
40
+ "Uses [magenta]stdin[/magenta] if not defined. "
41
+ "Can be a [magenta].tar.gz[/magenta] file for multi-file content format.",
42
+ metavar="INPUT_PATH",
43
+ ),
44
+ ] = None,
45
+ profile: ProfileOption = None,
46
+ ) -> None:
47
+ """
48
+ Upload data for Nextmv Cloud application runs.
49
+
50
+ When data is too large, or is not in a text-based content format, you can
51
+ use this command to upload information for a Nextmv Cloud application. Data
52
+ is used for starting new runs, tracking runs, performing experiments, and
53
+ more.
54
+
55
+ The [code]--upload-url[/code] flag is required to specify the pre-signed
56
+ upload URL. It can be obtained using the [code]nextmv cloud upload
57
+ create[/code] command. Use the [magenta].upload_url[/magenta] field from
58
+ the command output.
59
+
60
+ The data input should be given through [magenta]stdin[/magenta] or the
61
+ [code]--input[/code] flag. When using the [code]--input[/code] flag, the
62
+ value can be one of the following:
63
+
64
+ - [green]<FILE_PATH>[/green]: path to a [magenta]file[/magenta] containing
65
+ the data. Use with the [magenta]json[/magenta], and
66
+ [magenta]text[/magenta] content formats.
67
+ - [green]<DIR_PATH>[/green]: path to a [magenta]directory[/magenta]
68
+ containing data files. Use with the [magenta]multi-file[/magenta]
69
+ content format.
70
+ - [green]<.tar.gz_PATH>[/green]: path to a [magenta].tar.gz[/magenta] file
71
+ containing tarred data files. Use with the [magenta]multi-file[/magenta]
72
+ content format.
73
+
74
+ [bold][underline]Examples[/underline][/bold]
75
+
76
+ - Upload data from [magenta]stdin[/magenta] for application
77
+ [magenta]hare-app[/magenta].
78
+ $ [green]echo '{"key": "value"}' | nextmv cloud data upload --app-id hare-app --upload-url <URL>[/green]
79
+
80
+ - Upload data from a [magenta]JSON[/magenta] file.
81
+ $ [green]nextmv cloud data upload --app-id hare-app --upload-url <URL> --input data.json[/green]
82
+
83
+ - Upload data from a [magenta]text[/magenta] file.
84
+ $ [green]nextmv cloud data upload --app-id hare-app --upload-url <URL> --input data.txt[/green]
85
+
86
+ - Upload [magenta]multi-file[/magenta] data from a directory.
87
+ $ [green]nextmv cloud data upload --app-id hare-app --upload-url <URL> --input ./data_directory[/green]
88
+
89
+ - Upload [magenta]multi-file[/magenta] data from a
90
+ [magenta].tar.gz[/magenta] file.
91
+ $ [green]nextmv cloud data upload --app-id hare-app --upload-url <URL> --input data.tar.gz[/green]
92
+
93
+ - Upload data using a specific profile.
94
+ $ [green]nextmv cloud data upload --app-id hare-app --upload-url <URL> --input data.json \\
95
+ --profile production[/green]
96
+ """
97
+
98
+ # Validate that input is provided.
99
+ stdin = sys.stdin.read().strip() if sys.stdin.isatty() is False else None
100
+ if stdin is None and (input is None or input == ""):
101
+ error("Input data must be provided via the [code]--input[/code] flag or [magenta]stdin[/magenta].")
102
+
103
+ cloud_app = build_app(app_id=app_id, profile=profile)
104
+ data_kwarg = resolve_data_kwarg(
105
+ stdin=stdin,
106
+ input=input,
107
+ cloud_app=cloud_app,
108
+ )
109
+
110
+ in_progress(msg="Uploading data...")
111
+ cloud_app.upload_data(upload_url=upload_url, **data_kwarg)
112
+ success(msg="Data uploaded successfully.")
113
+
114
+
115
+ def resolve_data_kwarg(stdin: str | None, input: str | None, cloud_app: Application) -> dict[str, Any]:
116
+ """
117
+ Gets the keyword argument related to the data that is needed for the
118
+ upload. It handles stdin, file, and directory inputs.
119
+
120
+ Parameters
121
+ ----------
122
+ stdin : str | None
123
+ The stdin input data, if provided.
124
+ input : str | None
125
+ The input path, if provided.
126
+ cloud_app : Application
127
+ The Nextmv Cloud application instance.
128
+
129
+ Returns
130
+ -------
131
+ dict[str, Any]
132
+ The keyword argument with the resolved data.
133
+ """
134
+
135
+ if stdin is not None:
136
+ # Handle the case where stdin is provided as JSON for a JSON app.
137
+ try:
138
+ input_data = json.loads(stdin)
139
+ except json.JSONDecodeError:
140
+ input_data = stdin
141
+
142
+ return {"data": input_data}
143
+
144
+ input_path = Path(input)
145
+
146
+ # If the input is a file, we need to determine if it is a tar file or a
147
+ # regular file. If it is a regular file, we need to read its content.
148
+ if input_path.is_file():
149
+ if tarfile.is_tarfile(input_path):
150
+ return {"tar_file": str(input_path)}
151
+
152
+ input_data = input_path.read_text()
153
+
154
+ return {"data": input_data}
155
+
156
+ # If the input is a directory, we need to tar the contents.
157
+ if input_path.is_dir():
158
+ tar_path = cloud_app._package_inputs(dir_path=str(input_path))
159
+
160
+ return {"tar_file": tar_path}
161
+
162
+ error(f"Input path [magenta]{input}[/magenta] does not exist.")
@@ -0,0 +1,31 @@
1
+ """
2
+ This module defines the cloud ensemble command tree for the Nextmv CLI.
3
+ """
4
+
5
+ import typer
6
+
7
+ from nextmv.cli.cloud.ensemble.create import app as create_app
8
+ from nextmv.cli.cloud.ensemble.delete import app as delete_app
9
+ from nextmv.cli.cloud.ensemble.get import app as get_app
10
+ from nextmv.cli.cloud.ensemble.update import app as update_app
11
+
12
+ # Set up subcommand application.
13
+ app = typer.Typer()
14
+ app.add_typer(create_app)
15
+ app.add_typer(delete_app)
16
+ app.add_typer(get_app)
17
+ app.add_typer(update_app)
18
+
19
+
20
+ @app.callback()
21
+ def callback() -> None:
22
+ """
23
+ Create and manage Nextmv Cloud ensemble definitions.
24
+
25
+ An ensemble definition defines how to coordinate and execute multiple child
26
+ runs for an application, and how to determine the optimal result from those
27
+ runs. You can configure run groups to specify which instances to run on and
28
+ with what options, as well as evaluation rules to determine the best result
29
+ based on specified metrics.
30
+ """
31
+ pass