nextmv 0.39.0.dev1__py3-none-any.whl → 1.0.0__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.
- nextmv/__about__.py +1 -1
- nextmv/__entrypoint__.py +1 -2
- nextmv/__init__.py +2 -4
- nextmv/cli/CONTRIBUTING.md +583 -0
- nextmv/cli/cloud/__init__.py +49 -0
- nextmv/cli/cloud/acceptance/__init__.py +27 -0
- nextmv/cli/cloud/acceptance/create.py +391 -0
- nextmv/cli/cloud/acceptance/delete.py +64 -0
- nextmv/cli/cloud/acceptance/get.py +103 -0
- nextmv/cli/cloud/acceptance/list.py +62 -0
- nextmv/cli/cloud/acceptance/update.py +95 -0
- nextmv/cli/cloud/account/__init__.py +28 -0
- nextmv/cli/cloud/account/create.py +83 -0
- nextmv/cli/cloud/account/delete.py +59 -0
- nextmv/cli/cloud/account/get.py +66 -0
- nextmv/cli/cloud/account/update.py +70 -0
- nextmv/cli/cloud/app/__init__.py +35 -0
- nextmv/cli/cloud/app/create.py +140 -0
- nextmv/cli/cloud/app/delete.py +57 -0
- nextmv/cli/cloud/app/exists.py +44 -0
- nextmv/cli/cloud/app/get.py +66 -0
- nextmv/cli/cloud/app/list.py +61 -0
- nextmv/cli/cloud/app/push.py +432 -0
- nextmv/cli/cloud/app/update.py +124 -0
- nextmv/cli/cloud/batch/__init__.py +29 -0
- nextmv/cli/cloud/batch/create.py +452 -0
- nextmv/cli/cloud/batch/delete.py +64 -0
- nextmv/cli/cloud/batch/get.py +104 -0
- nextmv/cli/cloud/batch/list.py +63 -0
- nextmv/cli/cloud/batch/metadata.py +66 -0
- nextmv/cli/cloud/batch/update.py +95 -0
- nextmv/cli/cloud/data/__init__.py +26 -0
- nextmv/cli/cloud/data/upload.py +162 -0
- nextmv/cli/cloud/ensemble/__init__.py +33 -0
- nextmv/cli/cloud/ensemble/create.py +413 -0
- nextmv/cli/cloud/ensemble/delete.py +63 -0
- nextmv/cli/cloud/ensemble/get.py +65 -0
- nextmv/cli/cloud/ensemble/list.py +63 -0
- nextmv/cli/cloud/ensemble/update.py +103 -0
- nextmv/cli/cloud/input_set/__init__.py +32 -0
- nextmv/cli/cloud/input_set/create.py +168 -0
- nextmv/cli/cloud/input_set/delete.py +64 -0
- nextmv/cli/cloud/input_set/get.py +63 -0
- nextmv/cli/cloud/input_set/list.py +63 -0
- nextmv/cli/cloud/input_set/update.py +123 -0
- nextmv/cli/cloud/instance/__init__.py +35 -0
- nextmv/cli/cloud/instance/create.py +289 -0
- nextmv/cli/cloud/instance/delete.py +61 -0
- nextmv/cli/cloud/instance/exists.py +39 -0
- nextmv/cli/cloud/instance/get.py +62 -0
- nextmv/cli/cloud/instance/list.py +60 -0
- nextmv/cli/cloud/instance/update.py +216 -0
- nextmv/cli/cloud/managed_input/__init__.py +31 -0
- nextmv/cli/cloud/managed_input/create.py +144 -0
- nextmv/cli/cloud/managed_input/delete.py +64 -0
- nextmv/cli/cloud/managed_input/get.py +63 -0
- nextmv/cli/cloud/managed_input/list.py +60 -0
- nextmv/cli/cloud/managed_input/update.py +97 -0
- nextmv/cli/cloud/run/__init__.py +37 -0
- nextmv/cli/cloud/run/cancel.py +37 -0
- nextmv/cli/cloud/run/create.py +524 -0
- nextmv/cli/cloud/run/get.py +199 -0
- nextmv/cli/cloud/run/input.py +86 -0
- nextmv/cli/cloud/run/list.py +80 -0
- nextmv/cli/cloud/run/logs.py +166 -0
- nextmv/cli/cloud/run/metadata.py +67 -0
- nextmv/cli/cloud/run/track.py +500 -0
- nextmv/cli/cloud/scenario/__init__.py +29 -0
- nextmv/cli/cloud/scenario/create.py +451 -0
- nextmv/cli/cloud/scenario/delete.py +61 -0
- nextmv/cli/cloud/scenario/get.py +102 -0
- nextmv/cli/cloud/scenario/list.py +63 -0
- nextmv/cli/cloud/scenario/metadata.py +67 -0
- nextmv/cli/cloud/scenario/update.py +93 -0
- nextmv/cli/cloud/secrets/__init__.py +33 -0
- nextmv/cli/cloud/secrets/create.py +206 -0
- nextmv/cli/cloud/secrets/delete.py +63 -0
- nextmv/cli/cloud/secrets/get.py +66 -0
- nextmv/cli/cloud/secrets/list.py +60 -0
- nextmv/cli/cloud/secrets/update.py +144 -0
- nextmv/cli/cloud/shadow/__init__.py +33 -0
- nextmv/cli/cloud/shadow/create.py +184 -0
- nextmv/cli/cloud/shadow/delete.py +64 -0
- nextmv/cli/cloud/shadow/get.py +61 -0
- nextmv/cli/cloud/shadow/list.py +63 -0
- nextmv/cli/cloud/shadow/metadata.py +66 -0
- nextmv/cli/cloud/shadow/start.py +43 -0
- nextmv/cli/cloud/shadow/stop.py +53 -0
- nextmv/cli/cloud/shadow/update.py +96 -0
- nextmv/cli/cloud/switchback/__init__.py +33 -0
- nextmv/cli/cloud/switchback/create.py +151 -0
- nextmv/cli/cloud/switchback/delete.py +64 -0
- nextmv/cli/cloud/switchback/get.py +62 -0
- nextmv/cli/cloud/switchback/list.py +63 -0
- nextmv/cli/cloud/switchback/metadata.py +68 -0
- nextmv/cli/cloud/switchback/start.py +43 -0
- nextmv/cli/cloud/switchback/stop.py +53 -0
- nextmv/cli/cloud/switchback/update.py +96 -0
- nextmv/cli/cloud/upload/__init__.py +22 -0
- nextmv/cli/cloud/upload/create.py +39 -0
- nextmv/cli/cloud/version/__init__.py +33 -0
- nextmv/cli/cloud/version/create.py +96 -0
- nextmv/cli/cloud/version/delete.py +61 -0
- nextmv/cli/cloud/version/exists.py +39 -0
- nextmv/cli/cloud/version/get.py +62 -0
- nextmv/cli/cloud/version/list.py +60 -0
- nextmv/cli/cloud/version/update.py +92 -0
- nextmv/cli/community/__init__.py +24 -0
- nextmv/cli/community/clone.py +86 -0
- nextmv/cli/community/list.py +200 -0
- nextmv/cli/configuration/__init__.py +23 -0
- nextmv/cli/configuration/config.py +228 -0
- nextmv/cli/configuration/create.py +94 -0
- nextmv/cli/configuration/delete.py +67 -0
- nextmv/cli/configuration/list.py +77 -0
- nextmv/cli/confirm.py +34 -0
- nextmv/cli/main.py +161 -3
- nextmv/cli/message.py +170 -0
- nextmv/cli/options.py +220 -0
- nextmv/cli/version.py +22 -2
- nextmv/cloud/__init__.py +17 -38
- nextmv/cloud/acceptance_test.py +20 -83
- nextmv/cloud/account.py +269 -30
- nextmv/cloud/application/__init__.py +898 -0
- nextmv/cloud/application/_acceptance.py +424 -0
- nextmv/cloud/application/_batch_scenario.py +845 -0
- nextmv/cloud/application/_ensemble.py +251 -0
- nextmv/cloud/application/_input_set.py +263 -0
- nextmv/cloud/application/_instance.py +289 -0
- nextmv/cloud/application/_managed_input.py +227 -0
- nextmv/cloud/application/_run.py +1393 -0
- nextmv/cloud/application/_secrets.py +294 -0
- nextmv/cloud/application/_shadow.py +320 -0
- nextmv/cloud/application/_switchback.py +332 -0
- nextmv/cloud/application/_utils.py +54 -0
- nextmv/cloud/application/_version.py +304 -0
- nextmv/cloud/batch_experiment.py +6 -2
- nextmv/cloud/community.py +446 -0
- nextmv/cloud/instance.py +11 -1
- nextmv/cloud/integration.py +8 -5
- nextmv/cloud/package.py +50 -9
- nextmv/cloud/shadow.py +254 -0
- nextmv/cloud/switchback.py +228 -0
- nextmv/deprecated.py +5 -3
- nextmv/input.py +20 -88
- nextmv/local/application.py +3 -15
- nextmv/local/runner.py +1 -1
- nextmv/model.py +50 -11
- nextmv/options.py +11 -256
- nextmv/output.py +0 -62
- nextmv/polling.py +54 -16
- nextmv/run.py +84 -37
- nextmv/status.py +1 -51
- {nextmv-0.39.0.dev1.dist-info → nextmv-1.0.0.dist-info}/METADATA +37 -11
- nextmv-1.0.0.dist-info/RECORD +185 -0
- nextmv-1.0.0.dist-info/entry_points.txt +2 -0
- nextmv/cloud/application.py +0 -4204
- nextmv-0.39.0.dev1.dist-info/RECORD +0 -55
- nextmv-0.39.0.dev1.dist-info/entry_points.txt +0 -2
- {nextmv-0.39.0.dev1.dist-info → nextmv-1.0.0.dist-info}/WHEEL +0 -0
- {nextmv-0.39.0.dev1.dist-info → nextmv-1.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines the cloud run get 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, ProfileOption, RunIDOption
|
|
13
|
+
from nextmv.cloud.application import Application
|
|
14
|
+
from nextmv.output import OutputFormat
|
|
15
|
+
from nextmv.polling import PollingOptions, default_polling_options
|
|
16
|
+
|
|
17
|
+
# Set up subcommand application.
|
|
18
|
+
app = typer.Typer()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@app.command()
|
|
22
|
+
def get(
|
|
23
|
+
app_id: AppIDOption,
|
|
24
|
+
run_id: RunIDOption,
|
|
25
|
+
output: Annotated[
|
|
26
|
+
str | None,
|
|
27
|
+
typer.Option(
|
|
28
|
+
"--output",
|
|
29
|
+
"-o",
|
|
30
|
+
help="Waits for the run to complete and save the output to this location. "
|
|
31
|
+
"A file or directory will be created depending on content format.",
|
|
32
|
+
metavar="OUTPUT_PATH",
|
|
33
|
+
),
|
|
34
|
+
] = None,
|
|
35
|
+
timeout: Annotated[
|
|
36
|
+
int,
|
|
37
|
+
typer.Option(
|
|
38
|
+
help="The maximum time in seconds to wait for results when polling. Poll indefinitely if not set.",
|
|
39
|
+
metavar="TIMEOUT_SECONDS",
|
|
40
|
+
),
|
|
41
|
+
] = -1,
|
|
42
|
+
wait: Annotated[
|
|
43
|
+
bool,
|
|
44
|
+
typer.Option(
|
|
45
|
+
"--wait",
|
|
46
|
+
"-w",
|
|
47
|
+
help="Wait for the run to complete. Run result is printed to [magenta]stdout[/magenta] for "
|
|
48
|
+
"[magenta]json[/magenta], to a dir for [magenta]multi-file[/magenta]. "
|
|
49
|
+
"Specify output location with --output.",
|
|
50
|
+
),
|
|
51
|
+
] = False,
|
|
52
|
+
profile: ProfileOption = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Get the result (output) of a Nextmv Cloud application run.
|
|
56
|
+
|
|
57
|
+
Use the --wait flag to wait for the run to complete, polling
|
|
58
|
+
for results. Using the --output flag will also activate
|
|
59
|
+
waiting, and allows you to specify a destination (file or dir) for the
|
|
60
|
+
output, depending on the content type.
|
|
61
|
+
|
|
62
|
+
[bold][underline]Examples[/underline][/bold]
|
|
63
|
+
|
|
64
|
+
- Get the results of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
65
|
+
[magenta]hare-app[/magenta].
|
|
66
|
+
$ [dim]nextmv cloud run get --app-id hare-app --run-id burrow-123[/dim]
|
|
67
|
+
|
|
68
|
+
- Get the results of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
69
|
+
[magenta]hare-app[/magenta]. Wait for the run to complete if necessary.
|
|
70
|
+
$ [dim]nextmv cloud run get --app-id hare-app --run-id burrow-123 --wait[/dim]
|
|
71
|
+
|
|
72
|
+
- Get the results of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
73
|
+
[magenta]hare-app[/magenta]. The app is a [magenta]json[/magenta] app.
|
|
74
|
+
Save the results to a [magenta]results.json[/magenta] file.
|
|
75
|
+
$ [dim]nextmv cloud run get --app-id hare-app --run-id burrow-123 --output results.json[/dim]
|
|
76
|
+
|
|
77
|
+
- Get the results of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
78
|
+
[magenta]hare-app[/magenta]. The app is a [magenta]multi-file[/magenta] app.
|
|
79
|
+
Save the results to the [magenta]results[/magenta] dir.
|
|
80
|
+
$ [dim]nextmv cloud run get --app-id hare-app --run-id burrow-123 --output results[/dim]
|
|
81
|
+
|
|
82
|
+
- Get the results of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
83
|
+
[magenta]hare-app[/magenta]. Use the profile named [magenta]hare[/magenta].
|
|
84
|
+
$ [dim]nextmv cloud run get --app-id hare-app --run-id burrow-123 --profile hare[/dim]
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
88
|
+
|
|
89
|
+
# Build the polling options.
|
|
90
|
+
polling_options = default_polling_options()
|
|
91
|
+
polling_options.max_duration = timeout
|
|
92
|
+
|
|
93
|
+
handle_outputs(
|
|
94
|
+
cloud_app=cloud_app,
|
|
95
|
+
run_id=run_id,
|
|
96
|
+
wait=wait,
|
|
97
|
+
output=output,
|
|
98
|
+
polling_options=polling_options,
|
|
99
|
+
skip_wait_check=True,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def handle_outputs(
|
|
104
|
+
cloud_app: Application,
|
|
105
|
+
run_id: str,
|
|
106
|
+
wait: bool,
|
|
107
|
+
output: str | None,
|
|
108
|
+
polling_options: PollingOptions,
|
|
109
|
+
skip_wait_check: bool = False,
|
|
110
|
+
) -> None:
|
|
111
|
+
"""
|
|
112
|
+
Handle retrieving and outputting the results from a run.
|
|
113
|
+
|
|
114
|
+
If ``wait`` is False and ``output`` is not specified, this function returns
|
|
115
|
+
early without doing anything. Otherwise, results are retrieved using
|
|
116
|
+
polling (since the run may not yet be complete) and output accordingly.
|
|
117
|
+
|
|
118
|
+
The output behavior depends on the content type:
|
|
119
|
+
|
|
120
|
+
- **JSON/TEXT**: If ``output`` is specified, writes to the given file path.
|
|
121
|
+
Otherwise, prints to stdout.
|
|
122
|
+
- **MULTI_FILE/CSV_ARCHIVE**: Downloads files to a directory. If ``output``
|
|
123
|
+
is specified, uses that as the directory name. Otherwise, uses the
|
|
124
|
+
``run_id`` as the directory name.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
cloud_app : Application
|
|
129
|
+
The cloud application instance used to interact with the Nextmv Cloud
|
|
130
|
+
API.
|
|
131
|
+
run_id : str
|
|
132
|
+
The unique identifier of the run to retrieve results for.
|
|
133
|
+
wait : bool
|
|
134
|
+
Whether to wait for the run to complete. If False and ``output`` is not
|
|
135
|
+
specified, the function returns early without retrieving results.
|
|
136
|
+
output : str | None
|
|
137
|
+
The location to write the output. For JSON/TEXT formats, this is a file
|
|
138
|
+
path. For MULTI_FILE/CSV_ARCHIVE formats, this is a directory path. If
|
|
139
|
+
None, JSON/TEXT output is printed to stdout and MULTI_FILE/CSV_ARCHIVE
|
|
140
|
+
output uses the ``run_id`` as the directory name.
|
|
141
|
+
polling_options : PollingOptions
|
|
142
|
+
Configuration options for polling behavior, including timeout and
|
|
143
|
+
interval settings.
|
|
144
|
+
skip_wait_check : bool, optional
|
|
145
|
+
If True, skips the early return check when both `wait` is False and
|
|
146
|
+
`output` is not specified. Default is False.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
# If we don't need to wait, no output is specified, and we're not skipping
|
|
150
|
+
# the wait check, return early.
|
|
151
|
+
if not wait and (output is None or output == "") and not skip_wait_check:
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
# Get the run metadata to determine how to operate with the output.
|
|
155
|
+
run_info = cloud_app.run_metadata(run_id=run_id)
|
|
156
|
+
content_format = run_info.metadata.format.format_output.output_type
|
|
157
|
+
|
|
158
|
+
# Build kwargs for the result retrieval.
|
|
159
|
+
kwargs = {"run_id": run_id}
|
|
160
|
+
|
|
161
|
+
# For MULTI_FILE and CSV_ARCHIVE, we need output_dir_path.
|
|
162
|
+
if content_format not in {OutputFormat.JSON, OutputFormat.TEXT}:
|
|
163
|
+
output_dir = f"{run_id}-output" if output is None or output == "" else output
|
|
164
|
+
kwargs["output_dir_path"] = output_dir
|
|
165
|
+
|
|
166
|
+
# Always poll for results since we can't guarantee the run is done.
|
|
167
|
+
# If the run is already complete, polling returns immediately.
|
|
168
|
+
in_progress(msg="Getting run results...")
|
|
169
|
+
wait = wait or (output is not None and output != "")
|
|
170
|
+
if wait:
|
|
171
|
+
kwargs["polling_options"] = polling_options
|
|
172
|
+
run_result = cloud_app.run_result_with_polling(**kwargs)
|
|
173
|
+
else:
|
|
174
|
+
run_result = cloud_app.run_result(**kwargs)
|
|
175
|
+
|
|
176
|
+
# Handle the case where output is embedded directly in the result: json and text.
|
|
177
|
+
if content_format in {OutputFormat.JSON, OutputFormat.TEXT}:
|
|
178
|
+
if output is None or output == "":
|
|
179
|
+
print_json(run_result.to_dict())
|
|
180
|
+
else:
|
|
181
|
+
with open(output, "w") as f:
|
|
182
|
+
json.dump(run_result.to_dict(), f, indent=2)
|
|
183
|
+
|
|
184
|
+
success(f"Run output written to [magenta]{output}[/magenta].")
|
|
185
|
+
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
# At this point, we know that the output is multi-file or csv-archive.
|
|
189
|
+
result_dict = run_result.to_dict()
|
|
190
|
+
if "output" in result_dict and run_result.metadata.run_is_finalized():
|
|
191
|
+
del result_dict["output"]
|
|
192
|
+
success(f"Run outputs downloaded to [magenta]{output_dir}[/magenta]. Here is the metadata.")
|
|
193
|
+
else:
|
|
194
|
+
success(
|
|
195
|
+
f"Run is not finalized (status: [magenta]{run_result.metadata.status_v2.value}[/magenta]). "
|
|
196
|
+
"Here is the metadata."
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
print_json(result_dict)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines the cloud run input 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, ProfileOption, RunIDOption
|
|
13
|
+
from nextmv.output import OutputFormat
|
|
14
|
+
|
|
15
|
+
# Set up subcommand application.
|
|
16
|
+
app = typer.Typer()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@app.command()
|
|
20
|
+
def input(
|
|
21
|
+
app_id: AppIDOption,
|
|
22
|
+
run_id: RunIDOption,
|
|
23
|
+
output: Annotated[
|
|
24
|
+
str | None,
|
|
25
|
+
typer.Option(
|
|
26
|
+
"--output",
|
|
27
|
+
"-o",
|
|
28
|
+
help="Saves the input to this location.",
|
|
29
|
+
metavar="OUTPUT_PATH",
|
|
30
|
+
),
|
|
31
|
+
] = None,
|
|
32
|
+
profile: ProfileOption = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Get the input of a Nextmv Cloud application run.
|
|
36
|
+
|
|
37
|
+
By default, the input is fetched and printed to [magenta]stdout[/magenta].
|
|
38
|
+
Use the --output flag to save the input to a file.
|
|
39
|
+
|
|
40
|
+
[bold][underline]Examples[/underline][/bold]
|
|
41
|
+
|
|
42
|
+
- Get the input of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
43
|
+
[magenta]hare-app[/magenta]. Input is printed to [magenta]stdout[/magenta].
|
|
44
|
+
$ [dim]nextmv cloud run input --app-id hare-app --run-id burrow-123[/dim]
|
|
45
|
+
|
|
46
|
+
- Get the input of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
47
|
+
[magenta]hare-app[/magenta]. Save the input to a [magenta]input.json[/magenta] file.
|
|
48
|
+
$ [dim]nextmv cloud run input --app-id hare-app --run-id burrow-123 --output input.json[/dim]
|
|
49
|
+
|
|
50
|
+
- Get the input of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
51
|
+
[magenta]hare-app[/magenta]. Use the profile named [magenta]hare[/magenta].
|
|
52
|
+
$ [dim]nextmv cloud run input --app-id hare-app --run-id burrow-123 --profile hare[/dim]
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
56
|
+
in_progress(msg="Getting run input...")
|
|
57
|
+
|
|
58
|
+
# First get the content type to check what we should do with the input,
|
|
59
|
+
# based on its format.
|
|
60
|
+
run_info = cloud_app.run_metadata(run_id)
|
|
61
|
+
|
|
62
|
+
# If the input is multi-file, we need to provide an `output_dir_path` to
|
|
63
|
+
# save the files to.
|
|
64
|
+
if run_info.metadata.format.format_input.input_type not in {OutputFormat.JSON, OutputFormat.TEXT}:
|
|
65
|
+
# If no output path is provided, use the run ID as the directory name.
|
|
66
|
+
output = f"{run_id}-input" if output is None or output == "" else output
|
|
67
|
+
cloud_app.run_input(run_id=run_id, output_dir_path=output)
|
|
68
|
+
success(msg=f"Run input saved to [magenta]{output}[/magenta].")
|
|
69
|
+
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
# At this point, we know the input is JSON or text, so we can fetch it
|
|
73
|
+
# normally. The method internally will take care of large inputs.
|
|
74
|
+
run_input = cloud_app.run_input(run_id=run_id)
|
|
75
|
+
|
|
76
|
+
# If an output path is provided, save the input to that file.
|
|
77
|
+
if output is not None and output != "":
|
|
78
|
+
with open(output, "w") as f:
|
|
79
|
+
json.dump(run_input, f, indent=2)
|
|
80
|
+
|
|
81
|
+
success(msg=f"Run input saved to [magenta]{output}[/magenta].")
|
|
82
|
+
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
# Otherwise, print the input to stdout.
|
|
86
|
+
print_json(data=run_input)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines the cloud run list 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 enum_values, in_progress, print_json, success
|
|
12
|
+
from nextmv.cli.options import AppIDOption, ProfileOption
|
|
13
|
+
from nextmv.status import StatusV2
|
|
14
|
+
|
|
15
|
+
# Set up subcommand application.
|
|
16
|
+
app = typer.Typer()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@app.command()
|
|
20
|
+
def list(
|
|
21
|
+
app_id: AppIDOption,
|
|
22
|
+
output: Annotated[
|
|
23
|
+
str | None,
|
|
24
|
+
typer.Option(
|
|
25
|
+
"--output",
|
|
26
|
+
"-o",
|
|
27
|
+
help="Saves the list of runs to this location.",
|
|
28
|
+
metavar="OUTPUT_PATH",
|
|
29
|
+
),
|
|
30
|
+
] = None,
|
|
31
|
+
status: Annotated[
|
|
32
|
+
StatusV2 | None,
|
|
33
|
+
typer.Option(
|
|
34
|
+
"--status",
|
|
35
|
+
"-s",
|
|
36
|
+
help=f"Filter runs by their status. Allowed values are: {enum_values(StatusV2)}.",
|
|
37
|
+
metavar="STATUS",
|
|
38
|
+
),
|
|
39
|
+
] = None,
|
|
40
|
+
profile: ProfileOption = None,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Get the list of runs for a Nextmv Cloud application.
|
|
44
|
+
|
|
45
|
+
By default, the list of runs is fetched and printed to [magenta]stdout[/magenta].
|
|
46
|
+
Use the --output flag to save the list to a file.
|
|
47
|
+
|
|
48
|
+
You can use the optional --status flag to filter runs by their status.
|
|
49
|
+
|
|
50
|
+
[bold][underline]Examples[/underline][/bold]
|
|
51
|
+
|
|
52
|
+
- Get the list of runs for an app with ID [magenta]hare-app[/magenta]. List is printed to [magenta]stdout[/magenta].
|
|
53
|
+
$ [dim]nextmv cloud run list --app-id hare-app[/dim]
|
|
54
|
+
|
|
55
|
+
- Get the list of runs for an app with ID [magenta]hare-app[/magenta]. Save the list to a
|
|
56
|
+
[magenta]runs.json[/magenta] file.
|
|
57
|
+
$ [dim]nextmv cloud run list --app-id hare-app --output runs.json[/dim]
|
|
58
|
+
|
|
59
|
+
- Get the list of runs for an app with ID [magenta]hare-app[/magenta].
|
|
60
|
+
Use the profile named [magenta]hare[/magenta].
|
|
61
|
+
$ [dim]nextmv cloud run list --app-id hare-app --profile hare[/dim]
|
|
62
|
+
|
|
63
|
+
- Get the list of [magenta]queued[/magenta] runs for an app with ID [magenta]hare-app[/magenta].
|
|
64
|
+
$ [dim]nextmv cloud run list --app-id hare-app --status queued[/dim]
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
68
|
+
in_progress(msg="Listing app runs...")
|
|
69
|
+
runs = cloud_app.list_runs(status=status)
|
|
70
|
+
runs_dicts = [run.to_dict() for run in runs]
|
|
71
|
+
|
|
72
|
+
if output is not None and output != "":
|
|
73
|
+
with open(output, "w") as f:
|
|
74
|
+
json.dump(runs_dicts, f, indent=2)
|
|
75
|
+
|
|
76
|
+
success(msg=f"Run list saved to [magenta]{output}[/magenta].")
|
|
77
|
+
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
print_json(runs_dicts)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines the cloud run logs command for the Nextmv CLI.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
import rich
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
from nextmv.cli.configuration.config import build_app
|
|
13
|
+
from nextmv.cli.message import in_progress, success
|
|
14
|
+
from nextmv.cli.options import AppIDOption, ProfileOption, RunIDOption
|
|
15
|
+
from nextmv.cloud.application import Application
|
|
16
|
+
from nextmv.polling import PollingOptions, default_polling_options
|
|
17
|
+
|
|
18
|
+
# Set up subcommand application.
|
|
19
|
+
app = typer.Typer()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.command()
|
|
23
|
+
def logs(
|
|
24
|
+
app_id: AppIDOption,
|
|
25
|
+
run_id: RunIDOption,
|
|
26
|
+
output: Annotated[
|
|
27
|
+
str | None,
|
|
28
|
+
typer.Option(
|
|
29
|
+
"--output",
|
|
30
|
+
"-o",
|
|
31
|
+
help="Waits for the run to complete and saves the logs to this location.",
|
|
32
|
+
metavar="OUTPUT_PATH",
|
|
33
|
+
),
|
|
34
|
+
] = None,
|
|
35
|
+
tail: Annotated[
|
|
36
|
+
bool,
|
|
37
|
+
typer.Option(
|
|
38
|
+
"--tail",
|
|
39
|
+
"-t",
|
|
40
|
+
help="Tail the logs until the run completes. Logs are streamed to [magenta]stderr[/magenta]. "
|
|
41
|
+
"Specify log output location with --output.",
|
|
42
|
+
),
|
|
43
|
+
] = False,
|
|
44
|
+
timeout: Annotated[
|
|
45
|
+
int,
|
|
46
|
+
typer.Option(
|
|
47
|
+
help="The maximum time in seconds to wait for results when polling. Poll indefinitely if not set.",
|
|
48
|
+
metavar="TIMEOUT_SECONDS",
|
|
49
|
+
),
|
|
50
|
+
] = -1,
|
|
51
|
+
profile: ProfileOption = None,
|
|
52
|
+
) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Get the logs of a Nextmv Cloud application run.
|
|
55
|
+
|
|
56
|
+
By default, the logs are fetched and printed to [magenta]stderr[/magenta].
|
|
57
|
+
Use the --tail flag to stream logs to [magenta]stderr[/magenta] until the
|
|
58
|
+
run completes. Using the --output flag will also activate waiting, and
|
|
59
|
+
allows you to specify a file to write the logs to.
|
|
60
|
+
|
|
61
|
+
[bold][underline]Examples[/underline][/bold]
|
|
62
|
+
|
|
63
|
+
- Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
64
|
+
[magenta]hare-app[/magenta]. Logs are printed to [magenta]stderr[/magenta].
|
|
65
|
+
$ [dim]nextmv cloud run logs --app-id hare-app --run-id burrow-123[/dim]
|
|
66
|
+
|
|
67
|
+
- Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
68
|
+
[magenta]hare-app[/magenta]. Tail the logs until the run completes.
|
|
69
|
+
$ [dim]nextmv cloud run logs --app-id hare-app --run-id burrow-123 --tail[/dim]
|
|
70
|
+
|
|
71
|
+
- Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
72
|
+
[magenta]hare-app[/magenta]. Save the logs to a [magenta]logs.log[/magenta] file.
|
|
73
|
+
$ [dim]nextmv cloud run logs --app-id hare-app --run-id burrow-123 --output logs.log[/dim]
|
|
74
|
+
|
|
75
|
+
- Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
76
|
+
[magenta]hare-app[/magenta]. Tail the logs and save them to a [magenta]logs.log[/magenta] file.
|
|
77
|
+
$ [dim]nextmv cloud run logs --app-id hare-app --run-id burrow-123 --tail --output logs.log[/dim]
|
|
78
|
+
|
|
79
|
+
- Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
80
|
+
[magenta]hare-app[/magenta]. Use the profile named [magenta]hare[/magenta].
|
|
81
|
+
$ [dim]nextmv cloud run logs --app-id hare-app --run-id burrow-123 --profile hare[/dim]
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
85
|
+
|
|
86
|
+
# Build the polling options.
|
|
87
|
+
polling_options = default_polling_options()
|
|
88
|
+
polling_options.max_duration = timeout
|
|
89
|
+
|
|
90
|
+
handle_logs(
|
|
91
|
+
cloud_app=cloud_app,
|
|
92
|
+
run_id=run_id,
|
|
93
|
+
tail=tail,
|
|
94
|
+
logs=output,
|
|
95
|
+
polling_options=polling_options,
|
|
96
|
+
file_output=output is not None,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def handle_logs(
|
|
101
|
+
cloud_app: Application,
|
|
102
|
+
run_id: str,
|
|
103
|
+
tail: bool,
|
|
104
|
+
logs: str | None,
|
|
105
|
+
polling_options: PollingOptions,
|
|
106
|
+
file_output: bool,
|
|
107
|
+
) -> None:
|
|
108
|
+
"""
|
|
109
|
+
Handle retrieving and outputting logs from a run.
|
|
110
|
+
|
|
111
|
+
If neither `tail` is True nor `logs` is specified, this function
|
|
112
|
+
returns early without doing anything. Otherwise, logs are retrieved and
|
|
113
|
+
optionally written to a file.
|
|
114
|
+
|
|
115
|
+
When `tail` is True, logs are streamed in real-time to stderr as the run
|
|
116
|
+
executes. When `logs` is specified (without tailing), the function waits
|
|
117
|
+
for the run to complete and then fetches all logs at once. In both cases,
|
|
118
|
+
if a `logs` file path is provided, the logs are persisted to that file.
|
|
119
|
+
|
|
120
|
+
Parameters
|
|
121
|
+
----------
|
|
122
|
+
cloud_app : Application
|
|
123
|
+
The cloud application instance used to interact with the Nextmv Cloud
|
|
124
|
+
API.
|
|
125
|
+
run_id : str
|
|
126
|
+
The unique identifier of the run to retrieve logs for.
|
|
127
|
+
tail : bool
|
|
128
|
+
If True, streams logs in real-time to stderr as the run executes.
|
|
129
|
+
logs : str | None
|
|
130
|
+
The file path where logs should be written. If None, logs are only
|
|
131
|
+
displayed to stderr (when tailing) and not persisted to a file.
|
|
132
|
+
polling_options : PollingOptions
|
|
133
|
+
Configuration options for polling behavior, including timeout and
|
|
134
|
+
interval settings.
|
|
135
|
+
file_output : bool
|
|
136
|
+
Indicates whether logs should be written to a file. If False, logs are
|
|
137
|
+
only printed to stderr, no matter the status of the run.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
if tail:
|
|
141
|
+
in_progress(msg="Tailing logs...")
|
|
142
|
+
fetched_logs = cloud_app.run_logs_with_polling(
|
|
143
|
+
run_id=run_id,
|
|
144
|
+
polling_options=polling_options,
|
|
145
|
+
verbose=True,
|
|
146
|
+
rich_print=True,
|
|
147
|
+
)
|
|
148
|
+
if logs is None:
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
log_content = "".join(log_entry.log for log_entry in fetched_logs)
|
|
152
|
+
elif logs is not None and logs != "" and file_output:
|
|
153
|
+
in_progress(msg="Getting run logs...")
|
|
154
|
+
cloud_app.run_result_with_polling(run_id=run_id, polling_options=polling_options)
|
|
155
|
+
run_logs = cloud_app.run_logs(run_id=run_id)
|
|
156
|
+
log_content = run_logs.log
|
|
157
|
+
elif not file_output:
|
|
158
|
+
in_progress(msg="Getting run logs...")
|
|
159
|
+
run_logs = cloud_app.run_logs(run_id=run_id)
|
|
160
|
+
rich.print(run_logs.log, file=sys.stderr)
|
|
161
|
+
return
|
|
162
|
+
else:
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
Path(logs).write_text(log_content)
|
|
166
|
+
success(f"Run logs written to [magenta]{logs}[/magenta].")
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines the cloud run 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, ProfileOption, RunIDOption
|
|
13
|
+
|
|
14
|
+
# Set up subcommand application.
|
|
15
|
+
app = typer.Typer()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.command()
|
|
19
|
+
def metadata(
|
|
20
|
+
app_id: AppIDOption,
|
|
21
|
+
run_id: RunIDOption,
|
|
22
|
+
output: Annotated[
|
|
23
|
+
str | None,
|
|
24
|
+
typer.Option(
|
|
25
|
+
"--output",
|
|
26
|
+
"-o",
|
|
27
|
+
help="Saves the metadata to this location.",
|
|
28
|
+
metavar="OUTPUT_PATH",
|
|
29
|
+
),
|
|
30
|
+
] = None,
|
|
31
|
+
profile: ProfileOption = None,
|
|
32
|
+
) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Get the metadata of a Nextmv Cloud application run.
|
|
35
|
+
|
|
36
|
+
By default, the metadata is fetched and printed to [magenta]stdout[/magenta].
|
|
37
|
+
Use the --output flag to save the metadata to a file.
|
|
38
|
+
|
|
39
|
+
[bold][underline]Examples[/underline][/bold]
|
|
40
|
+
|
|
41
|
+
- Get the metadata of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
42
|
+
[magenta]hare-app[/magenta]. Metadata is printed to [magenta]stdout[/magenta].
|
|
43
|
+
$ [dim]nextmv cloud run metadata --app-id hare-app --run-id burrow-123[/dim]
|
|
44
|
+
|
|
45
|
+
- Get the metadata of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
46
|
+
[magenta]hare-app[/magenta]. Save the metadata to a [magenta]metadata.json[/magenta] file.
|
|
47
|
+
$ [dim]nextmv cloud run metadata --app-id hare-app --run-id burrow-123 --output metadata.json[/dim]
|
|
48
|
+
|
|
49
|
+
- Get the metadata of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
|
|
50
|
+
[magenta]hare-app[/magenta]. Use the profile named [magenta]hare[/magenta].
|
|
51
|
+
$ [dim]nextmv cloud run metadata --app-id hare-app --run-id burrow-123 --profile hare[/dim]
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
55
|
+
in_progress(msg="Getting run metadata...")
|
|
56
|
+
run_info = cloud_app.run_metadata(run_id)
|
|
57
|
+
info_dict = run_info.to_dict()
|
|
58
|
+
|
|
59
|
+
if output is not None and output != "":
|
|
60
|
+
with open(output, "w") as f:
|
|
61
|
+
json.dump(info_dict, f, indent=2)
|
|
62
|
+
|
|
63
|
+
success(msg=f"Run metadata saved to [magenta]{output}[/magenta].")
|
|
64
|
+
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
print_json(info_dict)
|