yellowdog-python-examples 8.1.2__tar.gz → 8.1.4__tar.gz
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.
- {yellowdog_python_examples-8.1.2/yellowdog_python_examples.egg-info → yellowdog_python_examples-8.1.4}/PKG-INFO +2 -2
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/README.md +26 -26
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/requirements.txt +1 -1
- yellowdog_python_examples-8.1.4/yellowdog_cli/__init__.py +1 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/cancel.py +1 -4
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/create.py +27 -37
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/finish.py +1 -4
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/instantiate.py +5 -5
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/provision.py +4 -4
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/remove.py +15 -15
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/entity_utils.py +214 -129
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/provision_utils.py +8 -29
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4/yellowdog_python_examples.egg-info}/PKG-INFO +2 -2
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_python_examples.egg-info/requires.txt +1 -1
- yellowdog_python_examples-8.1.2/yellowdog_cli/__init__.py +0 -1
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/LICENSE +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/PYPI_README.md +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/pyproject.toml +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/setup.cfg +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/tests/test_create_remove.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/tests/test_demos.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/tests/test_dryruns.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/tests/test_entrypoints.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/tests/test_gui.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/tests/test_list.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/tests/test_objects.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/tests/test_variable_processing.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/abort.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/admin.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/boost.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/cloudwizard.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/compare.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/delete.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/download.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/follow.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/format_json.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/hold.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/jsonnet2json.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/list.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/resize.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/show.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/shutdown.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/start.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/submit.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/terminate.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/upload.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/__init__.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/args.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/check_imports.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/cloudwizard_aws.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/cloudwizard_aws_types.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/cloudwizard_azure.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/cloudwizard_common.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/cloudwizard_gcp.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/compact_json.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/config_types.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/csv_data.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/follow_utils.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/interactive.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/items.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/load_config.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/load_resources.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/misc_utils.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/printing.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/property_names.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/rich_console_input_fixed.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/settings.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/start_hold_common.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/submit_utils.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/type_check.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/upload_utils.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/validate_properties.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/variables.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/wrapper.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/utils/ydid_utils.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/version.py +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_python_examples.egg-info/SOURCES.txt +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_python_examples.egg-info/dependency_links.txt +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_python_examples.egg-info/entry_points.txt +0 -0
- {yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_python_examples.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yellowdog-python-examples
|
|
3
|
-
Version: 8.1.
|
|
3
|
+
Version: 8.1.4
|
|
4
4
|
Summary: Python CLI commands using the YellowDog Python SDK
|
|
5
5
|
Author-email: YellowDog Limited <support@yellowdog.co>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -26,7 +26,7 @@ Requires-Dist: requests
|
|
|
26
26
|
Requires-Dist: rich==13.9.4
|
|
27
27
|
Requires-Dist: tabulate>=0.9.0
|
|
28
28
|
Requires-Dist: toml
|
|
29
|
-
Requires-Dist: yellowdog-sdk>=11.
|
|
29
|
+
Requires-Dist: yellowdog-sdk>=11.6.0
|
|
30
30
|
Provides-Extra: jsonnet
|
|
31
31
|
Requires-Dist: jsonnet; extra == "jsonnet"
|
|
32
32
|
Provides-Extra: cloudwizard
|
|
@@ -417,9 +417,9 @@ Variable substitutions are discussed in more detail below.
|
|
|
417
417
|
|
|
418
418
|
# Variable Substitutions
|
|
419
419
|
|
|
420
|
-
Variable substitutions provide a powerful mechanism for introducing variable values into TOML configuration files, and JSON/Jsonnet definitions
|
|
420
|
+
Variable substitutions provide a powerful mechanism for introducing variable values into TOML configuration files, and JSON/Jsonnet definitions. They can be included in the value of any property in any of these objects, including in values within arrays (lists), e.g., for the `arguments` property, and tables (dictionaries), e.g., the `environment` property.
|
|
421
421
|
|
|
422
|
-
Variable substitutions are expressed using the `{{variable}}` notation, where the expression is replaced by the value of `variable`.
|
|
422
|
+
Variable substitutions are expressed using the `{{variable}}` notation (note: no spaces between the double brackets and the variable name), where the expression is replaced by the value of `variable`.
|
|
423
423
|
|
|
424
424
|
Substitutions can also be performed for non-string (number, boolean, array, and table) values using the `num:`, `bool:`, `array:`, and `table:` prefixes within the variable substitution:
|
|
425
425
|
|
|
@@ -493,7 +493,7 @@ The precedence order for setting variables is:
|
|
|
493
493
|
4. General environment variables
|
|
494
494
|
5. Variables in a `.env` file
|
|
495
495
|
|
|
496
|
-
This method can also be used to override
|
|
496
|
+
This method can also be used to override some default variables, e.g., setting `-v username="other-user"` will override the default `{{username}}` variable.
|
|
497
497
|
|
|
498
498
|
### Nested Variables
|
|
499
499
|
|
|
@@ -547,7 +547,7 @@ name = "{{name_var:={{tag}}-{{datetime}}}}"
|
|
|
547
547
|
|
|
548
548
|
## Variable Substitutions in Worker Pool and Compute Requirement Specifications, and in User Data
|
|
549
549
|
|
|
550
|
-
In JSON specifications for Worker Pools and Compute Requirements, variable substitutions
|
|
550
|
+
In JSON/Jsonnet specifications for Worker Pools and Compute Requirements, variable substitutions **must be prefixed and postfixed by double underscores** `__`, e.g., `__{{username}}__`. This is to disambiguate client-side variable substitutions from server-side Mustache variable processing.
|
|
551
551
|
|
|
552
552
|
Variable substitutions can also be used within **User Data** to be supplied to instances, for which the same prefix/postfix requirement applies, **including** for User Data supplied directly using the `userData` property in the `workerPool` section of the TOML file.
|
|
553
553
|
|
|
@@ -1693,7 +1693,7 @@ The following properties are available:
|
|
|
1693
1693
|
|:------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------|:------------------------|
|
|
1694
1694
|
| `idleNodeTimeout` | The timeout in minutes after which an idle node will be shut down. Set this to `0` to disable the timeout. | `5.0` |
|
|
1695
1695
|
| `idlePoolTimeout` | The timeout in minutes after which an idle Worker Pool will be shut down. Set this to `0` to disable the timeout. | `30.0` |
|
|
1696
|
-
| `imagesId` | The
|
|
1696
|
+
| `imagesId` | The Image ID, Image Family ID, Image Family name, or Image Group name to use when booting instances. | |
|
|
1697
1697
|
| `instanceTags` | The dictionary of instance tags to apply to the instances. Tag names must be lower case. | |
|
|
1698
1698
|
| `maintainInstanceCount` | Only used when instantiating Compute Requirements; attempt to maintain the requested number of instances. | `False` |
|
|
1699
1699
|
| `maxNodes` | The maximum number of nodes to which the Worker Pool can be scaled up. | `1` |
|
|
@@ -1717,7 +1717,7 @@ The following properties are available:
|
|
|
1717
1717
|
|
|
1718
1718
|
The `templateId` property can be directly populated with the YellowDog ID (YDID), or it can be populated with the textual name of the template, in the form `namespace/template_name`.
|
|
1719
1719
|
|
|
1720
|
-
Similarly, the `imagesId` property can be populated with the YDID of an Image Family, Image Group, Image, or a string representing the native name of a cloud provider image (e.g., an AWS AMI). It can also be populated with
|
|
1720
|
+
Similarly, the `imagesId` property can be populated with the YDID of an Image Family, Image Group, Image, or a string representing the native name of a cloud provider image (e.g., an AWS AMI). It can also be populated with an Image Family name in the form `namespace/image_family_name`, or an Image Group name in the form `namespace/image_family_name/image_group_name` or `image_family_name/image_group_name`. Optionally, a `yd/` prefix can be supplied. The CLI will aim to map the provided name into an Image Family or Group YDID.
|
|
1721
1721
|
|
|
1722
1722
|
## Automatic Properties
|
|
1723
1723
|
|
|
@@ -1893,7 +1893,7 @@ When a JSON Worker Pool specification is used, the following properties from the
|
|
|
1893
1893
|
- `userDataFile`
|
|
1894
1894
|
- `userDataFiles`
|
|
1895
1895
|
|
|
1896
|
-
Note that the `templateId` property can use either the YellowDog ID ('YDID') for the Compute Requirement Template, or its name. Similarly, the `imagesId` property can use either a YDID or the Image Family
|
|
1896
|
+
Note that the `templateId` property can use either the YellowDog ID ('YDID') for the Compute Requirement Template, or its name. Similarly, the `imagesId` property can use either a YDID or the Image Family or Image Group name (e.g, `"yd-agent-docker"`).
|
|
1897
1897
|
|
|
1898
1898
|
**Properties Inherited within the `provisionedProperties` Property**
|
|
1899
1899
|
|
|
@@ -1990,7 +1990,7 @@ yd-remove --ids ydid:crt:D9C548:2a09093d-c74c-4bde-95d1-c576c6f03b13 ydid:imgfam
|
|
|
1990
1990
|
|
|
1991
1991
|
### Resource Matching
|
|
1992
1992
|
|
|
1993
|
-
Resources match on **resource names** and (where applicable) **resource namespaces** rather than on YellowDog IDs. This is done for flexibility and to allow the `yd-create` and `yd-remove` commands to be
|
|
1993
|
+
Resources match on **resource names** and (where applicable) **resource namespaces** rather than on YellowDog IDs. This is done for flexibility and to allow the `yd-create` and `yd-remove` commands to be stateless (i.e., we don't need to keep a local record of the YellowDog IDs of the resources created).
|
|
1994
1994
|
|
|
1995
1995
|
However, this means that **caution is required** when updating or removing resources, since resource matching is done using **only** the **namespace/name** of the resource -- i.e., the system-generated `ydid` IDs are not used. This means that a resource with a given name could have been removed and replaced in Platform by some other means, and the resource specification(s) would still match it.
|
|
1996
1996
|
|
|
@@ -1998,7 +1998,7 @@ However, this means that **caution is required** when updating or removing resou
|
|
|
1998
1998
|
|
|
1999
1999
|
The JSON specification used to define each type of resource can be found by inspecting the YellowDog Platform REST API documentation at https://docs.yellowdog.co/api.
|
|
2000
2000
|
|
|
2001
|
-
For example, to obtain the JSON schema for creating a Compute Source Template, take a look at the REST API
|
|
2001
|
+
For example, to obtain the JSON schema for creating a Compute Source Template, take a look at the REST API models for the Compute API: https://docs.yellowdog.ai/api?spec=Compute%20API.
|
|
2002
2002
|
|
|
2003
2003
|
When using the `yd-create` and `yd-remove` commands, note that an additional property `resource` must be supplied, to identify the type of resource being specified. The `"resource"` property can take the following values:
|
|
2004
2004
|
|
|
@@ -2043,7 +2043,7 @@ yd-show -q ydid:cst:000000:cde265f8-0b17-4e0e-be1c-505174a620e4 --substitute-ids
|
|
|
2043
2043
|
|
|
2044
2044
|
would generate a JSON file that can be used with `yd-create` without alteration, or which could be edited.
|
|
2045
2045
|
|
|
2046
|
-
As illustrated above, both `yd-list` and `yd-show` support the `--substitute-ids`/`-U` option. For Compute Requirement Template detailed output, this will substitute Compute Source Template IDs and Image Family IDs with their names, to make it easier to reuse the outputs. For Compute Source Templates, Image Family
|
|
2046
|
+
As illustrated above, both `yd-list` and `yd-show` support the `--substitute-ids`/`-U` option. For Compute Requirement Template detailed output, this will substitute Compute Source Template IDs and Image Family and Group IDs with their names, to make it easier to reuse the outputs. For Compute Source Templates, Image Family and Group IDs will be substituted.
|
|
2047
2047
|
|
|
2048
2048
|
The `--strip-ids` option will remove any YellowDog IDs ('ydids') from the JSON output, as well as any other properties that are not required in order to use the output with `yd-create`.
|
|
2049
2049
|
|
|
@@ -2088,7 +2088,7 @@ Below, we'll discuss each item type with example specifications.
|
|
|
2088
2088
|
|
|
2089
2089
|
## Keyrings
|
|
2090
2090
|
|
|
2091
|
-
The Keyring
|
|
2091
|
+
The Keyring models can be found in the Account API at: https://docs.yellowdog.ai/api?spec=Account%20API.
|
|
2092
2092
|
|
|
2093
2093
|
An example Keyring specification is shown below:
|
|
2094
2094
|
|
|
@@ -2116,7 +2116,7 @@ Note that Keyrings **cannot be updated**; they must instead be removed and recre
|
|
|
2116
2116
|
|
|
2117
2117
|
## Credentials
|
|
2118
2118
|
|
|
2119
|
-
The Credential
|
|
2119
|
+
The Credential models can be found in the Account API at: https://docs.yellowdog.ai/api?spec=Account%20API.
|
|
2120
2120
|
|
|
2121
2121
|
For example, to add a single AWS credential to a Keyring, the following resource specification might be used:
|
|
2122
2122
|
|
|
@@ -2137,7 +2137,7 @@ To **update** a Credential, make the modifications to the resource specification
|
|
|
2137
2137
|
|
|
2138
2138
|
## Compute Source Templates
|
|
2139
2139
|
|
|
2140
|
-
The Compute Source Template
|
|
2140
|
+
The Compute Source Template models can be found in the Compute API at: https://docs.yellowdog.ai/api?spec=Compute%20API.
|
|
2141
2141
|
|
|
2142
2142
|
An example Compute Source resource specification is found below:
|
|
2143
2143
|
|
|
@@ -2171,11 +2171,11 @@ An example Compute Source resource specification is found below:
|
|
|
2171
2171
|
}
|
|
2172
2172
|
```
|
|
2173
2173
|
|
|
2174
|
-
In the Compute Source Template `imageId` property, an Image Family **namespace/name** may be used instead of an ID. For example: `"imageId": "yellowdog/yd-agent-docker"`. The `yd-create` command will look up the Image Family name and substitute
|
|
2174
|
+
In the Compute Source Template `imageId` property, an Image Family name **namespace/family-name** or Image Group name **namespace/family-name/group-name** may be used instead of an ID. For example: `"imageId": "yellowdog/yd-agent-docker"`. The `yd-create` command will look up the Image Family name and substitute with a well-formed name or ID. A **`yd/`** prefix may also optionally be used.
|
|
2175
2175
|
|
|
2176
2176
|
## Compute Requirement Templates
|
|
2177
2177
|
|
|
2178
|
-
The Compute Requirement Template
|
|
2178
|
+
The Compute Requirement Template models can be found in the Compute API at: https://docs.yellowdog.ai/api?spec=Compute%20API.
|
|
2179
2179
|
|
|
2180
2180
|
An example Compute Requirement resource specification is found below, for a **static** tempate:
|
|
2181
2181
|
|
|
@@ -2197,7 +2197,7 @@ An example Compute Requirement resource specification is found below, for a **st
|
|
|
2197
2197
|
|
|
2198
2198
|
Note that Compute Source Template **namespace/names** in the form `namespace/compute_source_template_name` can be used instead of their IDs: the **yd-create** command will look up the IDs and make the substitutions. The Compute Source Templates must already exist.
|
|
2199
2199
|
|
|
2200
|
-
Also, In the `imagesId` property, an Image Family **namespace/name** may be used instead of an ID. For example: `"imagesId": "yellowdog/yd-agent-docker"`. The `yd-create` command will look up the Image Family name and substitute
|
|
2200
|
+
Also, In the `imagesId` property, an Image Family name **namespace/family-name** or an Image Group name **namespace/family-name/group-name** may be used instead of an ID. For example: `"imagesId": "yellowdog/yd-agent-docker/latest"`. The `yd-create` command will look up the Image Family name and substitute with a well-formed name or ID. A **`yd/`** prefix may also optionally be used.
|
|
2201
2201
|
|
|
2202
2202
|
A **dynamic** template example is:
|
|
2203
2203
|
|
|
@@ -2252,7 +2252,7 @@ A **dynamic** template example is:
|
|
|
2252
2252
|
|
|
2253
2253
|
## Image Families
|
|
2254
2254
|
|
|
2255
|
-
The Image Family
|
|
2255
|
+
The Image Family models can be found in the Image API: https://docs.yellowdog.ai/api?spec=Images%20API.
|
|
2256
2256
|
|
|
2257
2257
|
An example specification, illustrating a containment hierarchy of Image Family -> Image Group -> Image, is shown below:
|
|
2258
2258
|
|
|
@@ -2298,7 +2298,7 @@ Note that if the name of an Image Group or an Image is changed in the resource s
|
|
|
2298
2298
|
|
|
2299
2299
|
## Namespace Storage Configurations
|
|
2300
2300
|
|
|
2301
|
-
The Namespace Storage Configuration
|
|
2301
|
+
The Namespace Storage Configuration models can be found in the Object Store API at: https://docs.yellowdog.ai/api?spec=Object%20Store%20API.
|
|
2302
2302
|
|
|
2303
2303
|
Example:
|
|
2304
2304
|
|
|
@@ -2315,7 +2315,7 @@ Example:
|
|
|
2315
2315
|
|
|
2316
2316
|
## Configured Worker Pools
|
|
2317
2317
|
|
|
2318
|
-
The Configured Worker Pool
|
|
2318
|
+
The Configured Worker Pool models can be found in the Scheduler API at: https://docs.yellowdog.ai/api?spec=Scheduler%20API.
|
|
2319
2319
|
|
|
2320
2320
|
Example:
|
|
2321
2321
|
|
|
@@ -2346,7 +2346,7 @@ Example:
|
|
|
2346
2346
|
|
|
2347
2347
|
## Allowances
|
|
2348
2348
|
|
|
2349
|
-
The
|
|
2349
|
+
The Allowance models can be found in the Usage API at: https://docs.yellowdog.ai/api?spec=Usage%20API.
|
|
2350
2350
|
|
|
2351
2351
|
Example:
|
|
2352
2352
|
```json
|
|
@@ -2378,7 +2378,7 @@ Allowances can be **boosted** (have extra hours added to the Allowance) using th
|
|
|
2378
2378
|
|
|
2379
2379
|
## Attribute Definitions
|
|
2380
2380
|
|
|
2381
|
-
The Attribute Definition
|
|
2381
|
+
The Attribute Definition models can be found in the Compute API at: https://docs.yellowdog.ai/api?spec=Compute%20API.
|
|
2382
2382
|
|
|
2383
2383
|
### String Attribute Definitions
|
|
2384
2384
|
|
|
@@ -2416,7 +2416,7 @@ The `name`, `title` and `defaultRankOrder` properties are required, while the re
|
|
|
2416
2416
|
|
|
2417
2417
|
## Namespace Policies
|
|
2418
2418
|
|
|
2419
|
-
|
|
2419
|
+
Example:
|
|
2420
2420
|
|
|
2421
2421
|
```json
|
|
2422
2422
|
{
|
|
@@ -2475,7 +2475,7 @@ Example:
|
|
|
2475
2475
|
|
|
2476
2476
|
### Creating and Regenerating Application Keys
|
|
2477
2477
|
|
|
2478
|
-
When an Application is created its Application Key ID and Secret will be displayed (even if the `--quiet` option is used).
|
|
2478
|
+
When an Application is created, its Application Key ID and Secret will be displayed (even if the `--quiet` option is used).
|
|
2479
2479
|
|
|
2480
2480
|
When an Application is updated, the `--regenerate-app-keys` option can be used. This will invalidate the current Application key and secret, revoke any Keyring access, and generate a new key and secret which will be displayed.
|
|
2481
2481
|
|
|
@@ -2539,11 +2539,11 @@ A simple usage example might be:
|
|
|
2539
2539
|
yd-submit my_work_req.jsonnet
|
|
2540
2540
|
```
|
|
2541
2541
|
|
|
2542
|
-
The use of the filename extension `.jsonnet` will
|
|
2542
|
+
The use of the filename extension `.jsonnet` will activate Jsonnet evaluation. (Note that a temporary JSON file is created as part of Jsonnet processing, which you may see referred to in error messages: this file will have been deleted before the command exits.)
|
|
2543
2543
|
|
|
2544
2544
|
## Jsonnet Installation
|
|
2545
2545
|
|
|
2546
|
-
Jsonnet is **not** installed by default when `yellowdog-python-examples`
|
|
2546
|
+
Jsonnet is **not** installed by default when `yellowdog-python-examples` because the package has binary components that are not available on PyPI for all platforms. If you try to use a Jsonnet file in the absence of Jsonnet, the scripts will print an error message, and suggest an installation mechanism.
|
|
2547
2547
|
|
|
2548
2548
|
To install Jsonnet at the same time as installing or updating the Python Examples scripts, modify the installation as follows to include the `jsonnet` option:
|
|
2549
2549
|
|
|
@@ -2551,7 +2551,7 @@ To install Jsonnet at the same time as installing or updating the Python Example
|
|
|
2551
2551
|
pip install -U "yellowdog-python-examples[jsonnet]"
|
|
2552
2552
|
```
|
|
2553
2553
|
|
|
2554
|
-
To install Jsonnet separately from `yellowdog-python-examples`,
|
|
2554
|
+
To install Jsonnet separately from `yellowdog-python-examples`, use:
|
|
2555
2555
|
|
|
2556
2556
|
```shell
|
|
2557
2557
|
pip install -U jsonnet
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "8.1.4"
|
|
@@ -132,10 +132,7 @@ def _cancel_work_requirements_by_name_or_id(names_or_ids: List[str]):
|
|
|
132
132
|
)
|
|
133
133
|
)
|
|
134
134
|
if work_requirement_summary is None:
|
|
135
|
-
print_error(
|
|
136
|
-
f"Work Requirement '{name_or_id}' not found in "
|
|
137
|
-
f"namespace '{CONFIG_COMMON.namespace}'"
|
|
138
|
-
)
|
|
135
|
+
print_error(f"Work Requirement '{name_or_id}' not found")
|
|
139
136
|
continue
|
|
140
137
|
|
|
141
138
|
if work_requirement_summary.status not in [
|
|
@@ -50,10 +50,10 @@ from yellowdog_cli.utils.entity_utils import (
|
|
|
50
50
|
clear_application_caches,
|
|
51
51
|
clear_compute_source_template_cache,
|
|
52
52
|
clear_group_caches,
|
|
53
|
-
|
|
53
|
+
clear_image_caches,
|
|
54
54
|
find_compute_requirement_template_id_by_name,
|
|
55
55
|
find_compute_source_template_id_by_name,
|
|
56
|
-
|
|
56
|
+
find_image_name_or_id,
|
|
57
57
|
get_application_groups,
|
|
58
58
|
get_application_id_by_name,
|
|
59
59
|
get_group_id_by_name,
|
|
@@ -130,7 +130,9 @@ from yellowdog_cli.utils.wrapper import ARGS_PARSER, CLIENT, CONFIG_COMMON, main
|
|
|
130
130
|
from yellowdog_cli.utils.ydid_utils import YDIDType, get_ydid_type
|
|
131
131
|
|
|
132
132
|
CLEAR_CST_CACHE: bool = False # Track whether the CST cache needs to be cleared
|
|
133
|
-
CLEAR_IMAGE_FAMILY_CACHE: bool =
|
|
133
|
+
CLEAR_IMAGE_FAMILY_CACHE: bool = (
|
|
134
|
+
False # Track whether the image caches need to be cleared
|
|
135
|
+
)
|
|
134
136
|
|
|
135
137
|
|
|
136
138
|
@main_wrapper
|
|
@@ -233,7 +235,7 @@ def create_compute_source_template(resource: Dict):
|
|
|
233
235
|
# Allow image families (etc.) to be referenced by name rather than ID
|
|
234
236
|
global CLEAR_IMAGE_FAMILY_CACHE
|
|
235
237
|
if CLEAR_IMAGE_FAMILY_CACHE: # Update the IF cache if required
|
|
236
|
-
|
|
238
|
+
clear_image_caches()
|
|
237
239
|
CLEAR_IMAGE_FAMILY_CACHE = False
|
|
238
240
|
|
|
239
241
|
# Google CSTs use property name 'image' instead of 'imageId'
|
|
@@ -244,17 +246,14 @@ def create_compute_source_template(resource: Dict):
|
|
|
244
246
|
else PROP_IMAGE
|
|
245
247
|
)
|
|
246
248
|
|
|
247
|
-
image_id =
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
)
|
|
256
|
-
if image_family_id is not None:
|
|
257
|
-
source[image_property_name] = image_family_id
|
|
249
|
+
image_id = find_image_name_or_id(
|
|
250
|
+
client=CLIENT,
|
|
251
|
+
image_name_or_id=source.get(image_property_name),
|
|
252
|
+
always_return_id=False,
|
|
253
|
+
report_substitutions=True,
|
|
254
|
+
)
|
|
255
|
+
if image_id is not None:
|
|
256
|
+
source[image_property_name] = image_id
|
|
258
257
|
|
|
259
258
|
if ARGS_PARSER.dry_run:
|
|
260
259
|
resource[PROP_SOURCE] = source
|
|
@@ -322,31 +321,26 @@ def create_compute_requirement_template(resource: Dict):
|
|
|
322
321
|
# Allow image families to be referenced by name rather than ID
|
|
323
322
|
global CLEAR_IMAGE_FAMILY_CACHE
|
|
324
323
|
if CLEAR_IMAGE_FAMILY_CACHE: # Update the IF cache if required
|
|
325
|
-
|
|
324
|
+
clear_image_caches()
|
|
326
325
|
CLEAR_IMAGE_FAMILY_CACHE = False
|
|
327
326
|
|
|
328
|
-
def _get_images_id(image_str: str, context: Dict, key: str)
|
|
327
|
+
def _get_images_id(image_str: str, context: Dict, key: str):
|
|
329
328
|
"""
|
|
330
|
-
Helper function to
|
|
329
|
+
Helper function to resolve an image ID.
|
|
331
330
|
"""
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
if image_family_id is not None:
|
|
341
|
-
context[key] = image_family_id
|
|
342
|
-
return 1
|
|
343
|
-
return 0
|
|
331
|
+
images_id_ = find_image_name_or_id(
|
|
332
|
+
client=CLIENT,
|
|
333
|
+
image_name_or_id=image_str,
|
|
334
|
+
always_return_id=False,
|
|
335
|
+
report_substitutions=True,
|
|
336
|
+
)
|
|
337
|
+
if images_id_ is not None:
|
|
338
|
+
context[key] = images_id_
|
|
344
339
|
|
|
345
340
|
# Prepend the namespace when searching for existing templates
|
|
346
341
|
name = f"{namespace}{NAMESPACE_PREFIX_SEPARATOR}{name}"
|
|
347
342
|
|
|
348
343
|
source_template_substitutions = 0
|
|
349
|
-
source_image_id_substitutions = 0
|
|
350
344
|
|
|
351
345
|
# Dynamic templates don't have 'sources'; return '[]'
|
|
352
346
|
for source in resource.get(PROP_SOURCES, []):
|
|
@@ -365,16 +359,12 @@ def create_compute_requirement_template(resource: Dict):
|
|
|
365
359
|
|
|
366
360
|
source_image_id = source.get(PROP_IMAGE_ID)
|
|
367
361
|
if source_image_id is not None:
|
|
368
|
-
|
|
369
|
-
source_image_id, source, PROP_IMAGE_ID
|
|
370
|
-
)
|
|
362
|
+
_get_images_id(source_image_id, source, PROP_IMAGE_ID)
|
|
371
363
|
|
|
372
364
|
if source_template_substitutions > 0:
|
|
373
365
|
print_log(
|
|
374
366
|
f"Replaced {source_template_substitutions} Compute Source Template name(s) with ID(s)"
|
|
375
367
|
)
|
|
376
|
-
if source_image_id_substitutions > 0:
|
|
377
|
-
print_log(f"Replaced {source_image_id_substitutions} Image name(s) with ID(s)")
|
|
378
368
|
|
|
379
369
|
images_id = resource.get(PROP_IMAGES_ID)
|
|
380
370
|
if images_id is not None:
|
|
@@ -549,7 +539,7 @@ def create_image_family(resource):
|
|
|
549
539
|
# This will create the Image Family and all of its constituent
|
|
550
540
|
# Image Group/Image resources
|
|
551
541
|
image_family = _create_image_family(image_family, fq_name)
|
|
552
|
-
print_log(f"Created Machine Image Family '{fq_name}' (
|
|
542
|
+
print_log(f"Created Machine Image Family '{fq_name}' ({image_family.id})")
|
|
553
543
|
if ARGS_PARSER.quiet:
|
|
554
544
|
print(image_family.id)
|
|
555
545
|
else:
|
|
@@ -114,10 +114,7 @@ def _finish_work_requirements_by_name_or_id(names_or_ids: List[str]):
|
|
|
114
114
|
)
|
|
115
115
|
)
|
|
116
116
|
if work_requirement_summary is None:
|
|
117
|
-
print_error(
|
|
118
|
-
f"Work Requirement '{name_or_id}' not found in "
|
|
119
|
-
f"namespace '{CONFIG_COMMON.namespace}'"
|
|
120
|
-
)
|
|
117
|
+
print_error(f"Work Requirement '{name_or_id}' not found")
|
|
121
118
|
continue
|
|
122
119
|
|
|
123
120
|
if work_requirement_summary.status not in [
|
{yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/instantiate.py
RENAMED
|
@@ -30,7 +30,7 @@ from yellowdog_cli.utils.printing import (
|
|
|
30
30
|
print_yd_object,
|
|
31
31
|
)
|
|
32
32
|
from yellowdog_cli.utils.provision_utils import (
|
|
33
|
-
|
|
33
|
+
get_image_id,
|
|
34
34
|
get_template_id,
|
|
35
35
|
get_user_data_property,
|
|
36
36
|
)
|
|
@@ -92,8 +92,8 @@ def main():
|
|
|
92
92
|
|
|
93
93
|
# Allow use of IF name instead of ID
|
|
94
94
|
if CONFIG_WP.images_id is not None:
|
|
95
|
-
CONFIG_WP.images_id =
|
|
96
|
-
client=CLIENT,
|
|
95
|
+
CONFIG_WP.images_id = get_image_id(
|
|
96
|
+
client=CLIENT, image_name_or_id=CONFIG_WP.images_id
|
|
97
97
|
)
|
|
98
98
|
|
|
99
99
|
if not ARGS_PARSER.report:
|
|
@@ -303,8 +303,8 @@ def _create_compute_requirement_from_json(
|
|
|
303
303
|
|
|
304
304
|
# Allow use of IF name instead of ID
|
|
305
305
|
if cr_data.get("imagesId") is not None:
|
|
306
|
-
cr_data["imagesId"] =
|
|
307
|
-
client=CLIENT,
|
|
306
|
+
cr_data["imagesId"] = get_image_id(
|
|
307
|
+
client=CLIENT, image_name_or_id=cr_data["imagesId"]
|
|
308
308
|
)
|
|
309
309
|
|
|
310
310
|
if ARGS_PARSER.dry_run:
|
{yellowdog_python_examples-8.1.2 → yellowdog_python_examples-8.1.4}/yellowdog_cli/provision.py
RENAMED
|
@@ -47,7 +47,7 @@ from yellowdog_cli.utils.property_names import (
|
|
|
47
47
|
WORKER_TAG,
|
|
48
48
|
)
|
|
49
49
|
from yellowdog_cli.utils.provision_utils import (
|
|
50
|
-
|
|
50
|
+
get_image_id,
|
|
51
51
|
get_template_id,
|
|
52
52
|
get_user_data_property,
|
|
53
53
|
)
|
|
@@ -170,7 +170,7 @@ def create_worker_pool_from_json(wp_json_file: str) -> None:
|
|
|
170
170
|
|
|
171
171
|
# Allow Image Family name to be used instead of ID
|
|
172
172
|
if reqt_template_usage.get(IMAGES_ID) is not None:
|
|
173
|
-
reqt_template_usage[IMAGES_ID] =
|
|
173
|
+
reqt_template_usage[IMAGES_ID] = get_image_id(
|
|
174
174
|
CLIENT, reqt_template_usage[IMAGES_ID]
|
|
175
175
|
)
|
|
176
176
|
|
|
@@ -289,8 +289,8 @@ def create_worker_pool_from_toml():
|
|
|
289
289
|
|
|
290
290
|
# Allow the Image Family name to be used instead of ID
|
|
291
291
|
if CONFIG_WP.images_id is not None:
|
|
292
|
-
CONFIG_WP.images_id =
|
|
293
|
-
client=CLIENT,
|
|
292
|
+
CONFIG_WP.images_id = get_image_id(
|
|
293
|
+
client=CLIENT, image_name_or_id=CONFIG_WP.images_id
|
|
294
294
|
)
|
|
295
295
|
|
|
296
296
|
node_boot_timeout = (
|
|
@@ -207,17 +207,17 @@ def remove_keyring(resource: Dict):
|
|
|
207
207
|
print_error(f"Expected property to be defined ({e})")
|
|
208
208
|
return
|
|
209
209
|
|
|
210
|
-
if not confirmed(f"
|
|
210
|
+
if not confirmed(f"Remove Keyring '{name}'?"):
|
|
211
211
|
return
|
|
212
212
|
|
|
213
213
|
try:
|
|
214
214
|
CLIENT.keyring_client.delete_keyring_by_name(name)
|
|
215
|
-
print_log(f"
|
|
215
|
+
print_log(f"Removed Keyring '{name}'")
|
|
216
216
|
except HTTPError as e:
|
|
217
217
|
if e.response.status_code == 404:
|
|
218
|
-
print_error(f"Keyring '{name}'
|
|
218
|
+
print_error(f"Cannot find Keyring '{name}'")
|
|
219
219
|
else:
|
|
220
|
-
print_error(f"Unable to
|
|
220
|
+
print_error(f"Unable to remove Keyring '{name}': {e}")
|
|
221
221
|
|
|
222
222
|
|
|
223
223
|
def remove_credential(resource: Dict):
|
|
@@ -246,7 +246,7 @@ def remove_credential(resource: Dict):
|
|
|
246
246
|
except HTTPError as e:
|
|
247
247
|
if e.response.status_code == 404:
|
|
248
248
|
print_error(
|
|
249
|
-
f"Keyring '{keyring_name}'
|
|
249
|
+
f"Cannot find Keyring '{keyring_name}'(possibly already deleted,"
|
|
250
250
|
" including its credentials?)"
|
|
251
251
|
)
|
|
252
252
|
else:
|
|
@@ -275,7 +275,7 @@ def remove_image_family(resource: Dict):
|
|
|
275
275
|
)
|
|
276
276
|
except HTTPError as e:
|
|
277
277
|
if e.response.status_code == 404:
|
|
278
|
-
print_error(f"Machine Image Family '{fq_name}'
|
|
278
|
+
print_error(f"Cannot find Machine Image Family '{fq_name}'")
|
|
279
279
|
return
|
|
280
280
|
else:
|
|
281
281
|
raise e
|
|
@@ -285,9 +285,9 @@ def remove_image_family(resource: Dict):
|
|
|
285
285
|
|
|
286
286
|
try:
|
|
287
287
|
CLIENT.images_client.delete_image_family(image_family)
|
|
288
|
-
print_log(f"
|
|
288
|
+
print_log(f"Removed Image Family '{fq_name}' ({image_family.id})")
|
|
289
289
|
except Exception as e:
|
|
290
|
-
print_error(f"Unable to
|
|
290
|
+
print_error(f"Unable to remove Image Family '{fq_name}': {e}")
|
|
291
291
|
|
|
292
292
|
|
|
293
293
|
def remove_namespace_configuration(resource: Dict):
|
|
@@ -304,7 +304,7 @@ def remove_namespace_configuration(resource: Dict):
|
|
|
304
304
|
CLIENT.object_store_client.get_namespace_storage_configurations()
|
|
305
305
|
)
|
|
306
306
|
if namespace not in [x.namespace for x in namespaces]:
|
|
307
|
-
print_error(f"Namespace Storage Configuration '{namespace}'
|
|
307
|
+
print_error(f"Cannot find Namespace Storage Configuration '{namespace}'")
|
|
308
308
|
return
|
|
309
309
|
|
|
310
310
|
if not confirmed(f"Remove Namespace Storage Configuration '{namespace}'?"):
|
|
@@ -428,7 +428,7 @@ def remove_resource_by_id(resource_id: str):
|
|
|
428
428
|
CLIENT.keyring_client.delete_keyring_by_name(keyring.name)
|
|
429
429
|
print_log(f"Removed Keyring {resource_id}")
|
|
430
430
|
return
|
|
431
|
-
raise Exception(f"Keyring {resource_id}
|
|
431
|
+
raise Exception(f"Cannot find Keyring {resource_id}")
|
|
432
432
|
|
|
433
433
|
elif get_ydid_type(resource_id) == YDIDType.WORKER_POOL:
|
|
434
434
|
if confirmed(f"Shut down Worker Pool {resource_id}?"):
|
|
@@ -497,7 +497,7 @@ def remove_namespace_policy(resource: Dict):
|
|
|
497
497
|
return
|
|
498
498
|
except Exception:
|
|
499
499
|
# Assume it's not found ... 404 from API
|
|
500
|
-
print_error(f"Namespace Policy '{namespace}'
|
|
500
|
+
print_error(f"Cannot find Namespace Policy '{namespace}'")
|
|
501
501
|
return
|
|
502
502
|
|
|
503
503
|
if not confirmed(f"Remove Namespace Policy '{namespace}'?"):
|
|
@@ -522,7 +522,7 @@ def remove_group(resource: Dict):
|
|
|
522
522
|
|
|
523
523
|
group_id = get_group_id_by_name(CLIENT, group_name)
|
|
524
524
|
if group_id is None:
|
|
525
|
-
print_warning(f"Group '{group_name}'
|
|
525
|
+
print_warning(f"Cannot find Group '{group_name}'")
|
|
526
526
|
return
|
|
527
527
|
|
|
528
528
|
if not confirmed(f"Remove Group '{group_name}' ({group_id})?"):
|
|
@@ -533,7 +533,7 @@ def remove_group(resource: Dict):
|
|
|
533
533
|
print_log(f"Removed Group '{group_name}' ({group_id})")
|
|
534
534
|
clear_group_caches()
|
|
535
535
|
except Exception as e:
|
|
536
|
-
print_error(f"Unable to
|
|
536
|
+
print_error(f"Unable to remove Group '{group_name}' ({group_id}): {e}")
|
|
537
537
|
|
|
538
538
|
|
|
539
539
|
def remove_application(resource: Dict):
|
|
@@ -548,7 +548,7 @@ def remove_application(resource: Dict):
|
|
|
548
548
|
|
|
549
549
|
app_id = get_application_id_by_name(CLIENT, app_name)
|
|
550
550
|
if app_id is None:
|
|
551
|
-
print_warning(f"Application '{app_name}'
|
|
551
|
+
print_warning(f"Cannot find Application '{app_name}'")
|
|
552
552
|
return
|
|
553
553
|
|
|
554
554
|
if not confirmed(f"Remove Application '{app_name}' ({app_id})?"):
|
|
@@ -574,7 +574,7 @@ def remove_namespace(resource: Dict):
|
|
|
574
574
|
|
|
575
575
|
namespace_id = get_namespace_id_by_name(CLIENT, name)
|
|
576
576
|
if namespace_id is None:
|
|
577
|
-
print_warning(f"Namespace '{name}'
|
|
577
|
+
print_warning(f"Cannot find Namespace '{name}'")
|
|
578
578
|
return
|
|
579
579
|
|
|
580
580
|
if not confirmed(f"Remove Namespace '{name}'?"):
|