yellowdog-python-examples 7.10.2__tar.gz → 7.11.0__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.
Files changed (77) hide show
  1. {yellowdog_python_examples-7.10.2/yellowdog_python_examples.egg-info → yellowdog_python_examples-7.11.0}/PKG-INFO +2 -2
  2. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/README.md +30 -10
  3. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/requirements.txt +1 -1
  4. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/tests/test_entrypoints.py +2 -0
  5. yellowdog_python_examples-7.11.0/yd_commands/__init__.py +1 -0
  6. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/args.py +12 -0
  7. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/create.py +43 -0
  8. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/items.py +2 -0
  9. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/list.py +56 -6
  10. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/load_resources.py +9 -4
  11. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/object_utilities.py +27 -0
  12. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/printing.py +33 -9
  13. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/remove.py +30 -0
  14. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/settings.py +1 -0
  15. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/show.py +7 -11
  16. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/shutdown.py +8 -39
  17. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/variables.py +6 -1
  18. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/wrapper.py +2 -2
  19. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0/yellowdog_python_examples.egg-info}/PKG-INFO +2 -2
  20. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yellowdog_python_examples.egg-info/requires.txt +1 -1
  21. yellowdog_python_examples-7.10.2/yd_commands/__init__.py +0 -1
  22. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/LICENSE +0 -0
  23. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/PYPI_README.md +0 -0
  24. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/pyproject.toml +0 -0
  25. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/setup.cfg +0 -0
  26. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/setup.py +0 -0
  27. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/tests/test_create_remove.py +0 -0
  28. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/tests/test_demos.py +0 -0
  29. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/tests/test_dryruns.py +0 -0
  30. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/tests/test_gui.py +0 -0
  31. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/tests/test_list.py +0 -0
  32. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/tests/test_objects.py +0 -0
  33. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/tests/test_variable_processing.py +0 -0
  34. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/abort.py +0 -0
  35. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/admin.py +0 -0
  36. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/boost.py +0 -0
  37. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/cancel.py +0 -0
  38. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/check_imports.py +0 -0
  39. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/cloudwizard.py +0 -0
  40. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/cloudwizard_aws.py +0 -0
  41. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/cloudwizard_aws_types.py +0 -0
  42. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/cloudwizard_azure.py +0 -0
  43. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/cloudwizard_common.py +0 -0
  44. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/cloudwizard_gcp.py +0 -0
  45. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/compact_json.py +0 -0
  46. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/config_types.py +0 -0
  47. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/csv_data.py +0 -0
  48. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/delete.py +0 -0
  49. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/download.py +0 -0
  50. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/follow.py +0 -0
  51. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/follow_utils.py +0 -0
  52. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/format_json.py +0 -0
  53. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/hold.py +0 -0
  54. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/id_utils.py +0 -0
  55. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/instantiate.py +0 -0
  56. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/interactive.py +0 -0
  57. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/jsonnet2json.py +0 -0
  58. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/load_config.py +0 -0
  59. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/property_names.py +0 -0
  60. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/provision.py +0 -0
  61. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/provision_utils.py +0 -0
  62. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/resize.py +0 -0
  63. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/start.py +0 -0
  64. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/start_hold_common.py +0 -0
  65. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/submit.py +0 -0
  66. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/submit_utils.py +0 -0
  67. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/terminate.py +0 -0
  68. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/type_check.py +0 -0
  69. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/upload.py +0 -0
  70. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/upload_utils.py +0 -0
  71. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/utils.py +0 -0
  72. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/validate_properties.py +0 -0
  73. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yd_commands/version.py +0 -0
  74. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yellowdog_python_examples.egg-info/SOURCES.txt +0 -0
  75. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yellowdog_python_examples.egg-info/dependency_links.txt +0 -0
  76. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yellowdog_python_examples.egg-info/entry_points.txt +0 -0
  77. {yellowdog_python_examples-7.10.2 → yellowdog_python_examples-7.11.0}/yellowdog_python_examples.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: yellowdog-python-examples
3
- Version: 7.10.2
3
+ Version: 7.11.0
4
4
  Summary: Example Python commands using the YellowDog Python SDK
5
5
  Home-page: https://github.com/yellowdog/python-examples
6
6
  Author: YellowDog Limited
@@ -15,7 +15,7 @@ Classifier: Development Status :: 4 - Beta
15
15
  Requires-Python: >=3.7
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: yellowdog-sdk>=8.0.2
18
+ Requires-Dist: yellowdog-sdk==8.1.2
19
19
  Requires-Dist: toml
20
20
  Requires-Dist: tabulate>=0.9.0
21
21
  Requires-Dist: PyPAC>=0.16.4
@@ -90,6 +90,7 @@
90
90
  * [Attribute Definitions](#attribute-definitions)
91
91
  * [String Attribute Definitions](#string-attribute-definitions)
92
92
  * [Numeric Attribute Definitions](#numeric-attribute-definitions)
93
+ * [Namespace Policies](#namespace-policies)
93
94
  * [Jsonnet Support](#jsonnet-support)
94
95
  * [Jsonnet Installation](#jsonnet-installation)
95
96
  * [Variable Substitutions in Jsonnet Files](#variable-substitutions-in-jsonnet-files)
@@ -118,7 +119,7 @@
118
119
  * [yd-show](#yd-show)
119
120
 
120
121
  <!-- Created by https://github.com/ekalinin/github-markdown-toc -->
121
- <!-- Added by: pwt, at: Wed Jun 12 11:55:06 BST 2024 -->
122
+ <!-- Added by: pwt, at: Wed Jun 26 20:59:32 BST 2024 -->
122
123
 
123
124
  <!--te-->
124
125
 
@@ -581,7 +582,7 @@ All properties are optional except for **`taskType`** (or **`taskTypes`**).
581
582
  | `maxWorkers` | The maximum number of Workers that can be claimed for the associated Task Group. E.g., `10`. | Yes | Yes | Yes | |
582
583
  | `minWorkers` | The minimum number of Workers that the associated Task Group requires. This many workers must be claimed before the associated Task Group will start working. E.g., `1`. | Yes | Yes | Yes | |
583
584
  | `name` | The name of the Work Requirement, Task Group or Task. E.g., `"wr_name"`. Note that the `name` property is not inherited. | Yes | Yes | Yes | Yes |
584
- | `namespaces` | Only Worker Pools whose workers match one of the namespaces in this list can be claimed by the Task Group. E.g., `["namespace_1", "namespace_2"]. Defaults to `None`. | Yes | Yes | Yes | |
585
+ | `namespaces` | Only Workers whose Worker Pools match one of the namespaces in this list can be claimed by the Task Group. E.g., `["namespace_1", "namespace_2"]. Defaults to `None`. | Yes | Yes | Yes | |
585
586
  | `outputs` | The files to be uploaded to the YellowDog Object Store by a Worker node on completion of the Task. E.g., `["results_1.txt", "results_2.txt"]`. | Yes | Yes | Yes | Yes |
586
587
  | `outputsOther` | Files to be uploaded to the YellowDog Object Store from outside the Tasks's Working Directory by a Worker node on completion of a Task. E.g., `outputsOther = [{"directoryName" = "tmp", "filePattern" = "out.txt", "required" = false}]`. | Yes | Yes | Yes | Yes |
587
588
  | `outputsRequired` | The files that *must* be uploaded to the YellowDog Object Store by a Worker node on completion of the Task. The Task will fail if any outputs are unavailable. | Yes | Yes | Yes | Yes |
@@ -1808,6 +1809,7 @@ The commands **yd-create** and **yd-remove** allow the creation, update and remo
1808
1809
  - Configured Worker Pools
1809
1810
  - Allowances
1810
1811
  - String Attribute Definitions
1812
+ - Namespace Policies
1811
1813
 
1812
1814
  ## Overview of Operation
1813
1815
 
@@ -2209,6 +2211,20 @@ Example:
2209
2211
 
2210
2212
  The `name`, `title` and `defaultRankOrder` properties are required, while the rest are optional. Either the `range` property or the `options` property (with numeric option values) can be specified, but not both. The `user.` prefix is required when specifying the `name` property.
2211
2213
 
2214
+ ## Namespace Policies
2215
+
2216
+ The Namespace Policies example and schema can be found at: (TBD).
2217
+
2218
+ ```json
2219
+ {
2220
+ "resource": "NamespacePolicy",
2221
+ "namespace": "test_namespace",
2222
+ "autoscalingMaxNodes": 3
2223
+ }
2224
+ ```
2225
+
2226
+ Namespace Policies are matched by their `namespace` property when using `yd-create` and `yd-remove`. The `autoscalingMaxNodes` property can be omitted or set to `null` to remove an existing limit for a namespace.
2227
+
2212
2228
  # Jsonnet Support
2213
2229
 
2214
2230
  In all circumstances where JSON files are used by the Python Examples commands, **[Jsonnet](https://jsonnet.org)** files can be used instead. This allows the use of Jsonnet's powerful JSON extensions, including comments, variables, functions, etc.
@@ -2591,19 +2607,23 @@ The `yd-terminate` command immediately terminates Compute Requirements that matc
2591
2607
 
2592
2608
  ## yd-list
2593
2609
 
2594
- The `yd-list` command is used to list various YellowDog items, using the `namespace` and `tag` properties to target the scope of what to list:
2610
+ The `yd-list` command is used to list various YellowDog items, using the `namespace` and `tag` properties (if applicable) to target the scope of what to list:
2595
2611
 
2612
+ - Allowances
2613
+ - Attribute Definitions
2596
2614
  - Compute Requirements
2597
- - Worker Pools
2615
+ - Compute Templates
2616
+ - Image Families, Image Groups, and Images
2617
+ - Instances
2618
+ - Keyrings
2619
+ - Namespace Policies
2620
+ - Namespace Storage Configurations
2598
2621
  - Objects in the Object Store
2599
- - Work Requirements
2622
+ - Source Templates
2600
2623
  - Task Groups
2601
2624
  - Tasks
2602
- - Compute Sources
2603
- - Compute Templates
2604
- - Namespace Storage Configurations
2605
- - Keyrings
2606
- - Image Families
2625
+ - Work Requirements
2626
+ - Worker Pools
2607
2627
 
2608
2628
  Please use `yd-list --help` to inspect the various options.
2609
2629
 
@@ -1,4 +1,4 @@
1
- yellowdog-sdk >= 8.0.2
1
+ yellowdog-sdk == 8.1.2
2
2
  toml
3
3
  tabulate >= 0.9.0
4
4
  PyPAC >= 0.16.4
@@ -48,3 +48,5 @@ def test_entrypoints():
48
48
  assert result.exit_code == 0
49
49
  result = shell("yd-boost --help")
50
50
  assert result.exit_code == 0
51
+ result = shell("yd-show --help")
52
+ assert result.exit_code == 0
@@ -0,0 +1 @@
1
+ __version__ = "7.11.0"
@@ -536,6 +536,13 @@ class CLIParser:
536
536
  required=False,
537
537
  help="list user attribute definitions",
538
538
  )
539
+ parser.add_argument(
540
+ "--namespace-policies",
541
+ "-P",
542
+ action="store_true",
543
+ required=False,
544
+ help="list namespace policies",
545
+ )
539
546
 
540
547
  if any(module in sys.argv[0] for module in ["upload"]):
541
548
  parser.add_argument(
@@ -1331,6 +1338,11 @@ class CLIParser:
1331
1338
  def attribute_definitions(self) -> Optional[bool]:
1332
1339
  return self.args.attribute_definitions
1333
1340
 
1341
+ @property
1342
+ @allow_missing_attribute
1343
+ def namespace_policies(self) -> Optional[bool]:
1344
+ return self.args.namespace_policies
1345
+
1334
1346
  @property
1335
1347
  @allow_missing_attribute
1336
1348
  def show_keyring_passwords(self) -> Optional[bool]:
@@ -25,6 +25,7 @@ from yellowdog_client.model import (
25
25
  MachineImage,
26
26
  MachineImageFamily,
27
27
  MachineImageGroup,
28
+ NamespacePolicy,
28
29
  NamespaceStorageConfiguration,
29
30
  RequirementsAllowance,
30
31
  SourceAllowance,
@@ -51,6 +52,7 @@ from yd_commands.settings import (
51
52
  RN_CREDENTIAL,
52
53
  RN_IMAGE_FAMILY,
53
54
  RN_KEYRING,
55
+ RN_NAMESPACE_POLICY,
54
56
  RN_NUMERIC_ATTRIBUTE_DEFINITION,
55
57
  RN_REQUIREMENT_TEMPLATE,
56
58
  RN_SOURCE_TEMPLATE,
@@ -125,6 +127,8 @@ def create_resources(
125
127
  RN_NUMERIC_ATTRIBUTE_DEFINITION,
126
128
  ]:
127
129
  create_attribute_definition(resource, resource_type)
130
+ elif resource_type == RN_NAMESPACE_POLICY:
131
+ create_namespace_policy(resource)
128
132
  else:
129
133
  print_error(f"Unknown resource type '{resource_type}'")
130
134
  except Exception as e:
@@ -856,6 +860,45 @@ def create_attribute_definition(resource: Dict, resource_type: str):
856
860
  raise Exception(f"HTTP {response.status_code} ({response.text})")
857
861
 
858
862
 
863
+ def create_namespace_policy(resource: Dict):
864
+ """
865
+ Create or update a namespace policy.
866
+ """
867
+ try:
868
+ namespace_policy = NamespacePolicy(
869
+ namespace=resource["namespace"],
870
+ autoscalingMaxNodes=resource.get("autoscalingMaxNodes"),
871
+ )
872
+ except KeyError as e:
873
+ raise Exception(f"Expected property to be defined ({e})")
874
+
875
+ # Test for existing policy
876
+ try:
877
+ CLIENT.namespaces_client.get_namespace_policy(
878
+ namespace=namespace_policy.namespace
879
+ )
880
+ if not confirmed(
881
+ f"Update existing Namespace Policy '{namespace_policy.namespace}'?"
882
+ ):
883
+ return
884
+ except Exception:
885
+ # Assume it's not found ... 404 from API
886
+ pass
887
+
888
+ try:
889
+ CLIENT.namespaces_client.save_namespace_policy(namespace_policy)
890
+ except Exception as e:
891
+ print_error(
892
+ f"Unable to create or update Namespace Policy for '{namespace_policy.namespace}': {e}"
893
+ )
894
+ return
895
+
896
+ print_log(
897
+ f"Created or updated Namespace Policy '{namespace_policy.namespace}' with "
898
+ f"'autoscalingMaxNodes={namespace_policy.autoscalingMaxNodes}'"
899
+ )
900
+
901
+
859
902
  # Entry point
860
903
  if __name__ == "__main__":
861
904
  main()
@@ -14,6 +14,7 @@ from yellowdog_client.model import (
14
14
  Instance,
15
15
  KeyringSummary,
16
16
  MachineImageFamilySummary,
17
+ NamespacePolicy,
17
18
  NamespaceStorageConfiguration,
18
19
  ObjectPath,
19
20
  ProvisionedWorkerPool,
@@ -37,6 +38,7 @@ Item = TypeVar(
37
38
  Instance,
38
39
  KeyringSummary,
39
40
  MachineImageFamilySummary,
41
+ NamespacePolicy,
40
42
  NamespaceStorageConfiguration,
41
43
  ObjectPath,
42
44
  ProvisionedWorkerPool,
@@ -27,11 +27,12 @@ from yellowdog_client.model import (
27
27
  KeyringSummary,
28
28
  MachineImageFamilySearch,
29
29
  MachineImageFamilySummary,
30
+ NamespacePolicy,
31
+ NamespacePolicySearch,
30
32
  NamespaceStorageConfiguration,
31
33
  ObjectDetail,
32
34
  Task,
33
35
  TaskGroup,
34
- TaskSearch,
35
36
  WorkerPool,
36
37
  WorkerPoolStatus,
37
38
  WorkerPoolSummary,
@@ -43,6 +44,7 @@ from yd_commands.interactive import select
43
44
  from yd_commands.object_utilities import (
44
45
  get_filtered_work_requirements,
45
46
  get_task_groups_from_wr_summary,
47
+ get_tasks,
46
48
  list_matching_object_paths,
47
49
  )
48
50
  from yd_commands.printing import (
@@ -51,6 +53,7 @@ from yd_commands.printing import (
51
53
  print_log,
52
54
  print_numbered_object_list,
53
55
  print_table_core,
56
+ print_warning,
54
57
  print_yd_object,
55
58
  sorted_objects,
56
59
  )
@@ -88,6 +91,8 @@ def main():
88
91
  list_allowances()
89
92
  elif ARGS_PARSER.attribute_definitions:
90
93
  list_attribute_definitions()
94
+ elif ARGS_PARSER.namespace_policies:
95
+ list_namespace_policies()
91
96
 
92
97
 
93
98
  def check_for_valid_option() -> bool:
@@ -109,6 +114,7 @@ def check_for_valid_option() -> bool:
109
114
  ARGS_PARSER.instances,
110
115
  ARGS_PARSER.allowances,
111
116
  ARGS_PARSER.attribute_definitions,
117
+ ARGS_PARSER.namespace_policies,
112
118
  ].count(True) == 1:
113
119
  return True
114
120
  else:
@@ -185,11 +191,7 @@ def list_task_groups(work_summary: WorkRequirementSummary):
185
191
 
186
192
 
187
193
  def list_tasks(task_group: TaskGroup, work_summary: WorkRequirementSummary):
188
- task_search = TaskSearch(
189
- workRequirementId=work_summary.id,
190
- taskGroupId=task_group.id,
191
- )
192
- tasks: List[Task] = CLIENT.work_client.find_tasks(task_search)
194
+ tasks: List[Task] = get_tasks(CLIENT, work_summary.id, task_group.id)
193
195
  tasks = sorted_objects(tasks)
194
196
  if ARGS_PARSER.details:
195
197
  for task in select(CLIENT, tasks):
@@ -596,6 +598,54 @@ def list_attribute_definitions():
596
598
  print_json(selected_attribute_definition)
597
599
 
598
600
 
601
+ def list_namespace_policies():
602
+ """
603
+ List namespace policies.
604
+ """
605
+
606
+ np_search = NamespacePolicySearch()
607
+ search_client: SearchClient = CLIENT.namespaces_client.get_namespace_policies(
608
+ np_search
609
+ )
610
+ namespace_policies: List[NamespacePolicy] = search_client.list_all()
611
+ if len(namespace_policies) == 0:
612
+ print_log("No Namespace Policies to display")
613
+ return
614
+
615
+ if not ARGS_PARSER.details:
616
+ print_numbered_object_list(CLIENT, namespace_policies)
617
+ return
618
+
619
+ for selected_namespace_policy in select(
620
+ CLIENT, namespace_policies, object_type_name="Namespace Policy"
621
+ ):
622
+ if selected_namespace_policy.autoscalingMaxNodes is None:
623
+ print_yd_object(selected_namespace_policy)
624
+ else:
625
+ details = get_autoscaling_capacity(selected_namespace_policy.namespace)
626
+ details["autoscalingMaxNodes"] = (
627
+ selected_namespace_policy.autoscalingMaxNodes
628
+ )
629
+ print_json(details)
630
+
631
+
632
+ def get_autoscaling_capacity(namespace: str) -> Dict:
633
+ """
634
+ Get the current autoscaling values for a namespace.
635
+ """
636
+ response = get(
637
+ url=f"{CONFIG_COMMON.url}/workerPools/namespaces/{namespace}/autoscalingCapacity",
638
+ headers={"Authorization": f"yd-key {CONFIG_COMMON.key}:{CONFIG_COMMON.secret}"},
639
+ )
640
+ if response.status_code == 200:
641
+ return response.json()
642
+ else:
643
+ print_warning(
644
+ f"Failed to get autoscaling details for namespace '{namespace}' ({response.text})"
645
+ )
646
+ return {"namespace": namespace}
647
+
648
+
599
649
  # Entry point
600
650
  if __name__ == "__main__":
601
651
  main()
@@ -2,7 +2,7 @@
2
2
  Load data for resource creation/update/removal requests.
3
3
  """
4
4
 
5
- from sys import exit
5
+ from sys import argv, exit
6
6
  from typing import Dict, List
7
7
 
8
8
  from yd_commands.args import ARGS_PARSER
@@ -13,6 +13,7 @@ from yd_commands.settings import (
13
13
  RN_CREDENTIAL,
14
14
  RN_IMAGE_FAMILY,
15
15
  RN_KEYRING,
16
+ RN_NAMESPACE_POLICY,
16
17
  RN_NUMERIC_ATTRIBUTE_DEFINITION,
17
18
  RN_REQUIREMENT_TEMPLATE,
18
19
  RN_SOURCE_TEMPLATE,
@@ -49,10 +50,13 @@ def load_resource_specifications(creation_or_update: bool = True) -> List[Dict]:
49
50
  elif resource_spec.lower().endswith(".json"):
50
51
  resources_loaded = load_json_file_with_variable_substitutions(resource_spec)
51
52
  else:
52
- raise Exception(
53
- f"['{resource_spec}'] Resource specifications must end in '.toml',"
54
- " '.json' or '.jsonnet'"
53
+ exception_message = (
54
+ f"['{resource_spec}'] Resource specifications must end in '.toml', "
55
+ "'.json' or '.jsonnet'"
55
56
  )
57
+ if resource_spec.startswith("ydid:") and "":
58
+ exception_message += "; did you mean to use the '--ids' option?"
59
+ raise Exception(exception_message)
56
60
 
57
61
  # Transform single resource items into lists
58
62
  if isinstance(resources_loaded, dict):
@@ -101,6 +105,7 @@ def _resequence_resources(
101
105
  RN_SOURCE_TEMPLATE,
102
106
  RN_REQUIREMENT_TEMPLATE,
103
107
  RN_ALLOWANCE,
108
+ RN_NAMESPACE_POLICY,
104
109
  RN_STORAGE_CONFIGURATION,
105
110
  RN_CONFIGURED_POOL,
106
111
  ]
@@ -21,6 +21,7 @@ from yellowdog_client.model import (
21
21
  ProvisionedWorkerPool,
22
22
  Task,
23
23
  TaskGroup,
24
+ TaskSearch,
24
25
  WorkerPool,
25
26
  WorkerPoolSummary,
26
27
  WorkRequirementStatus,
@@ -304,3 +305,29 @@ def list_matching_object_paths(
304
305
  for object_path in object_paths
305
306
  if object_path.name.startswith(prefix)
306
307
  ]
308
+
309
+
310
+ def get_task_by_id(
311
+ client: PlatformClient, wr_id: str, task_group_id: str, task_id: str
312
+ ) -> Optional[Task]:
313
+ """
314
+ Find a task by its ID.
315
+ """
316
+ tasks: List[Task] = get_tasks(client, wr_id, task_group_id)
317
+ for task in tasks:
318
+ if task.id == task_id:
319
+ return task
320
+
321
+
322
+ @lru_cache()
323
+ def get_tasks(client: PlatformClient, wr_id: str, task_group_id: str) -> List[Task]:
324
+ """
325
+ Return all the tasks in a task group, with caching.
326
+ There is no native way to search for a task by its id.
327
+ """
328
+ task_search = TaskSearch(
329
+ workRequirementId=wr_id,
330
+ taskGroupId=task_group_id,
331
+ )
332
+ tasks: List[Task] = client.work_client.find_tasks(task_search)
333
+ return tasks
@@ -32,6 +32,7 @@ from yellowdog_client.model import (
32
32
  Instance,
33
33
  KeyringSummary,
34
34
  MachineImageFamilySummary,
35
+ NamespacePolicy,
35
36
  NodeStatus,
36
37
  NodeSummary,
37
38
  ObjectDetail,
@@ -202,20 +203,21 @@ def print_warning(
202
203
 
203
204
 
204
205
  TYPE_MAP = {
205
- ConfiguredWorkerPool: "Configured Worker Pool",
206
- ProvisionedWorkerPool: "Provisioned Worker Pool",
207
- WorkerPoolSummary: "Worker Pool",
206
+ AWSAvailabilityZone: "AWS Availability Zones",
207
+ Allowance: "Allowance",
208
208
  ComputeRequirement: "Compute Requirement",
209
- Task: "Task",
210
- TaskGroup: "Task Group",
211
- WorkRequirementSummary: "Work Requirement",
212
- ObjectPath: "Object Path",
213
209
  ComputeRequirementTemplateSummary: "Compute Requirement Template",
214
210
  ComputeSourceTemplateSummary: "Compute Source Template",
211
+ ConfiguredWorkerPool: "Configured Worker Pool",
215
212
  KeyringSummary: "Keyring",
216
213
  MachineImageFamilySummary: "Machine Image Family",
217
- AWSAvailabilityZone: "AWS Availability Zones",
218
- Allowance: "Allowance",
214
+ NamespacePolicy: "Namespace Policy",
215
+ ObjectPath: "Object Path",
216
+ ProvisionedWorkerPool: "Provisioned Worker Pool",
217
+ Task: "Task",
218
+ TaskGroup: "Task Group",
219
+ WorkRequirementSummary: "Work Requirement",
220
+ WorkerPoolSummary: "Worker Pool",
219
221
  }
220
222
 
221
223
 
@@ -613,6 +615,26 @@ def aws_availability_zone_table(
613
615
  return headers, table
614
616
 
615
617
 
618
+ def namespace_policies_table(
619
+ ns_policies: List[NamespacePolicy],
620
+ ) -> (List[str], List[List]):
621
+ headers = [
622
+ "#",
623
+ "Namespace",
624
+ "AutoscalingMaxNodes",
625
+ ]
626
+ table = []
627
+ for index, ns_policy in enumerate(ns_policies):
628
+ table.append(
629
+ [
630
+ index + 1,
631
+ ns_policy.namespace,
632
+ ns_policy.autoscalingMaxNodes,
633
+ ]
634
+ )
635
+ return headers, table
636
+
637
+
616
638
  def print_numbered_object_list(
617
639
  client: PlatformClient,
618
640
  objects: List[Union[Item, str, Dict]],
@@ -667,6 +689,8 @@ def print_numbered_object_list(
667
689
  headers, table = aws_availability_zone_table(objects)
668
690
  elif object_type_name == "Attribute Definition":
669
691
  headers, table = attribute_definitions_table(objects)
692
+ elif isinstance(objects[0], NamespacePolicy):
693
+ headers, table = namespace_policies_table(objects)
670
694
  else:
671
695
  table = []
672
696
  for index, obj in enumerate(objects):
@@ -32,6 +32,7 @@ from yd_commands.settings import (
32
32
  RN_CREDENTIAL,
33
33
  RN_IMAGE_FAMILY,
34
34
  RN_KEYRING,
35
+ RN_NAMESPACE_POLICY,
35
36
  RN_NUMERIC_ATTRIBUTE_DEFINITION,
36
37
  RN_REQUIREMENT_TEMPLATE,
37
38
  RN_SOURCE_TEMPLATE,
@@ -100,6 +101,8 @@ def remove_resources(resources: Optional[List[Dict]] = None):
100
101
  RN_NUMERIC_ATTRIBUTE_DEFINITION,
101
102
  ]:
102
103
  remove_attribute_definition(resource)
104
+ elif resource_type == RN_NAMESPACE_POLICY:
105
+ remove_namespace_policy(resource)
103
106
  else:
104
107
  print_error(f"Unknown resource type '{resource_type}'")
105
108
  except Exception as e:
@@ -438,6 +441,33 @@ def remove_attribute_definition(resource: Dict):
438
441
  raise Exception(f"HTTP {response.status_code} ({response.text})")
439
442
 
440
443
 
444
+ def remove_namespace_policy(resource: Dict):
445
+ """
446
+ Remove a Namespace Policy (if it exists).
447
+ """
448
+ try:
449
+ namespace = resource["namespace"]
450
+ except KeyError as e:
451
+ print_error(f"Expected property to be defined ({e})")
452
+ return
453
+
454
+ # Test for existing policy
455
+ try:
456
+ CLIENT.namespaces_client.get_namespace_policy(namespace=namespace)
457
+ if not confirmed(f"Remove Namespace Policy '{namespace}'?"):
458
+ return
459
+ except Exception:
460
+ # Assume it's not found ... 404 from API
461
+ print_error(f"Namespace Policy '{namespace}' not found")
462
+ return
463
+
464
+ try:
465
+ CLIENT.namespaces_client.delete_namespace_policy(namespace)
466
+ print_log(f"Removed Namespace Policy '{namespace}'")
467
+ except Exception as e:
468
+ print_error(f"Unable to remove Namespace Policy '{namespace}': {e}")
469
+
470
+
441
471
  # Entry point
442
472
  if __name__ == "__main__":
443
473
  main()
@@ -107,3 +107,4 @@ RN_SOURCE_TEMPLATE = "ComputeSourceTemplate"
107
107
  RN_STORAGE_CONFIGURATION = "NamespaceStorageConfiguration"
108
108
  RN_STRING_ATTRIBUTE_DEFINITION = "StringAttributeDefinition"
109
109
  RN_NUMERIC_ATTRIBUTE_DEFINITION = "NumericAttributeDefinition"
110
+ RN_NAMESPACE_POLICY = "NamespacePolicy"
@@ -4,11 +4,11 @@
4
4
  Command to show the JSON details of YellowDog entities via their IDs.
5
5
  """
6
6
 
7
- from typing import List
7
+ from typing import Optional
8
8
 
9
- from yellowdog_client.model import ConfiguredWorkerPool, Task, TaskSearch
10
- from yellowdog_client.model.exceptions import InvalidRequestException
9
+ from yellowdog_client.model import ConfiguredWorkerPool, Task
11
10
 
11
+ from yd_commands.object_utilities import get_task_by_id
12
12
  from yd_commands.printing import print_log, print_warning, print_yd_object
13
13
  from yd_commands.wrapper import ARGS_PARSER, CLIENT, main_wrapper
14
14
 
@@ -106,15 +106,11 @@ def show_details(ydid: str):
106
106
  else:
107
107
  print_warning(f"Task Group ID '{ydid}' not found")
108
108
  return
109
- task_search = TaskSearch(
110
- workRequirementId=work_requirement.id,
111
- taskGroupId=task_group.id,
109
+ task: Optional[Task] = get_task_by_id(
110
+ CLIENT, work_requirement.id, task_group.id, ydid
112
111
  )
113
- tasks: List[Task] = CLIENT.work_client.find_tasks(task_search)
114
- for task in tasks:
115
- if task.id == ydid:
116
- print_yd_object(task)
117
- return
112
+ if task is not None:
113
+ print_yd_object(task)
118
114
  else:
119
115
  print_warning(f"Task ID '{ydid}' not found")
120
116
 
@@ -1,18 +1,12 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
3
  """
4
- A script to shut down Provisioned Worker Pools.
4
+ A script to shut down Worker Pools.
5
5
  """
6
6
 
7
7
  from typing import List
8
8
 
9
- from yellowdog_client.model import (
10
- ComputeRequirement,
11
- ComputeRequirementStatus,
12
- WorkerPool,
13
- WorkerPoolStatus,
14
- WorkerPoolSummary,
15
- )
9
+ from yellowdog_client.model import WorkerPool, WorkerPoolStatus, WorkerPoolSummary
16
10
 
17
11
  from yd_commands.follow_utils import follow_ids
18
12
  from yd_commands.interactive import confirmed, select
@@ -32,12 +26,11 @@ def main():
32
26
  return
33
27
 
34
28
  print_log(
35
- "Shutting down Provisioned Worker Pools with Compute Requirements in "
29
+ "Shutting down Worker Pools in "
36
30
  f"namespace '{CONFIG_COMMON.namespace}' and "
37
- f"tag starting with '{CONFIG_COMMON.name_tag}' "
38
- "(or Configured Worker Pools with names starting with "
39
- f"'{CONFIG_COMMON.name_tag}')"
31
+ f"names including '{CONFIG_COMMON.name_tag}'"
40
32
  )
33
+
41
34
  worker_pool_summaries: List[WorkerPoolSummary] = (
42
35
  CLIENT.worker_pool_client.find_all_worker_pools()
43
36
  )
@@ -49,34 +42,10 @@ def main():
49
42
  WorkerPoolStatus.TERMINATED,
50
43
  WorkerPoolStatus.SHUTDOWN,
51
44
  ]:
52
- if "ProvisionedWorkerPool" not in worker_pool_summary.type:
53
- # Configured Worker Pool: check worker pool name only
54
- if (
55
- worker_pool_summary.name is not None
56
- and worker_pool_summary.name.startswith(CONFIG_COMMON.name_tag)
57
- ):
58
- selected_worker_pool_summaries.append(worker_pool_summary)
59
- continue
60
-
61
- worker_pool: WorkerPool = get_worker_pool_by_id(
62
- CLIENT, worker_pool_summary.id
63
- )
64
- compute_requirement: ComputeRequirement = (
65
- CLIENT.compute_client.get_compute_requirement_by_id(
66
- worker_pool.computeRequirementId
67
- )
68
- )
69
- compute_requirement.tag = (
70
- "" if compute_requirement.tag is None else compute_requirement.tag
71
- )
72
45
  if (
73
- compute_requirement.tag.startswith(CONFIG_COMMON.name_tag)
74
- and compute_requirement.namespace == CONFIG_COMMON.namespace
75
- and compute_requirement.status
76
- not in [
77
- ComputeRequirementStatus.TERMINATED,
78
- ComputeRequirementStatus.TERMINATING,
79
- ]
46
+ worker_pool_summary.name is not None
47
+ and worker_pool_summary.namespace == CONFIG_COMMON.namespace
48
+ and CONFIG_COMMON.name_tag in worker_pool_summary.name
80
49
  ):
81
50
  selected_worker_pool_summaries.append(worker_pool_summary)
82
51
 
@@ -42,8 +42,13 @@ from yd_commands.utils import (
42
42
  )
43
43
 
44
44
  # Set up default variable substitutions
45
+ try:
46
+ USERNAME = getuser().replace(" ", "_").lower()
47
+ except:
48
+ USERNAME = "default-yd-user"
49
+
45
50
  VARIABLE_SUBSTITUTIONS = {
46
- "username": getuser().replace(" ", "_").lower(),
51
+ "username": USERNAME,
47
52
  "date": UTCNOW.strftime("%y%m%d"),
48
53
  "time": UTCNOW.strftime("%H%M%S%f")[:-4],
49
54
  "datetime": UTCNOW.strftime("%y%m%d-%H%M%S"),
@@ -104,7 +104,7 @@ def main_wrapper(func):
104
104
  print_log("Cancelled")
105
105
  exit_code = 1
106
106
  finally:
107
- CLIENT.close()
107
+ # CLIENT.close()
108
108
  if exit_code == 0:
109
109
  print_log("Done")
110
110
  exit(exit_code)
@@ -112,7 +112,7 @@ def main_wrapper(func):
112
112
  set_proxy()
113
113
  print_account()
114
114
  func()
115
- CLIENT.close()
115
+ # CLIENT.close()
116
116
  print_log("Done")
117
117
  exit(0)
118
118
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: yellowdog-python-examples
3
- Version: 7.10.2
3
+ Version: 7.11.0
4
4
  Summary: Example Python commands using the YellowDog Python SDK
5
5
  Home-page: https://github.com/yellowdog/python-examples
6
6
  Author: YellowDog Limited
@@ -15,7 +15,7 @@ Classifier: Development Status :: 4 - Beta
15
15
  Requires-Python: >=3.7
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: yellowdog-sdk>=8.0.2
18
+ Requires-Dist: yellowdog-sdk==8.1.2
19
19
  Requires-Dist: toml
20
20
  Requires-Dist: tabulate>=0.9.0
21
21
  Requires-Dist: PyPAC>=0.16.4
@@ -1,4 +1,4 @@
1
- yellowdog-sdk>=8.0.2
1
+ yellowdog-sdk==8.1.2
2
2
  toml
3
3
  tabulate>=0.9.0
4
4
  PyPAC>=0.16.4
@@ -1 +0,0 @@
1
- __version__ = "7.10.2"