yellowdog-python-examples 8.2.1__tar.gz → 8.3.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 (81) hide show
  1. {yellowdog_python_examples-8.2.1/yellowdog_python_examples.egg-info → yellowdog_python_examples-8.3.0}/PKG-INFO +3 -2
  2. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/PYPI_README.md +1 -0
  3. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/README.md +7 -1
  4. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/pyproject.toml +1 -0
  5. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/requirements.txt +1 -1
  6. yellowdog_python_examples-8.3.0/yellowdog_cli/__init__.py +1 -0
  7. yellowdog_python_examples-8.3.0/yellowdog_cli/application.py +104 -0
  8. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/create.py +2 -2
  9. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/list.py +4 -2
  10. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/show.py +4 -2
  11. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/args.py +2 -0
  12. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/entity_utils.py +77 -12
  13. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/misc_utils.py +4 -1
  14. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/wrapper.py +29 -50
  15. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0/yellowdog_python_examples.egg-info}/PKG-INFO +3 -2
  16. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_python_examples.egg-info/SOURCES.txt +1 -0
  17. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_python_examples.egg-info/entry_points.txt +1 -0
  18. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_python_examples.egg-info/requires.txt +1 -1
  19. yellowdog_python_examples-8.2.1/yellowdog_cli/__init__.py +0 -1
  20. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/LICENSE +0 -0
  21. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/setup.cfg +0 -0
  22. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/tests/test_create_remove.py +0 -0
  23. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/tests/test_demos.py +0 -0
  24. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/tests/test_dryruns.py +0 -0
  25. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/tests/test_entrypoints.py +0 -0
  26. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/tests/test_gui.py +0 -0
  27. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/tests/test_list.py +0 -0
  28. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/tests/test_objects.py +0 -0
  29. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/tests/test_variable_processing.py +0 -0
  30. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/abort.py +0 -0
  31. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/admin.py +0 -0
  32. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/boost.py +0 -0
  33. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/cancel.py +0 -0
  34. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/cloudwizard.py +0 -0
  35. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/compare.py +0 -0
  36. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/delete.py +0 -0
  37. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/download.py +0 -0
  38. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/finish.py +0 -0
  39. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/follow.py +0 -0
  40. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/format_json.py +0 -0
  41. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/hold.py +0 -0
  42. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/instantiate.py +0 -0
  43. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/jsonnet2json.py +0 -0
  44. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/provision.py +0 -0
  45. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/remove.py +0 -0
  46. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/resize.py +0 -0
  47. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/shutdown.py +0 -0
  48. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/start.py +0 -0
  49. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/submit.py +0 -0
  50. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/terminate.py +0 -0
  51. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/upload.py +0 -0
  52. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/__init__.py +0 -0
  53. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/check_imports.py +0 -0
  54. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/cloudwizard_aws.py +0 -0
  55. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/cloudwizard_aws_types.py +0 -0
  56. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/cloudwizard_azure.py +0 -0
  57. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/cloudwizard_common.py +0 -0
  58. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/cloudwizard_gcp.py +0 -0
  59. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/compact_json.py +0 -0
  60. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/config_types.py +0 -0
  61. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/csv_data.py +0 -0
  62. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/follow_utils.py +0 -0
  63. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/interactive.py +0 -0
  64. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/items.py +0 -0
  65. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/load_config.py +0 -0
  66. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/load_resources.py +0 -0
  67. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/printing.py +0 -0
  68. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/property_names.py +0 -0
  69. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/provision_utils.py +0 -0
  70. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/rich_console_input_fixed.py +0 -0
  71. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/settings.py +0 -0
  72. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/start_hold_common.py +0 -0
  73. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/submit_utils.py +0 -0
  74. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/type_check.py +0 -0
  75. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/upload_utils.py +0 -0
  76. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/validate_properties.py +0 -0
  77. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/variables.py +0 -0
  78. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/utils/ydid_utils.py +0 -0
  79. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_cli/version.py +0 -0
  80. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/yellowdog_python_examples.egg-info/dependency_links.txt +0 -0
  81. {yellowdog_python_examples-8.2.1 → yellowdog_python_examples-8.3.0}/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.2.1
3
+ Version: 8.3.0
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.7.0
29
+ Requires-Dist: yellowdog-sdk>=11.8.1
30
30
  Provides-Extra: jsonnet
31
31
  Requires-Dist: jsonnet; extra == "jsonnet"
32
32
  Provides-Extra: cloudwizard
@@ -62,6 +62,7 @@ The commands support:
62
62
  - **Provisioning** Worker Pools with the **`yd-provision`** command
63
63
  - **Resizing** Worker Pools and Compute Requirements with the **`yd-resize`** command
64
64
  - **Showing** the details of any YellowDog entity using its YellowDog ID with the **`yd-show`** command
65
+ - **Showing** the details of the current Application with the **`yd-application`** command
65
66
  - **Shutting Down** Worker Pools and Nodes with the **`yd-shutdown`** command
66
67
  - **Starting** HELD Work Requirements and **Holding** (or pausing) RUNNING Work Requirements with the **`yd-start`** and **`yd-hold`** commands
67
68
  - **Submitting** Work Requirements with the **`yd-submit`** command
@@ -20,6 +20,7 @@ The commands support:
20
20
  - **Provisioning** Worker Pools with the **`yd-provision`** command
21
21
  - **Resizing** Worker Pools and Compute Requirements with the **`yd-resize`** command
22
22
  - **Showing** the details of any YellowDog entity using its YellowDog ID with the **`yd-show`** command
23
+ - **Showing** the details of the current Application with the **`yd-application`** command
23
24
  - **Shutting Down** Worker Pools and Nodes with the **`yd-shutdown`** command
24
25
  - **Starting** HELD Work Requirements and **Holding** (or pausing) RUNNING Work Requirements with the **`yd-start`** and **`yd-hold`** commands
25
26
  - **Submitting** Work Requirements with the **`yd-submit`** command
@@ -132,9 +132,10 @@
132
132
  * [yd-show](#yd-show)
133
133
  * [yd-compare](#yd-compare)
134
134
  * [yd-finish](#yd-finish)
135
+ * [yd-application](#yd-application)
135
136
 
136
137
  <!-- Created by https://github.com/ekalinin/github-markdown-toc -->
137
- <!-- Added by: pwt, at: Fri Oct 24 12:05:26 BST 2025 -->
138
+ <!-- Added by: pwt, at: Mon Feb 2 12:15:54 GMT 2026 -->
138
139
 
139
140
  <!--te-->
140
141
 
@@ -165,6 +166,7 @@ The commands provide the following capabilities:
165
166
  - **Provisioning** Worker Pools with the **`yd-provision`** command
166
167
  - **Resizing** Worker Pools and Compute Requirements with the **`yd-resize`** command
167
168
  - **Showing** the details of any YellowDog entity using its YellowDog ID with the **`yd-show`** command
169
+ - **Showing** the details of the current Application with the **`yd-application`** command
168
170
  - **Shutting Down** Worker Pools and Nodes with the **`yd-shutdown`** command
169
171
  - **Starting** HELD Work Requirements and **Holding** (or pausing) RUNNING Work Requirements with the **`yd-start`** and **`yd-hold`** commands
170
172
  - **Submitting** Work Requirements with the **`yd-submit`** command
@@ -3037,3 +3039,7 @@ The match status of a Worker Pool falls into one of four categories:
3037
3039
  ## yd-finish
3038
3040
 
3039
3041
  The `yd-finish` command moves work requirements into the `FINISHING` state, meaning the requirements will be allowed to conclude but that no new tasks can be added.
3042
+
3043
+ ## yd-application
3044
+
3045
+ The `yd-application` command shows the details of the current Application, i.e., the Application represented by the `key` and `secret` being used.
@@ -48,6 +48,7 @@
48
48
 
49
49
  [project.scripts]
50
50
  yd-abort = "yellowdog_cli.abort:main"
51
+ yd-application = "yellowdog_cli.application:main"
51
52
  yd-boost = "yellowdog_cli.boost:main"
52
53
  yd-cancel = "yellowdog_cli.cancel:main"
53
54
  yd-cloudwizard = "yellowdog_cli.cloudwizard:main"
@@ -5,4 +5,4 @@ requests
5
5
  rich == 13.9.4
6
6
  tabulate >= 0.9.0
7
7
  toml
8
- yellowdog-sdk >= 11.7.0
8
+ yellowdog-sdk >= 11.8.1
@@ -0,0 +1 @@
1
+ __version__ = "8.3.0"
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ A script for reporting on the details of the Application being used.
5
+ """
6
+
7
+ from yellowdog_client.model import ApplicationDetails
8
+
9
+ from yellowdog_cli.utils.entity_utils import (
10
+ get_all_roles_and_namespaces_for_application,
11
+ get_application_details,
12
+ get_application_group_summaries,
13
+ )
14
+ from yellowdog_cli.utils.printing import print_simple
15
+ from yellowdog_cli.utils.wrapper import CLIENT, CONFIG_COMMON, main_wrapper
16
+
17
+
18
+ @main_wrapper
19
+ def main():
20
+
21
+ application_details: ApplicationDetails = get_application_details(CLIENT)
22
+
23
+ print()
24
+ print_simple(
25
+ f" Application name: {application_details.name}",
26
+ override_quiet=True,
27
+ )
28
+ print_simple(
29
+ f" Application ID: {application_details.id}",
30
+ override_quiet=True,
31
+ )
32
+ print_simple(
33
+ f" Account name: {application_details.accountName}",
34
+ override_quiet=True,
35
+ )
36
+ if "api" in CONFIG_COMMON.url:
37
+ print_simple(
38
+ " Portal URL: "
39
+ f"{CONFIG_COMMON.url.replace('api', 'portal')}"
40
+ f"/#/signin?account={application_details.accountName}",
41
+ override_quiet=True,
42
+ )
43
+ print_simple(
44
+ f" Account ID: {application_details.accountId}",
45
+ override_quiet=True,
46
+ )
47
+ features = (
48
+ ""
49
+ if application_details.features is None
50
+ else ", ".join([str(feature) for feature in application_details.features])
51
+ )
52
+ print_simple(
53
+ f" Account features: {features}",
54
+ override_quiet=True,
55
+ )
56
+ all_ns_readable = "Yes" if application_details.allNamespacesReadable else "No"
57
+ print_simple(
58
+ f" All namespaces readable: {all_ns_readable}",
59
+ override_quiet=True,
60
+ )
61
+ if not application_details.allNamespacesReadable:
62
+ readable_namespaces = (
63
+ ""
64
+ if application_details.readableNamespaces is None
65
+ else ", ".join([rns for rns in application_details.readableNamespaces])
66
+ )
67
+ print_simple(
68
+ f" Readable namespaces: {readable_namespaces}",
69
+ override_quiet=True,
70
+ )
71
+ try:
72
+ groups = get_application_group_summaries(CLIENT, application_details.id)
73
+ group_names = ", ".join([group.name for group in groups])
74
+ print_simple(
75
+ f" In group(s): {group_names}",
76
+ override_quiet=True,
77
+ )
78
+ for i, (role, namespaces) in enumerate(
79
+ get_all_roles_and_namespaces_for_application(
80
+ CLIENT, application_details.id
81
+ ).items()
82
+ ):
83
+ msg = f"{role} [{', '.join(namespaces)}]"
84
+ if i == 0:
85
+ print_simple(
86
+ f" With role(s) [in namespace(s)]: {msg}",
87
+ override_quiet=True,
88
+ )
89
+ else:
90
+ print_simple(
91
+ f" {msg}",
92
+ override_quiet=True,
93
+ )
94
+
95
+ except Exception as e:
96
+ if "Forbidden" in str(e):
97
+ print_simple(
98
+ " Groups and roles: "
99
+ "Cannot be determined due to application permissions",
100
+ override_quiet=True,
101
+ )
102
+ else:
103
+ pass
104
+ print()
@@ -55,7 +55,7 @@ from yellowdog_cli.utils.entity_utils import (
55
55
  find_compute_requirement_template_id_by_name,
56
56
  find_compute_source_template_id_by_name,
57
57
  find_image_name_or_id,
58
- get_application_groups,
58
+ get_application_group_summaries,
59
59
  get_application_id_by_name,
60
60
  get_group_id_by_name,
61
61
  get_group_name_by_id,
@@ -1156,7 +1156,7 @@ def create_application(resource: Dict):
1156
1156
  Helper function to add/remove groups from an application.
1157
1157
  """
1158
1158
  current_group_ids = {
1159
- group.id for group in get_application_groups(CLIENT, app.id)
1159
+ group.id for group in get_application_group_summaries(CLIENT, app.id)
1160
1160
  }
1161
1161
 
1162
1162
  if current_group_ids == new_group_ids:
@@ -52,7 +52,7 @@ from yellowdog_cli.utils.entity_utils import (
52
52
  get_all_groups,
53
53
  get_all_roles,
54
54
  get_all_users,
55
- get_application_groups,
55
+ get_application_group_summaries,
56
56
  get_compute_requirement_summaries,
57
57
  get_compute_requirement_templates,
58
58
  get_compute_source_templates,
@@ -992,7 +992,9 @@ def list_applications():
992
992
  {
993
993
  PROP_GROUPS: [
994
994
  group.name
995
- for group in get_application_groups(CLIENT, application.id)
995
+ for group in get_application_group_summaries(
996
+ CLIENT, application.id
997
+ )
996
998
  ],
997
999
  PROP_RESOURCE: RN_APPLICATION,
998
1000
  },
@@ -8,7 +8,7 @@ from yellowdog_client.model import ConfiguredWorkerPool
8
8
 
9
9
  from yellowdog_cli.list import get_keyring
10
10
  from yellowdog_cli.utils.entity_utils import (
11
- get_application_groups,
11
+ get_application_group_summaries,
12
12
  substitute_id_for_name_in_allowance,
13
13
  substitute_ids_for_names_in_crt,
14
14
  substitute_image_family_id_for_name_in_cst,
@@ -225,7 +225,9 @@ def show_details(ydid: str, initial_indent: int = 0, with_final_comma: bool = Fa
225
225
 
226
226
  elif ydid_type == YDIDType.APPLICATION:
227
227
  print_log(f"Showing details of Application ID '{ydid}'")
228
- group_names = [group.name for group in get_application_groups(CLIENT, ydid)]
228
+ group_names = [
229
+ group.name for group in get_application_group_summaries(CLIENT, ydid)
230
+ ]
229
231
  print_yd_object(
230
232
  CLIENT.account_client.get_application(ydid),
231
233
  initial_indent=initial_indent,
@@ -1884,6 +1884,8 @@ def lookup_module_description(module_name: str) -> Optional[str]:
1884
1884
  "comparing whether a work requirement or task group is matched by "
1885
1885
  "workers in the specified provisioned worker pools"
1886
1886
  )
1887
+ elif "application" in module_name:
1888
+ suffix = "reporting the details of the current Application"
1887
1889
 
1888
1890
  return None if suffix is None else prefix + suffix
1889
1891
 
@@ -3,7 +3,7 @@ Various utility functions for finding objects, etc.
3
3
  """
4
4
 
5
5
  from functools import lru_cache
6
- from typing import Callable, List, Optional, Tuple, Union
6
+ from typing import Callable, Dict, List, Optional, Tuple, Union
7
7
 
8
8
  from yellowdog_client import PlatformClient
9
9
  from yellowdog_client.common import SearchClient
@@ -11,6 +11,7 @@ from yellowdog_client.model import (
11
11
  AccountAllowance,
12
12
  AllowanceSearch,
13
13
  Application,
14
+ ApplicationDetails,
14
15
  ApplicationSearch,
15
16
  ComputeRequirementStatus,
16
17
  ComputeRequirementSummary,
@@ -22,6 +23,7 @@ from yellowdog_client.model import (
22
23
  ComputeSourceTemplateSearch,
23
24
  ComputeSourceTemplateSummary,
24
25
  ExternalUser,
26
+ Group,
25
27
  GroupSearch,
26
28
  GroupSummary,
27
29
  ImageAccess,
@@ -385,7 +387,7 @@ def find_image_name_or_id(
385
387
  PUBLIC images.
386
388
 
387
389
  Finally, if nothing matches, the original ID is returned. This is
388
- likely to be a provider specific string.
390
+ likely to be a provider-specific string.
389
391
  """
390
392
  if image_name_or_id is None:
391
393
  return None
@@ -522,6 +524,7 @@ def find_image_name_or_id(
522
524
  )
523
525
 
524
526
  # Finally, fall through and return the unchanged, original ID string
527
+ print_log(f"No Images ID substitution possible for '{original_image_name_or_id}'")
525
528
  return original_image_name_or_id
526
529
 
527
530
 
@@ -915,21 +918,71 @@ def get_application_id_by_name(client: PlatformClient, app_name: str) -> Optiona
915
918
  return None
916
919
 
917
920
 
918
- def clear_application_caches():
921
+ @lru_cache
922
+ def get_application_details(client: PlatformClient) -> ApplicationDetails:
919
923
  """
920
- Clear the application caches.
924
+ Load and cache the Application's details
921
925
  """
922
- get_all_applications.cache_clear()
923
- get_application_id_by_name.cache_clear()
926
+ return client.application_client.get_application_details()
924
927
 
925
928
 
926
- def get_application_groups(client: PlatformClient, app_id: str) -> List[GroupSummary]:
929
+ @lru_cache
930
+ def get_application_group_summaries(
931
+ client: PlatformClient, app_id: str
932
+ ) -> List[GroupSummary]:
927
933
  """
928
- Get the groups to which an application belongs.
934
+ Get the summaries of the groups to which an application belongs.
929
935
  """
930
936
  return client.account_client.get_application_groups(app_id).list_all()
931
937
 
932
938
 
939
+ @lru_cache
940
+ def get_application_groups(client: PlatformClient, app_id: str) -> List[Group]:
941
+ """
942
+ Get the groups to which an application belongs.
943
+ """
944
+ return [
945
+ client.account_client.get_group(group_summary.id)
946
+ for group_summary in get_application_group_summaries(client, app_id)
947
+ ]
948
+
949
+
950
+ @lru_cache
951
+ def get_all_roles_and_namespaces_for_application(
952
+ client: PlatformClient, application_id: str
953
+ ) -> Dict:
954
+ """
955
+ Get a list of roles and the namespaces to which they apply, for a given application.
956
+ Returns {role_name: [namespace, ...]}, sorted by role name.
957
+ """
958
+ # Iterate through groups, roles
959
+ roles_ = dict()
960
+ for group in get_application_groups(client, application_id):
961
+ for role in group.roles:
962
+ if roles_.get(role.role.name) is None:
963
+ roles_[role.role.name] = []
964
+ if role.scope.global_:
965
+ roles_[role.role.name] += ["GLOBAL"]
966
+ else:
967
+ roles_[role.role.name] += [
968
+ namespace.namespace for namespace in role.scope.namespaces
969
+ ]
970
+
971
+ return {role: namespaces for role, namespaces in sorted(roles_.items())}
972
+
973
+
974
+ def clear_application_caches():
975
+ """
976
+ Clear the application caches.
977
+ """
978
+ get_all_applications.cache_clear()
979
+ get_application_id_by_name.cache_clear()
980
+ get_application_details.cache_clear()
981
+ get_application_group_summaries.cache_clear()
982
+ get_application_groups.cache_clear()
983
+ get_all_roles_and_namespaces_for_application.cache_clear()
984
+
985
+
933
986
  def get_user_groups(client: PlatformClient, user_id: str) -> List[GroupSummary]:
934
987
  """
935
988
  Get the groups to which a user belongs.
@@ -1013,13 +1066,25 @@ def get_image_family_summaries(
1013
1066
  """
1014
1067
  Obtain and cache the list of image families.
1015
1068
  """
1016
- # Temporarily suppress most permission errors: will be improved
1017
- # once the application can be queried for its admissible
1018
- # IMAGE_READ namespaces
1069
+ # Determine namespace(s) to search
1070
+ if namespace is None:
1071
+ # Attempt to use the namespace(s) that are 'readable' by
1072
+ # this application; does not guarantee IMAGE_READ
1073
+ application_details = get_application_details(client)
1074
+ if application_details.allNamespacesReadable:
1075
+ namespaces = None # Search all namespaces
1076
+ elif application_details.readableNamespaces is not None:
1077
+ namespaces = application_details.readableNamespaces
1078
+ else:
1079
+ namespaces = []
1080
+ else:
1081
+ # Use the supplied namespace
1082
+ namespaces = [namespace]
1083
+
1019
1084
  try:
1020
1085
  if_search = MachineImageFamilySearch(
1021
1086
  familyName=None,
1022
- namespaces=None if namespace is None else [namespace],
1087
+ namespaces=namespaces,
1023
1088
  includePublic=True,
1024
1089
  )
1025
1090
  search_client: SearchClient = client.images_client.get_image_families(if_search)
@@ -256,7 +256,10 @@ def load_dotenv_file():
256
256
  if dotenv_file == "":
257
257
  return
258
258
 
259
- print_log(f"Loading environment variables from '{dotenv_file}'")
259
+ print_log(
260
+ f"Loading environment variables from '{dotenv_file}' ("
261
+ f"{'' if ARGS_PARSER.env_override else 'NOT '}OVERRIDING existing variables)"
262
+ )
260
263
 
261
264
  dotenv_yd_substitutions = [ # Find 'YD' variables
262
265
  f"'{key}'"
@@ -5,11 +5,10 @@ for all commands.
5
5
 
6
6
  import os
7
7
  from sys import exit
8
- from typing import List
9
8
 
10
9
  from pypac import pac_context_for_url
11
10
  from yellowdog_client import PlatformClient
12
- from yellowdog_client.model import ApiKey, KeyringSummary, ServicesSchema
11
+ from yellowdog_client.model import ApiKey, ServicesSchema
13
12
 
14
13
  from yellowdog_cli.utils.args import ARGS_PARSER
15
14
  from yellowdog_cli.utils.config_types import ConfigCommon
@@ -22,62 +21,38 @@ CLIENT = PlatformClient.create(
22
21
  ApiKey(CONFIG_COMMON.key, CONFIG_COMMON.secret),
23
22
  )
24
23
 
25
- from requests.exceptions import HTTPError
26
-
27
24
 
28
25
  def dry_run() -> bool:
29
26
  """
30
27
  Is this a dry-run?
31
28
  """
32
- dry_run = ARGS_PARSER.dry_run or ARGS_PARSER.process_csv_only
33
- if dry_run is None:
29
+ dry_run_ = ARGS_PARSER.dry_run or ARGS_PARSER.process_csv_only
30
+ if dry_run_ is None:
34
31
  return False
35
32
  else:
36
- return dry_run
37
-
38
-
39
- def print_account():
40
- """
41
- Print the six character hexadecimal account ID. Depends on there
42
- being at least one Keyring in the account. Omit if this is a dry run.
43
- """
44
- if not dry_run():
45
- try:
46
- keyrings: List[KeyringSummary] = CLIENT.keyring_client.find_all_keyrings()
47
- if len(keyrings) > 0:
48
- # This is a little brittle, obviously
49
- print_log(
50
- f"YellowDog Account short identifier is: '{keyrings[0].id[13:19]}'"
51
- )
52
- except HTTPError as e:
53
- if "Unauthorized" in str(e):
54
- print_error(
55
- "Unable to authorise YellowDog Application; please check"
56
- " your Application Key/Secret and its permissions"
57
- )
58
- exit(1)
59
- except:
60
- pass
33
+ return dry_run_
61
34
 
62
35
 
63
36
  def set_proxy():
64
37
  """
65
38
  Set the HTTPS proxy using autoconfiguration (PAC) if enabled.
66
39
  """
67
- if not dry_run():
68
- proxy_var = "HTTPS_PROXY"
69
- if CONFIG_COMMON.use_pac:
70
- print_log("Using Proxy Auto-Configuration (PAC)")
71
- with pac_context_for_url(CONFIG_COMMON.url):
72
- https_proxy = os.getenv(proxy_var, None)
73
- if https_proxy is not None:
74
- os.environ[proxy_var] = https_proxy
75
- else:
76
- print_log("No PAC proxy settings found")
77
- else:
40
+ if dry_run():
41
+ return
42
+
43
+ proxy_var = "HTTPS_PROXY"
44
+ if CONFIG_COMMON.use_pac:
45
+ print_log("Using Proxy Auto-Configuration (PAC)")
46
+ with pac_context_for_url(CONFIG_COMMON.url):
78
47
  https_proxy = os.getenv(proxy_var, None)
79
48
  if https_proxy is not None:
80
- print_log(f"Using {proxy_var}={https_proxy}")
49
+ os.environ[proxy_var] = https_proxy
50
+ else:
51
+ print_log("No PAC proxy settings found")
52
+ else:
53
+ https_proxy = os.getenv(proxy_var, None)
54
+ if https_proxy is not None:
55
+ print_log(f"Using {proxy_var}={https_proxy}")
81
56
 
82
57
 
83
58
  def main_wrapper(func):
@@ -86,7 +61,6 @@ def main_wrapper(func):
86
61
  exit_code = 0
87
62
  try:
88
63
  set_proxy()
89
- # print_account()
90
64
  func()
91
65
  except Exception as e:
92
66
  if "MissingPermissionException" in str(e):
@@ -96,6 +70,10 @@ def main_wrapper(func):
96
70
  " Application belongs to the required group(s), e.g.,"
97
71
  f" 'administrators', with roles in the required namespace(s): {e}"
98
72
  )
73
+ elif "Unauthorized" in str(e):
74
+ print_error(
75
+ f"Your Application Key ID and SECRET are not recognised: {e}"
76
+ )
99
77
  else:
100
78
  print_error(e)
101
79
  exit_code = 1
@@ -109,11 +87,12 @@ def main_wrapper(func):
109
87
  print_log("Done")
110
88
  exit(exit_code)
111
89
  else:
112
- set_proxy()
113
- # print_account()
114
- func()
115
- CLIENT.close()
116
- print_log("Done")
117
- exit(0)
90
+ try:
91
+ set_proxy()
92
+ func()
93
+ print_log("Done")
94
+ exit(0)
95
+ finally:
96
+ CLIENT.close()
118
97
 
119
98
  return wrapper
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yellowdog-python-examples
3
- Version: 8.2.1
3
+ Version: 8.3.0
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.7.0
29
+ Requires-Dist: yellowdog-sdk>=11.8.1
30
30
  Provides-Extra: jsonnet
31
31
  Requires-Dist: jsonnet; extra == "jsonnet"
32
32
  Provides-Extra: cloudwizard
@@ -62,6 +62,7 @@ The commands support:
62
62
  - **Provisioning** Worker Pools with the **`yd-provision`** command
63
63
  - **Resizing** Worker Pools and Compute Requirements with the **`yd-resize`** command
64
64
  - **Showing** the details of any YellowDog entity using its YellowDog ID with the **`yd-show`** command
65
+ - **Showing** the details of the current Application with the **`yd-application`** command
65
66
  - **Shutting Down** Worker Pools and Nodes with the **`yd-shutdown`** command
66
67
  - **Starting** HELD Work Requirements and **Holding** (or pausing) RUNNING Work Requirements with the **`yd-start`** and **`yd-hold`** commands
67
68
  - **Submitting** Work Requirements with the **`yd-submit`** command
@@ -14,6 +14,7 @@ tests/test_variable_processing.py
14
14
  yellowdog_cli/__init__.py
15
15
  yellowdog_cli/abort.py
16
16
  yellowdog_cli/admin.py
17
+ yellowdog_cli/application.py
17
18
  yellowdog_cli/boost.py
18
19
  yellowdog_cli/cancel.py
19
20
  yellowdog_cli/cloudwizard.py
@@ -1,5 +1,6 @@
1
1
  [console_scripts]
2
2
  yd-abort = yellowdog_cli.abort:main
3
+ yd-application = yellowdog_cli.application:main
3
4
  yd-boost = yellowdog_cli.boost:main
4
5
  yd-cancel = yellowdog_cli.cancel:main
5
6
  yd-cloudwizard = yellowdog_cli.cloudwizard:main
@@ -5,7 +5,7 @@ requests
5
5
  rich==13.9.4
6
6
  tabulate>=0.9.0
7
7
  toml
8
- yellowdog-sdk>=11.7.0
8
+ yellowdog-sdk>=11.8.1
9
9
 
10
10
  [cloudwizard]
11
11
  boto3
@@ -1 +0,0 @@
1
- __version__ = "8.2.1"