nextmv 0.26.3__py3-none-any.whl → 0.28.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 +3 -5
- nextmv/__init__.py +1 -0
- nextmv/base_model.py +52 -7
- nextmv/cloud/__init__.py +3 -0
- nextmv/cloud/acceptance_test.py +711 -20
- nextmv/cloud/account.py +152 -7
- nextmv/cloud/application.py +1231 -396
- nextmv/cloud/batch_experiment.py +133 -21
- nextmv/cloud/client.py +240 -46
- nextmv/cloud/input_set.py +96 -3
- nextmv/cloud/instance.py +89 -3
- nextmv/cloud/manifest.py +625 -87
- nextmv/cloud/package.py +2 -2
- nextmv/cloud/run.py +376 -45
- nextmv/cloud/safe.py +7 -7
- nextmv/cloud/scenario.py +205 -20
- nextmv/cloud/secrets.py +179 -6
- nextmv/cloud/status.py +95 -2
- nextmv/cloud/version.py +132 -4
- nextmv/deprecated.py +36 -2
- nextmv/input.py +300 -82
- nextmv/logger.py +71 -7
- nextmv/model.py +225 -58
- nextmv/options.py +301 -69
- nextmv/output.py +667 -236
- {nextmv-0.26.3.dist-info → nextmv-0.28.0.dist-info}/METADATA +1 -1
- nextmv-0.28.0.dist-info/RECORD +30 -0
- nextmv-0.26.3.dist-info/RECORD +0 -30
- {nextmv-0.26.3.dist-info → nextmv-0.28.0.dist-info}/WHEEL +0 -0
- {nextmv-0.26.3.dist-info → nextmv-0.28.0.dist-info}/licenses/LICENSE +0 -0
nextmv/cloud/scenario.py
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
"""This module contains definitions for scenario tests.
|
|
1
|
+
"""This module contains definitions for scenario tests.
|
|
2
|
+
|
|
3
|
+
Classes
|
|
4
|
+
-------
|
|
5
|
+
ScenarioConfiguration
|
|
6
|
+
Configuration for a scenario with multiple option values.
|
|
7
|
+
ScenarioInputType
|
|
8
|
+
Enumeration of input types for a scenario.
|
|
9
|
+
ScenarioInput
|
|
10
|
+
Input to be processed in a scenario.
|
|
11
|
+
Scenario
|
|
12
|
+
A test case for comparing a decision model with inputs and configurations.
|
|
13
|
+
"""
|
|
2
14
|
|
|
3
15
|
import itertools
|
|
4
16
|
from dataclasses import dataclass
|
|
@@ -11,6 +23,12 @@ class ScenarioConfiguration:
|
|
|
11
23
|
"""
|
|
12
24
|
Configuration for a scenario.
|
|
13
25
|
|
|
26
|
+
You can import the `ScenarioConfiguration` class directly from `cloud`:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from nextmv.cloud import ScenarioConfiguration
|
|
30
|
+
```
|
|
31
|
+
|
|
14
32
|
You can define multiple values for a single option, which will result in
|
|
15
33
|
multiple runs being created. For example, if you have a configuration
|
|
16
34
|
option "x" with values [1, 2], and a configuration option "y" with values
|
|
@@ -20,12 +38,17 @@ class ScenarioConfiguration:
|
|
|
20
38
|
- x=2, y=3
|
|
21
39
|
- x=2, y=4
|
|
22
40
|
|
|
23
|
-
|
|
41
|
+
Parameters
|
|
24
42
|
----------
|
|
25
43
|
name : str
|
|
26
44
|
Name of the configuration option.
|
|
27
45
|
values : list[str]
|
|
28
46
|
List of values for the configuration option.
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
--------
|
|
50
|
+
>>> from nextmv.cloud import ScenarioConfiguration
|
|
51
|
+
>>> config = ScenarioConfiguration(name="solver", values=["simplex", "interior-point"])
|
|
29
52
|
"""
|
|
30
53
|
|
|
31
54
|
name: str
|
|
@@ -36,6 +59,11 @@ class ScenarioConfiguration:
|
|
|
36
59
|
def __post_init__(self):
|
|
37
60
|
"""
|
|
38
61
|
Post-initialization method to ensure that the values are unique.
|
|
62
|
+
|
|
63
|
+
Raises
|
|
64
|
+
------
|
|
65
|
+
ValueError
|
|
66
|
+
If the configuration values list is empty.
|
|
39
67
|
"""
|
|
40
68
|
if len(self.values) <= 0:
|
|
41
69
|
raise ValueError("Configuration values must be non-empty.")
|
|
@@ -46,7 +74,13 @@ class ScenarioInputType(str, Enum):
|
|
|
46
74
|
Type of input for a scenario. This is used to determine how the input
|
|
47
75
|
should be processed.
|
|
48
76
|
|
|
49
|
-
|
|
77
|
+
You can import the `ScenarioInputType` class directly from `cloud`:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from nextmv.cloud import ScenarioInputType
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
50
84
|
----------
|
|
51
85
|
INPUT_SET : str
|
|
52
86
|
The data in the scenario is an input set.
|
|
@@ -54,6 +88,11 @@ class ScenarioInputType(str, Enum):
|
|
|
54
88
|
The data in the scenario is an input.
|
|
55
89
|
NEW : str
|
|
56
90
|
The data in the scenario is new data.
|
|
91
|
+
|
|
92
|
+
Examples
|
|
93
|
+
--------
|
|
94
|
+
>>> from nextmv.cloud import ScenarioInputType
|
|
95
|
+
>>> input_type = ScenarioInputType.INPUT_SET
|
|
57
96
|
"""
|
|
58
97
|
|
|
59
98
|
INPUT_SET = "input_set"
|
|
@@ -67,12 +106,20 @@ class ScenarioInputType(str, Enum):
|
|
|
67
106
|
@dataclass
|
|
68
107
|
class ScenarioInput:
|
|
69
108
|
"""
|
|
70
|
-
Input to be processed in a scenario.
|
|
71
|
-
the `scenario_input_type` attribute. The input can be a single input set
|
|
72
|
-
ID, a list of input IDs, or raw data. The data itself of the scenario input
|
|
73
|
-
is tracked by the `scenario_input_data` attribute.
|
|
109
|
+
Input to be processed in a scenario.
|
|
74
110
|
|
|
75
|
-
|
|
111
|
+
You can import the `ScenarioInput` class directly from `cloud`:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from nextmv.cloud import ScenarioInput
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The type of input is determined by the `scenario_input_type` attribute.
|
|
118
|
+
The input can be a single input set ID, a list of input IDs, or raw data.
|
|
119
|
+
The data itself of the scenario input is tracked by the `scenario_input_data`
|
|
120
|
+
attribute.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
76
123
|
----------
|
|
77
124
|
scenario_input_type : ScenarioInputType
|
|
78
125
|
Type of input for the scenario. This is used to determine how the input
|
|
@@ -85,6 +132,25 @@ class ScenarioInput:
|
|
|
85
132
|
behavior occurs when providing raw data (`list[dict[str, Any]]`). All
|
|
86
133
|
the entries in the list of raw dicts will be collected to create a new
|
|
87
134
|
input set.
|
|
135
|
+
|
|
136
|
+
Examples
|
|
137
|
+
--------
|
|
138
|
+
>>> from nextmv.cloud import ScenarioInput, ScenarioInputType
|
|
139
|
+
>>> # Using an existing input set
|
|
140
|
+
>>> input_set = ScenarioInput(
|
|
141
|
+
... scenario_input_type=ScenarioInputType.INPUT_SET,
|
|
142
|
+
... scenario_input_data="input-set-id-123"
|
|
143
|
+
... )
|
|
144
|
+
>>> # Using a list of inputs
|
|
145
|
+
>>> inputs = ScenarioInput(
|
|
146
|
+
... scenario_input_type=ScenarioInputType.INPUT,
|
|
147
|
+
... scenario_input_data=["input-id-1", "input-id-2"]
|
|
148
|
+
... )
|
|
149
|
+
>>> # Using raw data
|
|
150
|
+
>>> raw_data = ScenarioInput(
|
|
151
|
+
... scenario_input_type=ScenarioInputType.NEW,
|
|
152
|
+
... scenario_input_data=[{"id": 1, "value": "data1"}, {"id": 2, "value": "data2"}]
|
|
153
|
+
... )
|
|
88
154
|
"""
|
|
89
155
|
|
|
90
156
|
scenario_input_type: ScenarioInputType
|
|
@@ -105,6 +171,13 @@ class ScenarioInput:
|
|
|
105
171
|
def __post_init__(self):
|
|
106
172
|
"""
|
|
107
173
|
Post-initialization method to ensure that the input data is valid.
|
|
174
|
+
|
|
175
|
+
Raises
|
|
176
|
+
------
|
|
177
|
+
ValueError
|
|
178
|
+
If the scenario input type and data type don't match:
|
|
179
|
+
- When using INPUT_SET, scenario_input_data must be a string
|
|
180
|
+
- When using INPUT or NEW, scenario_input_data must be a list
|
|
108
181
|
"""
|
|
109
182
|
if self.scenario_input_type == ScenarioInputType.INPUT_SET and not isinstance(self.scenario_input_data, str):
|
|
110
183
|
raise ValueError("Scenario input type must be a string when using an input set.")
|
|
@@ -120,19 +193,55 @@ class Scenario:
|
|
|
120
193
|
A scenario is a test case that is used to compare a decision model being
|
|
121
194
|
executed with a set of inputs and configurations.
|
|
122
195
|
|
|
123
|
-
|
|
196
|
+
You can import the `Scenario` class directly from `cloud`:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
from nextmv.cloud import Scenario
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
A scenario encapsulates all the necessary information to run a test case
|
|
203
|
+
against a decision model. Each scenario includes input data, an instance ID,
|
|
204
|
+
and can optionally include configuration options that define different
|
|
205
|
+
variations of the run.
|
|
206
|
+
|
|
207
|
+
Parameters
|
|
124
208
|
----------
|
|
125
209
|
scenario_input : ScenarioInput
|
|
126
210
|
Input for the scenario. The input is composed of a type and data. Make
|
|
127
211
|
sure you use the `ScenarioInput` class to create the input.
|
|
212
|
+
instance_id : str
|
|
213
|
+
ID of the instance to be used for the scenario.
|
|
128
214
|
scenario_id : Optional[str]
|
|
129
215
|
Optional ID of the scenario. The default value will be set as
|
|
130
216
|
`scenario-<index>` if not set.
|
|
131
|
-
|
|
132
|
-
ID of the instance to be used for the scenario.
|
|
133
|
-
configuration : Optional[ScenarioConfiguration]
|
|
217
|
+
configuration : Optional[list[ScenarioConfiguration]]
|
|
134
218
|
Optional configuration for the scenario. Use this attribute to
|
|
135
219
|
configure variation of options for the scenario.
|
|
220
|
+
|
|
221
|
+
Examples
|
|
222
|
+
--------
|
|
223
|
+
>>> from nextmv.cloud import Scenario, ScenarioInput, ScenarioInputType, ScenarioConfiguration
|
|
224
|
+
>>> # Creating a simple scenario with an input set
|
|
225
|
+
>>> input_data = ScenarioInput(
|
|
226
|
+
... scenario_input_type=ScenarioInputType.INPUT_SET,
|
|
227
|
+
... scenario_input_data="input-set-id-123"
|
|
228
|
+
... )
|
|
229
|
+
>>> scenario = Scenario(
|
|
230
|
+
... scenario_input=input_data,
|
|
231
|
+
... instance_id="instance-id-456",
|
|
232
|
+
... scenario_id="my-test-scenario"
|
|
233
|
+
... )
|
|
234
|
+
>>>
|
|
235
|
+
>>> # Creating a scenario with configuration options
|
|
236
|
+
>>> config_options = [
|
|
237
|
+
... ScenarioConfiguration(name="solver", values=["simplex", "interior-point"]),
|
|
238
|
+
... ScenarioConfiguration(name="timeout", values=["10", "30", "60"])
|
|
239
|
+
... ]
|
|
240
|
+
>>> scenario_with_config = Scenario(
|
|
241
|
+
... scenario_input=input_data,
|
|
242
|
+
... instance_id="instance-id-456",
|
|
243
|
+
... configuration=config_options
|
|
244
|
+
... )
|
|
136
245
|
"""
|
|
137
246
|
|
|
138
247
|
scenario_input: ScenarioInput
|
|
@@ -156,14 +265,36 @@ class Scenario:
|
|
|
156
265
|
def option_combinations(self) -> list[dict[str, str]]:
|
|
157
266
|
"""
|
|
158
267
|
Creates the combination of options that are derived from the
|
|
159
|
-
`configuration` property.
|
|
160
|
-
|
|
268
|
+
`configuration` property.
|
|
269
|
+
|
|
270
|
+
This method calculates the cross-product of all configuration
|
|
271
|
+
options to generate all possible combinations. If no configuration
|
|
272
|
+
is provided, it returns a list with an empty dictionary.
|
|
161
273
|
|
|
162
274
|
Returns
|
|
163
275
|
-------
|
|
164
276
|
list[dict[str, str]]
|
|
165
277
|
A list of dictionaries where each dictionary represents a set of
|
|
166
278
|
options derived from the configuration.
|
|
279
|
+
|
|
280
|
+
Examples
|
|
281
|
+
--------
|
|
282
|
+
>>> from nextmv.cloud import Scenario, ScenarioInput, ScenarioInputType, ScenarioConfiguration
|
|
283
|
+
>>> input_data = ScenarioInput(
|
|
284
|
+
... scenario_input_type=ScenarioInputType.INPUT_SET,
|
|
285
|
+
... scenario_input_data="input-set-id"
|
|
286
|
+
... )
|
|
287
|
+
>>> config = [
|
|
288
|
+
... ScenarioConfiguration(name="x", values=["1", "2"]),
|
|
289
|
+
... ScenarioConfiguration(name="y", values=["3", "4"])
|
|
290
|
+
... ]
|
|
291
|
+
>>> scenario = Scenario(
|
|
292
|
+
... scenario_input=input_data,
|
|
293
|
+
... instance_id="instance-id",
|
|
294
|
+
... configuration=config
|
|
295
|
+
... )
|
|
296
|
+
>>> scenario.option_combinations()
|
|
297
|
+
[{'x': '1', 'y': '3'}, {'x': '1', 'y': '4'}, {'x': '2', 'y': '3'}, {'x': '2', 'y': '4'}]
|
|
167
298
|
"""
|
|
168
299
|
|
|
169
300
|
if self.configuration is None or len(self.configuration) == 0:
|
|
@@ -177,9 +308,12 @@ class Scenario:
|
|
|
177
308
|
|
|
178
309
|
def _option_sets(scenarios: list[Scenario]) -> dict[str, dict[str, dict[str, str]]]:
|
|
179
310
|
"""
|
|
180
|
-
Creates options sets that are derived from `scenarios`.
|
|
181
|
-
|
|
182
|
-
options
|
|
311
|
+
Creates options sets that are derived from `scenarios`.
|
|
312
|
+
|
|
313
|
+
The options sets are grouped by scenario ID. The cross-product of the
|
|
314
|
+
configuration options is created to generate all possible combinations
|
|
315
|
+
of options. Each combination is given a unique key based on the scenario ID
|
|
316
|
+
and a combination index.
|
|
183
317
|
|
|
184
318
|
Parameters
|
|
185
319
|
----------
|
|
@@ -193,6 +327,23 @@ def _option_sets(scenarios: list[Scenario]) -> dict[str, dict[str, dict[str, str
|
|
|
193
327
|
dictionaries of option sets. Each option set is a dictionary where the
|
|
194
328
|
keys are option names and the values are the corresponding option
|
|
195
329
|
values.
|
|
330
|
+
|
|
331
|
+
Examples
|
|
332
|
+
--------
|
|
333
|
+
>>> from nextmv.cloud import Scenario, ScenarioInput, ScenarioInputType, ScenarioConfiguration
|
|
334
|
+
>>> input_data = ScenarioInput(
|
|
335
|
+
... scenario_input_type=ScenarioInputType.INPUT_SET,
|
|
336
|
+
... scenario_input_data="input-set-id"
|
|
337
|
+
... )
|
|
338
|
+
>>> config = [ScenarioConfiguration(name="x", values=["1", "2"])]
|
|
339
|
+
>>> scenario = Scenario(
|
|
340
|
+
... scenario_input=input_data,
|
|
341
|
+
... instance_id="instance-id",
|
|
342
|
+
... scenario_id="test-scenario",
|
|
343
|
+
... configuration=config
|
|
344
|
+
... )
|
|
345
|
+
>>> _option_sets([scenario])
|
|
346
|
+
{'test-scenario': {'test-scenario_0': {'x': '1'}, 'test-scenario_1': {'x': '2'}}}
|
|
196
347
|
"""
|
|
197
348
|
|
|
198
349
|
sets_by_scenario = {}
|
|
@@ -210,9 +361,43 @@ def _option_sets(scenarios: list[Scenario]) -> dict[str, dict[str, dict[str, str
|
|
|
210
361
|
|
|
211
362
|
def _scenarios_by_id(scenarios: list[Scenario]) -> dict[str, Scenario]:
|
|
212
363
|
"""
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
scenario
|
|
364
|
+
Maps scenarios to their IDs.
|
|
365
|
+
|
|
366
|
+
This function builds a dictionary that maps each scenario to its ID.
|
|
367
|
+
If a scenario doesn't have an ID defined, one is created using the format
|
|
368
|
+
"scenario-{index}". The function also checks that there are no duplicate
|
|
369
|
+
scenario IDs in the provided list.
|
|
370
|
+
|
|
371
|
+
Parameters
|
|
372
|
+
----------
|
|
373
|
+
scenarios : list[Scenario]
|
|
374
|
+
List of scenarios to be mapped.
|
|
375
|
+
|
|
376
|
+
Returns
|
|
377
|
+
-------
|
|
378
|
+
dict[str, Scenario]
|
|
379
|
+
A dictionary where keys are scenario IDs and values are the corresponding
|
|
380
|
+
Scenario objects.
|
|
381
|
+
|
|
382
|
+
Raises
|
|
383
|
+
------
|
|
384
|
+
ValueError
|
|
385
|
+
If duplicate scenario IDs are found in the list.
|
|
386
|
+
|
|
387
|
+
Examples
|
|
388
|
+
--------
|
|
389
|
+
>>> from nextmv.cloud import Scenario, ScenarioInput, ScenarioInputType
|
|
390
|
+
>>> input_data = ScenarioInput(
|
|
391
|
+
... scenario_input_type=ScenarioInputType.INPUT_SET,
|
|
392
|
+
... scenario_input_data="input-set-id"
|
|
393
|
+
... )
|
|
394
|
+
>>> scenarios = [
|
|
395
|
+
... Scenario(scenario_input=input_data, instance_id="instance-1", scenario_id="test-1"),
|
|
396
|
+
... Scenario(scenario_input=input_data, instance_id="instance-2")
|
|
397
|
+
... ]
|
|
398
|
+
>>> result = _scenarios_by_id(scenarios)
|
|
399
|
+
>>> sorted(list(result.keys()))
|
|
400
|
+
['scenario-2', 'test-1']
|
|
216
401
|
"""
|
|
217
402
|
|
|
218
403
|
scenario_by_id = {}
|
nextmv/cloud/secrets.py
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
"""This module contains the declarations for secrets management.
|
|
1
|
+
"""This module contains the declarations for secrets management.
|
|
2
|
+
|
|
3
|
+
Classes
|
|
4
|
+
-------
|
|
5
|
+
SecretsCollectionSummary
|
|
6
|
+
Summary of a secrets collection in Nextmv Cloud.
|
|
7
|
+
SecretType
|
|
8
|
+
Enumeration of available secret types.
|
|
9
|
+
Secret
|
|
10
|
+
Representation of a sensitive piece of information.
|
|
11
|
+
SecretsCollection
|
|
12
|
+
Collection of secrets hosted in the Nextmv Cloud.
|
|
13
|
+
|
|
14
|
+
"""
|
|
2
15
|
|
|
3
16
|
from datetime import datetime
|
|
4
17
|
from enum import Enum
|
|
@@ -9,8 +22,48 @@ from nextmv.base_model import BaseModel
|
|
|
9
22
|
|
|
10
23
|
|
|
11
24
|
class SecretsCollectionSummary(BaseModel):
|
|
12
|
-
"""The summary of a secrets collection
|
|
13
|
-
|
|
25
|
+
"""The summary of a secrets collection in the Nextmv Cloud.
|
|
26
|
+
|
|
27
|
+
You can import the `SecretsCollectionSummary` class directly from `cloud`:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from nextmv.cloud import SecretsCollectionSummary
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
A secrets collection is a mechanism for hosting secrets securely in the
|
|
34
|
+
Nextmv Cloud. This class provides summary information about such a collection.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
collection_id : str
|
|
39
|
+
ID of the secrets collection. This is aliased from `id` for
|
|
40
|
+
serialization and validation.
|
|
41
|
+
application_id : str
|
|
42
|
+
ID of the application to which the secrets collection belongs.
|
|
43
|
+
name : str
|
|
44
|
+
Name of the secrets collection.
|
|
45
|
+
description : str
|
|
46
|
+
Description of the secrets collection.
|
|
47
|
+
created_at : datetime
|
|
48
|
+
Creation date of the secrets collection.
|
|
49
|
+
updated_at : datetime
|
|
50
|
+
Last update date of the secrets collection.
|
|
51
|
+
|
|
52
|
+
Examples
|
|
53
|
+
--------
|
|
54
|
+
>>> from datetime import datetime
|
|
55
|
+
>>> collection_summary = SecretsCollectionSummary(
|
|
56
|
+
... collection_id="col_123",
|
|
57
|
+
... application_id="app_456",
|
|
58
|
+
... name="My API Credentials",
|
|
59
|
+
... description="Collection of API keys for external services",
|
|
60
|
+
... created_at=datetime.now(),
|
|
61
|
+
... updated_at=datetime.now()
|
|
62
|
+
... )
|
|
63
|
+
>>> print(collection_summary.name)
|
|
64
|
+
My API Credentials
|
|
65
|
+
|
|
66
|
+
"""
|
|
14
67
|
|
|
15
68
|
collection_id: str = Field(
|
|
16
69
|
serialization_alias="id",
|
|
@@ -30,7 +83,37 @@ class SecretsCollectionSummary(BaseModel):
|
|
|
30
83
|
|
|
31
84
|
|
|
32
85
|
class SecretType(str, Enum):
|
|
33
|
-
"""Type of the secret that is stored in the Nextmv Cloud.
|
|
86
|
+
"""Type of the secret that is stored in the Nextmv Cloud.
|
|
87
|
+
|
|
88
|
+
You can import the `SecretType` class directly from `cloud`:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from nextmv.cloud import SecretType
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This enumeration defines the types of secrets that can be managed.
|
|
95
|
+
|
|
96
|
+
Attributes
|
|
97
|
+
----------
|
|
98
|
+
ENV : str
|
|
99
|
+
Represents an environment variable secret. The value of the secret
|
|
100
|
+
will be available as an environment variable in the execution
|
|
101
|
+
environment.
|
|
102
|
+
FILE : str
|
|
103
|
+
Represents a file-based secret. The value of the secret will be
|
|
104
|
+
written to a file, and the path to this file will be available
|
|
105
|
+
via the `location` attribute of the `Secret`.
|
|
106
|
+
|
|
107
|
+
Examples
|
|
108
|
+
--------
|
|
109
|
+
>>> secret_type_env = SecretType.ENV
|
|
110
|
+
>>> print(secret_type_env.value)
|
|
111
|
+
env
|
|
112
|
+
>>> secret_type_file = SecretType.FILE
|
|
113
|
+
>>> print(secret_type_file.value)
|
|
114
|
+
file
|
|
115
|
+
|
|
116
|
+
"""
|
|
34
117
|
|
|
35
118
|
ENV = "env"
|
|
36
119
|
"""Environment variable secret type."""
|
|
@@ -40,7 +123,49 @@ class SecretType(str, Enum):
|
|
|
40
123
|
|
|
41
124
|
class Secret(BaseModel):
|
|
42
125
|
"""A secret is a piece of sensitive information that is stored securely in
|
|
43
|
-
the Nextmv Cloud.
|
|
126
|
+
the Nextmv Cloud.
|
|
127
|
+
|
|
128
|
+
You can import the `Secret` class directly from `cloud`:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from nextmv.cloud import Secret
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This class represents an individual secret, detailing its type, location
|
|
135
|
+
(if applicable), and value.
|
|
136
|
+
|
|
137
|
+
Parameters
|
|
138
|
+
----------
|
|
139
|
+
secret_type : SecretType
|
|
140
|
+
The type of the secret, indicating how it should be handled (e.g.,
|
|
141
|
+
as an environment variable or a file). This is aliased from `type`
|
|
142
|
+
for serialization and validation.
|
|
143
|
+
location : str
|
|
144
|
+
The location where the secret will be made available. For `ENV`
|
|
145
|
+
type secrets, this is the name of the environment variable. For
|
|
146
|
+
`FILE` type secrets, this is the path where the file will be
|
|
147
|
+
created.
|
|
148
|
+
value : str
|
|
149
|
+
The actual content of the secret.
|
|
150
|
+
|
|
151
|
+
Examples
|
|
152
|
+
--------
|
|
153
|
+
>>> env_secret = Secret(
|
|
154
|
+
... secret_type=SecretType.ENV,
|
|
155
|
+
... location="API_KEY",
|
|
156
|
+
... value="supersecretapikey123"
|
|
157
|
+
... )
|
|
158
|
+
>>> print(env_secret.location)
|
|
159
|
+
API_KEY
|
|
160
|
+
>>> file_secret = Secret(
|
|
161
|
+
... secret_type=SecretType.FILE,
|
|
162
|
+
... location="/mnt/secrets/config.json",
|
|
163
|
+
... value=\'\'\'{"user": "admin", "pass": "secure"}\'\'\'
|
|
164
|
+
... )
|
|
165
|
+
>>> print(file_secret.secret_type)
|
|
166
|
+
SecretType.FILE
|
|
167
|
+
|
|
168
|
+
"""
|
|
44
169
|
|
|
45
170
|
secret_type: SecretType = Field(
|
|
46
171
|
serialization_alias="type",
|
|
@@ -55,7 +180,55 @@ class Secret(BaseModel):
|
|
|
55
180
|
|
|
56
181
|
class SecretsCollection(SecretsCollectionSummary, BaseModel):
|
|
57
182
|
"""A secrets collection is a mechanism for hosting secrets securely in the
|
|
58
|
-
Nextmv Cloud.
|
|
183
|
+
Nextmv Cloud.
|
|
184
|
+
|
|
185
|
+
You can import the `SecretsCollection` class directly from `cloud`:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from nextmv.cloud import SecretsCollection
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
This class extends `SecretsCollectionSummary` by including the actual list
|
|
192
|
+
of secrets contained within the collection.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
secrets : list[Secret]
|
|
197
|
+
A list of `Secret` objects that are part of this collection.
|
|
198
|
+
*args
|
|
199
|
+
Variable length argument list for `SecretsCollectionSummary`.
|
|
200
|
+
**kwargs
|
|
201
|
+
Arbitrary keyword arguments for `SecretsCollectionSummary`.
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
Examples
|
|
205
|
+
--------
|
|
206
|
+
>>> from datetime import datetime
|
|
207
|
+
>>> secret1 = Secret(
|
|
208
|
+
... secret_type=SecretType.ENV,
|
|
209
|
+
... location="DATABASE_USER",
|
|
210
|
+
... value="nextmv_user"
|
|
211
|
+
... )
|
|
212
|
+
>>> secret2 = Secret(
|
|
213
|
+
... secret_type=SecretType.FILE,
|
|
214
|
+
... location="/etc/app/license.key",
|
|
215
|
+
... value="longlicensekeystring"
|
|
216
|
+
... )
|
|
217
|
+
>>> full_collection = SecretsCollection(
|
|
218
|
+
... collection_id="col_789",
|
|
219
|
+
... application_id="app_000",
|
|
220
|
+
... name="Full App Secrets",
|
|
221
|
+
... description="All secrets required by the main application",
|
|
222
|
+
... created_at=datetime.now(),
|
|
223
|
+
... updated_at=datetime.now(),
|
|
224
|
+
... secrets=[secret1, secret2]
|
|
225
|
+
... )
|
|
226
|
+
>>> print(full_collection.name)
|
|
227
|
+
Full App Secrets
|
|
228
|
+
>>> print(len(full_collection.secrets))
|
|
229
|
+
2
|
|
230
|
+
|
|
231
|
+
"""
|
|
59
232
|
|
|
60
233
|
secrets: list[Secret]
|
|
61
234
|
"""List of secrets in the collection."""
|
nextmv/cloud/status.py
CHANGED
|
@@ -1,8 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provides status enums for Nextmv Cloud runs.
|
|
3
|
+
|
|
4
|
+
This module defines enumerations for representing the status of a run in
|
|
5
|
+
Nextmv Cloud. It includes a deprecated `Status` enum and the current `StatusV2`
|
|
6
|
+
enum.
|
|
7
|
+
|
|
8
|
+
Classes
|
|
9
|
+
-------
|
|
10
|
+
Status
|
|
11
|
+
Deprecated status of a run.
|
|
12
|
+
StatusV2
|
|
13
|
+
Represents the status of a run.
|
|
14
|
+
"""
|
|
15
|
+
|
|
1
16
|
from enum import Enum
|
|
2
17
|
|
|
3
18
|
|
|
4
19
|
class Status(str, Enum):
|
|
5
|
-
"""
|
|
20
|
+
"""
|
|
21
|
+
!!! warning
|
|
22
|
+
`Status` is deprecated, use `StatusV2` instead.
|
|
23
|
+
|
|
24
|
+
Status of a run.
|
|
25
|
+
|
|
26
|
+
You can import the `Status` class directly from `cloud`:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from nextmv.cloud import Status
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This enum represents the possible states of a run. It is deprecated and
|
|
33
|
+
`StatusV2` should be used for new implementations.
|
|
34
|
+
|
|
35
|
+
Attributes
|
|
36
|
+
----------
|
|
37
|
+
failed : str
|
|
38
|
+
Run failed.
|
|
39
|
+
running : str
|
|
40
|
+
Run is running.
|
|
41
|
+
succeeded : str
|
|
42
|
+
Run succeeded.
|
|
43
|
+
|
|
44
|
+
Examples
|
|
45
|
+
--------
|
|
46
|
+
>>> from nextmv.cloud import Status
|
|
47
|
+
>>> current_status = Status.running
|
|
48
|
+
>>> if current_status == Status.succeeded:
|
|
49
|
+
... print("Run completed successfully.")
|
|
50
|
+
... elif current_status == Status.failed:
|
|
51
|
+
... print("Run failed.")
|
|
52
|
+
... else:
|
|
53
|
+
... print(f"Run is currently {current_status.value}.")
|
|
54
|
+
Run is currently running.
|
|
55
|
+
|
|
56
|
+
"""
|
|
6
57
|
|
|
7
58
|
failed = "failed"
|
|
8
59
|
"""Run failed."""
|
|
@@ -13,7 +64,49 @@ class Status(str, Enum):
|
|
|
13
64
|
|
|
14
65
|
|
|
15
66
|
class StatusV2(str, Enum):
|
|
16
|
-
"""
|
|
67
|
+
"""
|
|
68
|
+
Status of a run.
|
|
69
|
+
|
|
70
|
+
You can import the `StatusV2` class directly from `cloud`:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from nextmv.cloud import StatusV2
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This enum represents the comprehensive set of possible states for a run
|
|
77
|
+
in Nextmv Cloud.
|
|
78
|
+
|
|
79
|
+
Attributes
|
|
80
|
+
----------
|
|
81
|
+
canceled : str
|
|
82
|
+
Run was canceled.
|
|
83
|
+
failed : str
|
|
84
|
+
Run failed.
|
|
85
|
+
none : str
|
|
86
|
+
Run has no status.
|
|
87
|
+
queued : str
|
|
88
|
+
Run is queued.
|
|
89
|
+
running : str
|
|
90
|
+
Run is running.
|
|
91
|
+
succeeded : str
|
|
92
|
+
Run succeeded.
|
|
93
|
+
|
|
94
|
+
Examples
|
|
95
|
+
--------
|
|
96
|
+
>>> from nextmv.cloud import StatusV2
|
|
97
|
+
>>> run_status = StatusV2.queued
|
|
98
|
+
>>> print(f"The run status is: {run_status.value}")
|
|
99
|
+
The run status is: queued
|
|
100
|
+
|
|
101
|
+
>>> if run_status == StatusV2.succeeded:
|
|
102
|
+
... print("Processing complete.")
|
|
103
|
+
... elif run_status in [StatusV2.queued, StatusV2.running]:
|
|
104
|
+
... print("Processing in progress.")
|
|
105
|
+
... else:
|
|
106
|
+
... print("Processing has not started or has ended with issues.")
|
|
107
|
+
Processing in progress.
|
|
108
|
+
|
|
109
|
+
"""
|
|
17
110
|
|
|
18
111
|
canceled = "canceled"
|
|
19
112
|
"""Run was canceled."""
|