Skip to content

Commit 172d1d1

Browse files
committed
Update
1 parent af62165 commit 172d1d1

4 files changed

Lines changed: 394 additions & 37 deletions

File tree

src/mas/devops/data/__init__.py

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,38 @@
77
# http://www.eclipse.org/legal/epl-v10.html
88
#
99
# *****************************************************************************
10+
"""
11+
IBM Operator Catalog data management module.
12+
13+
This module provides functions to access and query IBM Operator Catalog definitions
14+
stored as YAML files. Catalogs contain operator version information and are organized
15+
by version tag and architecture.
16+
"""
17+
1018
import yaml
1119
from glob import glob
1220
from os import path
1321

1422

15-
def getCatalog(name: str) -> dict:
23+
def getCatalog(name: str) -> dict | None:
24+
"""
25+
Load a specific IBM Operator Catalog definition by name.
26+
27+
This function reads a catalog YAML file from the catalogs directory and returns
28+
its contents as a dictionary.
29+
30+
Args:
31+
name (str): The catalog name/tag (e.g., "v9-241205-amd64", "v8-240528-amd64").
32+
33+
Returns:
34+
dict: The catalog definition dictionary containing operator versions and metadata.
35+
Returns None if the catalog file doesn't exist.
36+
37+
Example:
38+
>>> catalog = getCatalog("v9-241205-amd64")
39+
>>> if catalog:
40+
... print(f"Catalog version: {catalog.get('version')}")
41+
"""
1642
moduleFile = path.abspath(__file__)
1743
modulePath = path.dirname(moduleFile)
1844
catalogFileName = f"{name}.yaml"
@@ -26,6 +52,26 @@ def getCatalog(name: str) -> dict:
2652

2753

2854
def listCatalogTags(arch="amd64") -> list:
55+
"""
56+
List all available IBM Operator Catalog tags for a specific architecture.
57+
58+
This function scans the catalogs directory and returns a sorted list of all
59+
catalog tags matching the specified architecture.
60+
61+
Args:
62+
arch (str, optional): The target architecture (e.g., "amd64", "s390x", "ppc64le").
63+
Defaults to "amd64".
64+
65+
Returns:
66+
list: Sorted list of catalog tag strings (e.g., ["v8-240528-amd64", "v9-241205-amd64"]).
67+
Returns empty list if no catalogs are found for the architecture.
68+
69+
Example:
70+
>>> tags = listCatalogTags("amd64")
71+
>>> print(f"Available catalogs: {len(tags)}")
72+
>>> for tag in tags[-3:]: # Show last 3
73+
... print(tag)
74+
"""
2975
moduleFile = path.abspath(__file__)
3076
modulePath = path.dirname(moduleFile)
3177
yamlFiles = glob(path.join(modulePath, "catalogs", f"*-{arch}.yaml"))
@@ -35,7 +81,27 @@ def listCatalogTags(arch="amd64") -> list:
3581
return result
3682

3783

38-
def getNewestCatalogTag(arch="amd64") -> str:
84+
def getNewestCatalogTag(arch="amd64") -> str | None:
85+
"""
86+
Get the most recent IBM Operator Catalog tag for a specific architecture.
87+
88+
This function returns the newest (last in sorted order) catalog tag available
89+
for the specified architecture.
90+
91+
Args:
92+
arch (str, optional): The target architecture (e.g., "amd64", "s390x", "ppc64le").
93+
Defaults to "amd64".
94+
95+
Returns:
96+
str: The newest catalog tag (e.g., "v9-241205-amd64").
97+
Returns None if no catalogs are found for the architecture.
98+
99+
Example:
100+
>>> newest = getNewestCatalogTag("amd64")
101+
>>> if newest:
102+
... print(f"Latest catalog: {newest}")
103+
... catalog = getCatalog(newest)
104+
"""
39105
catalogs = listCatalogTags(arch)
40106
if len(catalogs) == 0:
41107
return None

src/mas/devops/mas/apps.py

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,27 @@
5555

5656
def getAppResource(dynClient: DynamicClient, instanceId: str, applicationId: str, workspaceId: str = None) -> bool:
5757
"""
58-
Get the application or workspace Custom Resource
59-
60-
:param dynClient: Description
61-
:type dynClient: DynamicClient
62-
:param instanceId: Description
63-
:type instanceId: str
64-
:param applicationId: Description
65-
:type applicationId: str
66-
:return: Description
67-
:rtype: bool
68-
:type workspaceId: str
69-
:return: Description
70-
:rtype: bool
58+
Retrieve a MAS application or workspace custom resource.
59+
60+
This function fetches either an application-level CR (e.g., ManageApp) or a
61+
workspace-level CR (e.g., ManageWorkspace) depending on whether workspaceId is provided.
62+
63+
Args:
64+
dynClient (DynamicClient): OpenShift dynamic client for cluster API interactions.
65+
instanceId (str): The MAS instance identifier (e.g., "inst1").
66+
applicationId (str): The MAS application identifier (e.g., "manage", "iot", "monitor").
67+
workspaceId (str, optional): The workspace identifier. If provided, retrieves workspace CR.
68+
Defaults to None (retrieves application CR).
69+
70+
Returns:
71+
ResourceInstance: The custom resource object if found, None otherwise.
72+
Returns None if the resource doesn't exist, CRD is missing, or authorization fails.
73+
74+
Example:
75+
>>> # Get application CR
76+
>>> app = getAppResource(client, "inst1", "manage")
77+
>>> # Get workspace CR
78+
>>> workspace = getAppResource(client, "inst1", "manage", "masdev")
7179
"""
7280

7381
apiVersion = APP_API_VERSIONS[applicationId] if applicationId in APP_API_VERSIONS else "apps.mas.ibm.com/v1"
@@ -93,7 +101,19 @@ def getAppResource(dynClient: DynamicClient, instanceId: str, applicationId: str
93101

94102
def verifyAppInstance(dynClient: DynamicClient, instanceId: str, applicationId: str) -> bool:
95103
"""
96-
Validate that the chosen app instance exists
104+
Verify that a MAS application instance exists in the cluster.
105+
106+
Args:
107+
dynClient (DynamicClient): OpenShift dynamic client for cluster API interactions.
108+
instanceId (str): The MAS instance identifier.
109+
applicationId (str): The MAS application identifier (e.g., "manage", "iot").
110+
111+
Returns:
112+
bool: True if the application instance exists, False otherwise.
113+
114+
Example:
115+
>>> if verifyAppInstance(client, "inst1", "manage"):
116+
... print("Manage application is installed")
97117
"""
98118
return getAppResource(dynClient, instanceId, applicationId) is not None
99119

@@ -108,22 +128,33 @@ def waitForAppReady(
108128
debugLogFunction=logger.debug,
109129
infoLogFunction=logger.info) -> bool:
110130
"""
111-
Docstring for waitForAppReady
112-
113-
:param dynClient: Description
114-
:type dynClient: DynamicClient
115-
:param instanceId: Description
116-
:type instanceId: str
117-
:param applicationId: Description
118-
:type applicationId: str
119-
:param workspaceId: Description
120-
:type workspaceId: str
121-
:param retries: Description
122-
:type retries: int
123-
:param delay: Description
124-
:type delay: int
125-
:return: Description
126-
:rtype: bool
131+
Wait for a MAS application or workspace to reach ready state.
132+
133+
This function polls the application/workspace custom resource until its Ready condition
134+
status becomes True, or until the retry limit is reached. It checks the status.conditions
135+
array for a condition with type="Ready" and status="True".
136+
137+
Args:
138+
dynClient (DynamicClient): OpenShift dynamic client for cluster API interactions.
139+
instanceId (str): The MAS instance identifier.
140+
applicationId (str): The MAS application identifier (e.g., "manage", "iot").
141+
workspaceId (str, optional): The workspace identifier. If provided, waits for workspace CR.
142+
Defaults to None (waits for application CR).
143+
retries (int, optional): Maximum number of polling attempts. Defaults to 100.
144+
delay (int, optional): Delay in seconds between polling attempts. Defaults to 600 (10 minutes).
145+
debugLogFunction (callable, optional): Function for debug logging. Defaults to logger.debug.
146+
infoLogFunction (callable, optional): Function for info logging. Defaults to logger.info.
147+
148+
Returns:
149+
bool: True if the resource reaches ready state within the retry limit, False otherwise.
150+
151+
Example:
152+
>>> # Wait for Manage application to be ready
153+
>>> if waitForAppReady(client, "inst1", "manage", retries=50, delay=300):
154+
... print("Manage is ready")
155+
>>> # Wait for Manage workspace to be ready
156+
>>> if waitForAppReady(client, "inst1", "manage", "masdev", retries=50):
157+
... print("Manage workspace is ready")
127158
"""
128159

129160
resourceName = f"{APP_KINDS[applicationId]}/{instanceId}"
@@ -176,7 +207,25 @@ def waitForAppReady(
176207

177208
def getAppsSubscriptionChannel(dynClient: DynamicClient, instanceId: str) -> list:
178209
"""
179-
Return list of installed apps with their subscribed channel
210+
Retrieve the OLM subscription channels for all installed MAS applications.
211+
212+
This function queries the Operator Lifecycle Manager subscriptions for each known
213+
MAS application and returns a list of installed applications with their update channels.
214+
215+
Args:
216+
dynClient (DynamicClient): OpenShift dynamic client for cluster API interactions.
217+
instanceId (str): The MAS instance identifier.
218+
219+
Returns:
220+
list: List of dictionaries with 'appId' and 'channel' keys for each installed app.
221+
Returns empty list if no apps are found or if errors occur.
222+
223+
Example:
224+
>>> apps = getAppsSubscriptionChannel(client, "inst1")
225+
>>> for app in apps:
226+
... print(f"{app['appId']}: {app['channel']}")
227+
manage: 8.7.x
228+
iot: 8.8.x
180229
"""
181230
try:
182231
installedApps = []

0 commit comments

Comments
 (0)