nextmv 1.0.0__py3-none-any.whl → 1.0.0.dev0__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 +2 -1
- nextmv/__init__.py +4 -0
- nextmv/cli/CONTRIBUTING.md +40 -112
- nextmv/cli/cloud/__init__.py +0 -4
- nextmv/cli/cloud/acceptance/create.py +22 -20
- nextmv/cli/cloud/acceptance/delete.py +12 -8
- nextmv/cli/cloud/acceptance/get.py +10 -9
- nextmv/cli/cloud/acceptance/list.py +3 -3
- nextmv/cli/cloud/acceptance/update.py +6 -6
- nextmv/cli/cloud/account/__init__.py +3 -3
- nextmv/cli/cloud/account/create.py +11 -11
- nextmv/cli/cloud/account/delete.py +8 -7
- nextmv/cli/cloud/account/get.py +3 -3
- nextmv/cli/cloud/account/update.py +5 -5
- nextmv/cli/cloud/app/create.py +26 -25
- nextmv/cli/cloud/app/delete.py +7 -6
- nextmv/cli/cloud/app/exists.py +2 -2
- nextmv/cli/cloud/app/get.py +2 -2
- nextmv/cli/cloud/app/list.py +3 -3
- nextmv/cli/cloud/app/push.py +54 -349
- nextmv/cli/cloud/app/update.py +12 -12
- nextmv/cli/cloud/batch/create.py +28 -26
- nextmv/cli/cloud/batch/delete.py +10 -6
- nextmv/cli/cloud/batch/get.py +9 -9
- nextmv/cli/cloud/batch/list.py +3 -3
- nextmv/cli/cloud/batch/metadata.py +4 -4
- nextmv/cli/cloud/batch/update.py +6 -6
- nextmv/cli/cloud/data/__init__.py +1 -1
- nextmv/cli/cloud/data/upload.py +15 -15
- nextmv/cli/cloud/ensemble/__init__.py +0 -2
- nextmv/cli/cloud/ensemble/create.py +22 -21
- nextmv/cli/cloud/ensemble/delete.py +10 -6
- nextmv/cli/cloud/ensemble/get.py +4 -4
- nextmv/cli/cloud/ensemble/update.py +9 -9
- nextmv/cli/cloud/input_set/__init__.py +0 -2
- nextmv/cli/cloud/input_set/create.py +22 -22
- nextmv/cli/cloud/input_set/get.py +3 -3
- nextmv/cli/cloud/input_set/list.py +3 -3
- nextmv/cli/cloud/input_set/update.py +24 -24
- nextmv/cli/cloud/instance/create.py +15 -14
- nextmv/cli/cloud/instance/delete.py +7 -6
- nextmv/cli/cloud/instance/exists.py +2 -2
- nextmv/cli/cloud/instance/get.py +2 -2
- nextmv/cli/cloud/instance/list.py +3 -3
- nextmv/cli/cloud/instance/update.py +14 -14
- nextmv/cli/cloud/managed_input/create.py +16 -14
- nextmv/cli/cloud/managed_input/delete.py +8 -7
- nextmv/cli/cloud/managed_input/get.py +3 -3
- nextmv/cli/cloud/managed_input/list.py +3 -3
- nextmv/cli/cloud/managed_input/update.py +9 -9
- nextmv/cli/cloud/run/cancel.py +2 -2
- nextmv/cli/cloud/run/create.py +40 -34
- nextmv/cli/cloud/run/get.py +8 -8
- nextmv/cli/cloud/run/input.py +4 -4
- nextmv/cli/cloud/run/list.py +6 -6
- nextmv/cli/cloud/run/logs.py +10 -9
- nextmv/cli/cloud/run/metadata.py +4 -4
- nextmv/cli/cloud/run/track.py +33 -32
- nextmv/cli/cloud/scenario/create.py +21 -21
- nextmv/cli/cloud/scenario/delete.py +10 -6
- nextmv/cli/cloud/scenario/get.py +9 -9
- nextmv/cli/cloud/scenario/list.py +3 -3
- nextmv/cli/cloud/scenario/metadata.py +4 -4
- nextmv/cli/cloud/scenario/update.py +6 -6
- nextmv/cli/cloud/secrets/create.py +17 -17
- nextmv/cli/cloud/secrets/delete.py +10 -6
- nextmv/cli/cloud/secrets/get.py +4 -4
- nextmv/cli/cloud/secrets/list.py +3 -3
- nextmv/cli/cloud/secrets/update.py +20 -17
- nextmv/cli/cloud/upload/create.py +2 -2
- nextmv/cli/cloud/version/create.py +10 -9
- nextmv/cli/cloud/version/delete.py +7 -6
- nextmv/cli/cloud/version/exists.py +2 -2
- nextmv/cli/cloud/version/get.py +2 -2
- nextmv/cli/cloud/version/list.py +3 -3
- nextmv/cli/cloud/version/update.py +8 -8
- nextmv/cli/community/__init__.py +1 -1
- nextmv/cli/community/clone.py +204 -20
- nextmv/cli/community/list.py +125 -60
- nextmv/cli/configuration/config.py +10 -43
- nextmv/cli/configuration/create.py +7 -7
- nextmv/cli/configuration/delete.py +8 -8
- nextmv/cli/configuration/list.py +3 -3
- nextmv/cli/main.py +36 -26
- nextmv/cli/message.py +54 -71
- nextmv/cli/options.py +0 -28
- nextmv/cli/version.py +1 -1
- nextmv/cloud/__init__.py +38 -14
- nextmv/cloud/acceptance_test.py +65 -1
- nextmv/cloud/account.py +6 -1
- nextmv/cloud/application/__init__.py +75 -18
- nextmv/cloud/application/_acceptance.py +8 -13
- nextmv/cloud/application/_batch_scenario.py +19 -4
- nextmv/cloud/application/_input_set.py +6 -42
- nextmv/cloud/application/_instance.py +3 -3
- nextmv/cloud/application/_managed_input.py +2 -2
- nextmv/cloud/application/_version.py +3 -4
- nextmv/cloud/batch_experiment.py +1 -3
- nextmv/cloud/integration.py +4 -7
- nextmv/deprecated.py +3 -5
- nextmv/input.py +52 -0
- nextmv/local/runner.py +1 -1
- nextmv/model.py +11 -50
- nextmv/options.py +256 -11
- nextmv/output.py +62 -0
- nextmv/run.py +10 -1
- nextmv/status.py +51 -1
- {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/METADATA +4 -5
- nextmv-1.0.0.dev0.dist-info/RECORD +158 -0
- nextmv/cli/cloud/ensemble/list.py +0 -63
- nextmv/cli/cloud/input_set/delete.py +0 -64
- nextmv/cli/cloud/shadow/__init__.py +0 -33
- nextmv/cli/cloud/shadow/create.py +0 -184
- nextmv/cli/cloud/shadow/delete.py +0 -64
- nextmv/cli/cloud/shadow/get.py +0 -61
- nextmv/cli/cloud/shadow/list.py +0 -63
- nextmv/cli/cloud/shadow/metadata.py +0 -66
- nextmv/cli/cloud/shadow/start.py +0 -43
- nextmv/cli/cloud/shadow/stop.py +0 -53
- nextmv/cli/cloud/shadow/update.py +0 -96
- nextmv/cli/cloud/switchback/__init__.py +0 -33
- nextmv/cli/cloud/switchback/create.py +0 -151
- nextmv/cli/cloud/switchback/delete.py +0 -64
- nextmv/cli/cloud/switchback/get.py +0 -62
- nextmv/cli/cloud/switchback/list.py +0 -63
- nextmv/cli/cloud/switchback/metadata.py +0 -68
- nextmv/cli/cloud/switchback/start.py +0 -43
- nextmv/cli/cloud/switchback/stop.py +0 -53
- nextmv/cli/cloud/switchback/update.py +0 -96
- nextmv/cli/confirm.py +0 -34
- nextmv/cloud/application/_shadow.py +0 -320
- nextmv/cloud/application/_switchback.py +0 -332
- nextmv/cloud/community.py +0 -446
- nextmv/cloud/shadow.py +0 -254
- nextmv/cloud/switchback.py +0 -228
- nextmv-1.0.0.dist-info/RECORD +0 -185
- nextmv-1.0.0.dist-info/entry_points.txt +0 -2
- {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/WHEEL +0 -0
- {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module defines the cloud switchback 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 in_progress, print_json, success
|
|
12
|
-
from nextmv.cli.options import AppIDOption, ProfileOption
|
|
13
|
-
|
|
14
|
-
# Set up subcommand application.
|
|
15
|
-
app = typer.Typer()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@app.command()
|
|
19
|
-
def list(
|
|
20
|
-
app_id: AppIDOption,
|
|
21
|
-
output: Annotated[
|
|
22
|
-
str | None,
|
|
23
|
-
typer.Option(
|
|
24
|
-
"--output",
|
|
25
|
-
"-o",
|
|
26
|
-
help="Saves the list of switchback tests to this location.",
|
|
27
|
-
metavar="OUTPUT_PATH",
|
|
28
|
-
),
|
|
29
|
-
] = None,
|
|
30
|
-
profile: ProfileOption = None,
|
|
31
|
-
) -> None:
|
|
32
|
-
"""
|
|
33
|
-
List all Nextmv Cloud switchback tests for an application.
|
|
34
|
-
|
|
35
|
-
This command retrieves all switchback tests associated with the specified
|
|
36
|
-
application.
|
|
37
|
-
|
|
38
|
-
[bold][underline]Examples[/underline][/bold]
|
|
39
|
-
|
|
40
|
-
- List all switchback tests for application [magenta]hare-app[/magenta].
|
|
41
|
-
$ [dim]nextmv cloud switchback list --app-id hare-app[/dim]
|
|
42
|
-
|
|
43
|
-
- List all switchback tests and save to a file.
|
|
44
|
-
$ [dim]nextmv cloud switchback list --app-id hare-app --output tests.json[/dim]
|
|
45
|
-
|
|
46
|
-
- List all switchback tests using a specific profile.
|
|
47
|
-
$ [dim]nextmv cloud switchback list --app-id hare-app --profile prod[/dim]
|
|
48
|
-
"""
|
|
49
|
-
|
|
50
|
-
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
51
|
-
in_progress(msg="Listing switchback tests...")
|
|
52
|
-
switchback_tests = cloud_app.list_switchback_tests()
|
|
53
|
-
switchback_tests_dict = [test.to_dict() for test in switchback_tests]
|
|
54
|
-
|
|
55
|
-
if output is not None and output != "":
|
|
56
|
-
with open(output, "w") as f:
|
|
57
|
-
json.dump(switchback_tests_dict, f, indent=2)
|
|
58
|
-
|
|
59
|
-
success(msg=f"Switchback tests list saved to [magenta]{output}[/magenta].")
|
|
60
|
-
|
|
61
|
-
return
|
|
62
|
-
|
|
63
|
-
print_json(switchback_tests_dict)
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module defines the cloud switchback 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, SwitchbackTestIDOption
|
|
13
|
-
|
|
14
|
-
# Set up subcommand application.
|
|
15
|
-
app = typer.Typer()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@app.command()
|
|
19
|
-
def metadata(
|
|
20
|
-
app_id: AppIDOption,
|
|
21
|
-
switchback_test_id: SwitchbackTestIDOption,
|
|
22
|
-
output: Annotated[
|
|
23
|
-
str | None,
|
|
24
|
-
typer.Option(
|
|
25
|
-
"--output",
|
|
26
|
-
"-o",
|
|
27
|
-
help="Saves the switchback test 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 switchback test.
|
|
35
|
-
|
|
36
|
-
This command retrieves metadata for a specific switchback test, 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 switchback test [magenta]bunny-warren-optimization[/magenta] from application
|
|
43
|
-
[magenta]hare-app[/magenta].
|
|
44
|
-
$ [dim]nextmv cloud switchback metadata --app-id hare-app \\
|
|
45
|
-
--switchback-test-id bunny-warren-optimization[/dim]
|
|
46
|
-
|
|
47
|
-
- Get metadata and save to a file.
|
|
48
|
-
$ [dim]nextmv cloud switchback metadata --app-id hare-app --switchback-test-id lettuce-delivery \\
|
|
49
|
-
--output metadata.json[/dim]
|
|
50
|
-
|
|
51
|
-
- Get metadata using a specific profile.
|
|
52
|
-
$ [dim]nextmv cloud switchback metadata --app-id hare-app --switchback-test-id hop-schedule \\
|
|
53
|
-
--profile prod[/dim]
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
57
|
-
in_progress(msg="Getting switchback test metadata...")
|
|
58
|
-
switchback_metadata = cloud_app.switchback_test_metadata(switchback_test_id=switchback_test_id)
|
|
59
|
-
switchback_metadata_dict = switchback_metadata.to_dict()
|
|
60
|
-
|
|
61
|
-
if output is not None and output != "":
|
|
62
|
-
with open(output, "w") as f:
|
|
63
|
-
json.dump(switchback_metadata_dict, f, indent=2)
|
|
64
|
-
|
|
65
|
-
success(msg=f"Switchback test metadata saved to [magenta]{output}[/magenta].")
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
print_json(switchback_metadata_dict)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module defines the cloud switchback start command for the Nextmv CLI.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import typer
|
|
6
|
-
|
|
7
|
-
from nextmv.cli.configuration.config import build_app
|
|
8
|
-
from nextmv.cli.message import in_progress, success
|
|
9
|
-
from nextmv.cli.options import AppIDOption, ProfileOption, SwitchbackTestIDOption
|
|
10
|
-
|
|
11
|
-
# Set up subcommand application.
|
|
12
|
-
app = typer.Typer()
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@app.command()
|
|
16
|
-
def start(
|
|
17
|
-
app_id: AppIDOption,
|
|
18
|
-
switchback_test_id: SwitchbackTestIDOption,
|
|
19
|
-
profile: ProfileOption = None,
|
|
20
|
-
) -> None:
|
|
21
|
-
"""
|
|
22
|
-
Starts a Nextmv Cloud switchback test.
|
|
23
|
-
|
|
24
|
-
Before starting a switchback test, it must be created in draft state. You
|
|
25
|
-
may use the [code]nextmv cloud switchback create[/code] command to create a
|
|
26
|
-
new switchback test. Alternatively, define a --start when using the
|
|
27
|
-
[code]nextmv cloud switchback create[/code] command to have the switchback
|
|
28
|
-
test start automatically at a specific time.
|
|
29
|
-
|
|
30
|
-
[bold][underline]Examples[/underline][/bold]
|
|
31
|
-
|
|
32
|
-
- Start the switchback test with the ID [magenta]hop-analysis[/magenta] from application
|
|
33
|
-
[magenta]hare-app[/magenta].
|
|
34
|
-
$ [dim]nextmv cloud switchback start --app-id hare-app --switchback-test-id hop-analysis[/dim]
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
in_progress(msg="Starting switchback test...")
|
|
38
|
-
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
39
|
-
cloud_app.start_switchback_test(switchback_test_id=switchback_test_id)
|
|
40
|
-
success(
|
|
41
|
-
f"Switchback test [magenta]{switchback_test_id}[/magenta] started successfully "
|
|
42
|
-
f"in application [magenta]{app_id}[/magenta]."
|
|
43
|
-
)
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module defines the cloud switchback stop command for the Nextmv CLI.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from typing import Annotated
|
|
6
|
-
|
|
7
|
-
import typer
|
|
8
|
-
|
|
9
|
-
from nextmv.cli.configuration.config import build_app
|
|
10
|
-
from nextmv.cli.message import enum_values, in_progress, success
|
|
11
|
-
from nextmv.cli.options import AppIDOption, ProfileOption, SwitchbackTestIDOption
|
|
12
|
-
from nextmv.cloud.shadow import StopIntent
|
|
13
|
-
|
|
14
|
-
# Set up subcommand application.
|
|
15
|
-
app = typer.Typer()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@app.command()
|
|
19
|
-
def stop(
|
|
20
|
-
app_id: AppIDOption,
|
|
21
|
-
intent: Annotated[
|
|
22
|
-
StopIntent,
|
|
23
|
-
typer.Option(
|
|
24
|
-
"--intent",
|
|
25
|
-
"-i",
|
|
26
|
-
help=f"Intent for stopping the switchback test. Allowed values are: {enum_values(StopIntent)}.",
|
|
27
|
-
metavar="INTENT",
|
|
28
|
-
),
|
|
29
|
-
],
|
|
30
|
-
switchback_test_id: SwitchbackTestIDOption,
|
|
31
|
-
profile: ProfileOption = None,
|
|
32
|
-
) -> None:
|
|
33
|
-
"""
|
|
34
|
-
Stops a Nextmv Cloud switchback test.
|
|
35
|
-
|
|
36
|
-
Before stopping a switchback test, it must be in a started state. Experiments
|
|
37
|
-
in a [magenta]draft[/magenta] state, that haven't started, can be deleted
|
|
38
|
-
with the [code]nextmv cloud switchback delete[/code] command.
|
|
39
|
-
|
|
40
|
-
[bold][underline]Examples[/underline][/bold]
|
|
41
|
-
|
|
42
|
-
- Stop the switchback test with the ID [magenta]hop-analysis[/magenta] from application
|
|
43
|
-
[magenta]hare-app[/magenta].
|
|
44
|
-
$ [dim]nextmv cloud switchback stop --app-id hare-app --switchback-test-id hop-analysis[/dim]
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
in_progress(msg="Stopping switchback test...")
|
|
48
|
-
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
49
|
-
cloud_app.stop_switchback_test(switchback_test_id=switchback_test_id, intent=StopIntent(intent))
|
|
50
|
-
success(
|
|
51
|
-
f"Switchback test [magenta]{switchback_test_id}[/magenta] stopped successfully "
|
|
52
|
-
f"in application [magenta]{app_id}[/magenta]."
|
|
53
|
-
)
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module defines the cloud switchback 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, ProfileOption, SwitchbackTestIDOption
|
|
13
|
-
|
|
14
|
-
# Set up subcommand application.
|
|
15
|
-
app = typer.Typer()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@app.command()
|
|
19
|
-
def update(
|
|
20
|
-
app_id: AppIDOption,
|
|
21
|
-
switchback_test_id: SwitchbackTestIDOption,
|
|
22
|
-
description: Annotated[
|
|
23
|
-
str | None,
|
|
24
|
-
typer.Option(
|
|
25
|
-
"--description",
|
|
26
|
-
"-d",
|
|
27
|
-
help="Updated description of the switchback test.",
|
|
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 switchback test.",
|
|
37
|
-
metavar="NAME",
|
|
38
|
-
),
|
|
39
|
-
] = None,
|
|
40
|
-
output: Annotated[
|
|
41
|
-
str | None,
|
|
42
|
-
typer.Option(
|
|
43
|
-
"--output",
|
|
44
|
-
"-o",
|
|
45
|
-
help="Saves the updated switchback test information to this location.",
|
|
46
|
-
metavar="OUTPUT_PATH",
|
|
47
|
-
),
|
|
48
|
-
] = None,
|
|
49
|
-
profile: ProfileOption = None,
|
|
50
|
-
) -> None:
|
|
51
|
-
"""
|
|
52
|
-
Update a Nextmv Cloud switchback test.
|
|
53
|
-
|
|
54
|
-
Update the name and/or description of a switchback test. Any fields not
|
|
55
|
-
specified will remain unchanged.
|
|
56
|
-
|
|
57
|
-
[bold][underline]Examples[/underline][/bold]
|
|
58
|
-
|
|
59
|
-
- Update the name of a switchback test.
|
|
60
|
-
$ [dim]nextmv cloud switchback update --app-id hare-app --switchback-test-id carrot-feast \\
|
|
61
|
-
--name "Spring Carrot Harvest"[/dim]
|
|
62
|
-
|
|
63
|
-
- Update the description of a switchback test.
|
|
64
|
-
$ [dim]nextmv cloud switchback update --app-id hare-app --switchback-test-id bunny-hop-routes \\
|
|
65
|
-
--description "Optimizing hop paths through the meadow"[/dim]
|
|
66
|
-
|
|
67
|
-
- Update both name and description and save the result.
|
|
68
|
-
$ [dim]nextmv cloud switchback update --app-id hare-app --switchback-test-id lettuce-delivery \\
|
|
69
|
-
--name "Warren Lettuce Express" --description "Fast lettuce delivery to all burrows" \\
|
|
70
|
-
--output updated-switchback-test.json[/dim]
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
74
|
-
|
|
75
|
-
in_progress(msg="Updating switchback test...")
|
|
76
|
-
switchback_test = cloud_app.update_switchback_test(
|
|
77
|
-
switchback_test_id=switchback_test_id,
|
|
78
|
-
name=name,
|
|
79
|
-
description=description,
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
switchback_test_dict = switchback_test.to_dict()
|
|
83
|
-
success(
|
|
84
|
-
f"Switchback test [magenta]{switchback_test_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(switchback_test_dict, f, indent=2)
|
|
91
|
-
|
|
92
|
-
success(msg=f"Updated switchback test information saved to [magenta]{output}[/magenta].")
|
|
93
|
-
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
print_json(switchback_test_dict)
|
nextmv/cli/confirm.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
|
|
3
|
-
from rich.prompt import Confirm
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def get_confirmation(msg: str, default: bool = False) -> bool:
|
|
7
|
-
"""
|
|
8
|
-
Method to get a yes/no confirmation from the user.
|
|
9
|
-
|
|
10
|
-
Parameters
|
|
11
|
-
----------
|
|
12
|
-
msg : str
|
|
13
|
-
The message to display to the user.
|
|
14
|
-
default : bool, optional
|
|
15
|
-
The default value if the user just presses Enter. Default is False.
|
|
16
|
-
|
|
17
|
-
Returns
|
|
18
|
-
-------
|
|
19
|
-
bool
|
|
20
|
-
True if the user confirmed, False otherwise.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
# If this is not an interactive terminal, do not ask for confirmation, to
|
|
24
|
-
# avoid hanging indefinitely waiting for a user response.
|
|
25
|
-
if not sys.stdin.isatty():
|
|
26
|
-
return default
|
|
27
|
-
|
|
28
|
-
return Confirm.ask(
|
|
29
|
-
msg,
|
|
30
|
-
default=default,
|
|
31
|
-
case_sensitive=False,
|
|
32
|
-
show_default=True,
|
|
33
|
-
show_choices=True,
|
|
34
|
-
)
|
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Application mixin for managing shadow tests.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
|
-
|
|
7
|
-
from nextmv.cloud.shadow import ShadowTest, ShadowTestMetadata, StartEvents, StopIntent, TerminationEvents
|
|
8
|
-
from nextmv.run import Run
|
|
9
|
-
from nextmv.safe import safe_id
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from . import Application
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class ApplicationShadowMixin:
|
|
16
|
-
"""
|
|
17
|
-
Mixin class for managing shadow tests within an application.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
def shadow_test(self: "Application", shadow_test_id: str) -> ShadowTest:
|
|
21
|
-
"""
|
|
22
|
-
Get a shadow test. This method also returns the runs of the shadow
|
|
23
|
-
test under the `.runs` attribute.
|
|
24
|
-
|
|
25
|
-
Parameters
|
|
26
|
-
----------
|
|
27
|
-
shadow_test_id : str
|
|
28
|
-
ID of the shadow test.
|
|
29
|
-
|
|
30
|
-
Returns
|
|
31
|
-
-------
|
|
32
|
-
ShadowTest
|
|
33
|
-
The requested shadow test details.
|
|
34
|
-
|
|
35
|
-
Raises
|
|
36
|
-
------
|
|
37
|
-
requests.HTTPError
|
|
38
|
-
If the response status code is not 2xx.
|
|
39
|
-
|
|
40
|
-
Examples
|
|
41
|
-
--------
|
|
42
|
-
>>> shadow_test = app.shadow_test("shadow-123")
|
|
43
|
-
>>> print(shadow_test.name)
|
|
44
|
-
'My Shadow Test'
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
response = self.client.request(
|
|
48
|
-
method="GET",
|
|
49
|
-
endpoint=f"{self.experiments_endpoint}/shadow/{shadow_test_id}",
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
exp = ShadowTest.from_dict(response.json())
|
|
53
|
-
|
|
54
|
-
runs_response = self.client.request(
|
|
55
|
-
method="GET",
|
|
56
|
-
endpoint=f"{self.experiments_endpoint}/shadow/{shadow_test_id}/runs",
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
runs = [Run.from_dict(run) for run in runs_response.json().get("runs", [])]
|
|
60
|
-
exp.runs = runs
|
|
61
|
-
|
|
62
|
-
return exp
|
|
63
|
-
|
|
64
|
-
def shadow_test_metadata(self: "Application", shadow_test_id: str) -> ShadowTestMetadata:
|
|
65
|
-
"""
|
|
66
|
-
Get metadata for a shadow test.
|
|
67
|
-
|
|
68
|
-
Parameters
|
|
69
|
-
----------
|
|
70
|
-
shadow_test_id : str
|
|
71
|
-
ID of the shadow test.
|
|
72
|
-
|
|
73
|
-
Returns
|
|
74
|
-
-------
|
|
75
|
-
ShadowTestMetadata
|
|
76
|
-
The requested shadow test metadata.
|
|
77
|
-
|
|
78
|
-
Raises
|
|
79
|
-
------
|
|
80
|
-
requests.HTTPError
|
|
81
|
-
If the response status code is not 2xx.
|
|
82
|
-
|
|
83
|
-
Examples
|
|
84
|
-
--------
|
|
85
|
-
>>> metadata = app.shadow_test_metadata("shadow-123")
|
|
86
|
-
>>> print(metadata.name)
|
|
87
|
-
'My Shadow Test'
|
|
88
|
-
"""
|
|
89
|
-
|
|
90
|
-
response = self.client.request(
|
|
91
|
-
method="GET",
|
|
92
|
-
endpoint=f"{self.experiments_endpoint}/shadow/{shadow_test_id}/metadata",
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
return ShadowTestMetadata.from_dict(response.json())
|
|
96
|
-
|
|
97
|
-
def delete_shadow_test(self: "Application", shadow_test_id: str) -> None:
|
|
98
|
-
"""
|
|
99
|
-
Delete a shadow test.
|
|
100
|
-
|
|
101
|
-
Deletes a shadow test along with all the associated information,
|
|
102
|
-
such as its runs.
|
|
103
|
-
|
|
104
|
-
Parameters
|
|
105
|
-
----------
|
|
106
|
-
shadow_test_id : str
|
|
107
|
-
ID of the shadow test to delete.
|
|
108
|
-
|
|
109
|
-
Raises
|
|
110
|
-
------
|
|
111
|
-
requests.HTTPError
|
|
112
|
-
If the response status code is not 2xx.
|
|
113
|
-
|
|
114
|
-
Examples
|
|
115
|
-
--------
|
|
116
|
-
>>> app.delete_shadow_test("shadow-123")
|
|
117
|
-
"""
|
|
118
|
-
|
|
119
|
-
_ = self.client.request(
|
|
120
|
-
method="DELETE",
|
|
121
|
-
endpoint=f"{self.experiments_endpoint}/shadow/{shadow_test_id}",
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
def list_shadow_tests(self: "Application") -> list[ShadowTest]:
|
|
125
|
-
"""
|
|
126
|
-
List all shadow tests.
|
|
127
|
-
|
|
128
|
-
Returns
|
|
129
|
-
-------
|
|
130
|
-
list[ShadowTest]
|
|
131
|
-
List of shadow tests.
|
|
132
|
-
|
|
133
|
-
Raises
|
|
134
|
-
------
|
|
135
|
-
requests.HTTPError
|
|
136
|
-
If the response status code is not 2xx.
|
|
137
|
-
"""
|
|
138
|
-
|
|
139
|
-
response = self.client.request(
|
|
140
|
-
method="GET",
|
|
141
|
-
endpoint=f"{self.experiments_endpoint}/shadow",
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
return [ShadowTest.from_dict(shadow_test) for shadow_test in response.json()]
|
|
145
|
-
|
|
146
|
-
def new_shadow_test(
|
|
147
|
-
self: "Application",
|
|
148
|
-
comparisons: dict[str, list[str]],
|
|
149
|
-
termination_events: TerminationEvents,
|
|
150
|
-
shadow_test_id: str | None = None,
|
|
151
|
-
name: str | None = None,
|
|
152
|
-
description: str | None = None,
|
|
153
|
-
start_events: StartEvents | None = None,
|
|
154
|
-
) -> ShadowTest:
|
|
155
|
-
"""
|
|
156
|
-
Create a new shadow test in draft mode. Shadow tests are experiments
|
|
157
|
-
that run instances in parallel to compare their results.
|
|
158
|
-
|
|
159
|
-
Use the `comparisons` parameter to define how to set up instance
|
|
160
|
-
comparisons. The keys of the `comparisons` dictionary are the baseline
|
|
161
|
-
instance IDs, and the values are the candidate lists of instance IDs to
|
|
162
|
-
compare against the respective baseline.
|
|
163
|
-
|
|
164
|
-
You may specify `start_events` to make the shadow test start at a
|
|
165
|
-
specific time. Alternatively, you may use the `start_shadow_test`
|
|
166
|
-
method to start the test.
|
|
167
|
-
|
|
168
|
-
The `termination_events` parameter is required and provides control
|
|
169
|
-
over when the shadow test should terminate. Alternatively, you may use
|
|
170
|
-
the `stop_shadow_test` method to stop the test.
|
|
171
|
-
|
|
172
|
-
Parameters
|
|
173
|
-
----------
|
|
174
|
-
comparisons : dict[str, list[str]]
|
|
175
|
-
Dictionary defining the baseline and candidate instance IDs for
|
|
176
|
-
comparison. The keys are baseline instance IDs, and the values are
|
|
177
|
-
lists of candidate instance IDs to compare against the respective
|
|
178
|
-
baseline.
|
|
179
|
-
termination_events : TerminationEvents
|
|
180
|
-
Termination events for the shadow test.
|
|
181
|
-
shadow_test_id : Optional[str]
|
|
182
|
-
ID of the shadow test. Will be generated if not provided.
|
|
183
|
-
name : Optional[str]
|
|
184
|
-
Name of the shadow test. If not provided, the ID will be used as
|
|
185
|
-
the name.
|
|
186
|
-
description : Optional[str]
|
|
187
|
-
Optional description of the shadow test.
|
|
188
|
-
start_events : Optional[StartEvents]
|
|
189
|
-
Start events for the shadow test.
|
|
190
|
-
|
|
191
|
-
Returns
|
|
192
|
-
-------
|
|
193
|
-
ShadowTest
|
|
194
|
-
The created shadow test.
|
|
195
|
-
|
|
196
|
-
Raises
|
|
197
|
-
------
|
|
198
|
-
requests.HTTPError
|
|
199
|
-
If the response status code is not 2xx.
|
|
200
|
-
"""
|
|
201
|
-
|
|
202
|
-
# Generate ID if not provided
|
|
203
|
-
if shadow_test_id is None:
|
|
204
|
-
shadow_test_id = safe_id("shadow")
|
|
205
|
-
|
|
206
|
-
# Use ID as name if name not provided
|
|
207
|
-
if name is None or name == "":
|
|
208
|
-
name = shadow_test_id
|
|
209
|
-
|
|
210
|
-
payload = {
|
|
211
|
-
"id": shadow_test_id,
|
|
212
|
-
"name": name,
|
|
213
|
-
"comparisons": comparisons,
|
|
214
|
-
"termination_events": termination_events.to_dict(),
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if description is not None:
|
|
218
|
-
payload["description"] = description
|
|
219
|
-
if start_events is not None:
|
|
220
|
-
payload["start_events"] = start_events.to_dict()
|
|
221
|
-
|
|
222
|
-
response = self.client.request(
|
|
223
|
-
method="POST",
|
|
224
|
-
endpoint=f"{self.experiments_endpoint}/shadow",
|
|
225
|
-
payload=payload,
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
return ShadowTest.from_dict(response.json())
|
|
229
|
-
|
|
230
|
-
def start_shadow_test(self: "Application", shadow_test_id: str) -> None:
|
|
231
|
-
"""
|
|
232
|
-
Start a shadow test. Create a shadow test in draft mode using the
|
|
233
|
-
`new_shadow_test` method, then use this method to start the test.
|
|
234
|
-
|
|
235
|
-
Parameters
|
|
236
|
-
----------
|
|
237
|
-
shadow_test_id : str
|
|
238
|
-
ID of the shadow test to start.
|
|
239
|
-
|
|
240
|
-
Raises
|
|
241
|
-
------
|
|
242
|
-
requests.HTTPError
|
|
243
|
-
If the response status code is not 2xx.
|
|
244
|
-
"""
|
|
245
|
-
|
|
246
|
-
_ = self.client.request(
|
|
247
|
-
method="PUT",
|
|
248
|
-
endpoint=f"{self.experiments_endpoint}/shadow/{shadow_test_id}/start",
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
def stop_shadow_test(self: "Application", shadow_test_id: str, intent: StopIntent) -> None:
|
|
252
|
-
"""
|
|
253
|
-
Stop a shadow test. The test should already have started before using
|
|
254
|
-
this method.
|
|
255
|
-
|
|
256
|
-
Parameters
|
|
257
|
-
----------
|
|
258
|
-
shadow_test_id : str
|
|
259
|
-
ID of the shadow test to stop.
|
|
260
|
-
intent : StopIntent
|
|
261
|
-
Intent for stopping the shadow test.
|
|
262
|
-
Raises
|
|
263
|
-
------
|
|
264
|
-
requests.HTTPError
|
|
265
|
-
If the response status code is not 2xx.
|
|
266
|
-
"""
|
|
267
|
-
|
|
268
|
-
payload = {
|
|
269
|
-
"intent": intent.value,
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
_ = self.client.request(
|
|
273
|
-
method="PUT",
|
|
274
|
-
endpoint=f"{self.experiments_endpoint}/shadow/{shadow_test_id}/stop",
|
|
275
|
-
payload=payload,
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
def update_shadow_test(
|
|
279
|
-
self: "Application",
|
|
280
|
-
shadow_test_id: str,
|
|
281
|
-
name: str | None = None,
|
|
282
|
-
description: str | None = None,
|
|
283
|
-
) -> ShadowTest:
|
|
284
|
-
"""
|
|
285
|
-
Update a shadow test.
|
|
286
|
-
|
|
287
|
-
Parameters
|
|
288
|
-
----------
|
|
289
|
-
shadow_test_id : str
|
|
290
|
-
ID of the shadow test to update.
|
|
291
|
-
name : Optional[str], default=None
|
|
292
|
-
Optional name of the shadow test.
|
|
293
|
-
description : Optional[str], default=None
|
|
294
|
-
Optional description of the shadow test.
|
|
295
|
-
|
|
296
|
-
Returns
|
|
297
|
-
-------
|
|
298
|
-
ShadowTest
|
|
299
|
-
The information with the updated shadow test.
|
|
300
|
-
|
|
301
|
-
Raises
|
|
302
|
-
------
|
|
303
|
-
requests.HTTPError
|
|
304
|
-
If the response status code is not 2xx.
|
|
305
|
-
"""
|
|
306
|
-
|
|
307
|
-
payload = {}
|
|
308
|
-
|
|
309
|
-
if name is not None:
|
|
310
|
-
payload["name"] = name
|
|
311
|
-
if description is not None:
|
|
312
|
-
payload["description"] = description
|
|
313
|
-
|
|
314
|
-
response = self.client.request(
|
|
315
|
-
method="PATCH",
|
|
316
|
-
endpoint=f"{self.experiments_endpoint}/shadow/{shadow_test_id}",
|
|
317
|
-
payload=payload,
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
return ShadowTest.from_dict(response.json())
|