Skip to content

Commit af99c4b

Browse files
Feature/add supported infra to samples (#12)
1 parent 4063e69 commit af99c4b

File tree

6 files changed

+119
-87
lines changed

6 files changed

+119
-87
lines changed

samples/_TEMPLATE/create.ipynb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
"\n",
6161
"# 2) Service-defined parameters (please do not change these)\n",
6262
"rg_name = utils.get_infra_rg_name(deployment, index)\n",
63+
"supported_infrastructures = [] # ENTER SUPPORTED INFRASTRUCTURES HERE, e.g., [INFRASTRUCTURE.AFD_APIM_PE, INFRASTRUCTURE.AFD_APIM_FE]\n",
64+
"utils.validate_infrastructure(deployment, supported_infrastructures)\n",
6365
"\n",
6466
"# 3) Define the APIs and their operations and policies\n",
6567
"\n",

samples/general/create.ipynb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
"\n",
5252
"# 2) Service-defined parameters (please do not change these)\n",
5353
"rg_name = utils.get_infra_rg_name(deployment, index)\n",
54+
"supported_infrastructures = [INFRASTRUCTURE.AFD_APIM_PE, INFRASTRUCTURE.APIM_ACA, INFRASTRUCTURE.SIMPLE_APIM]\n",
55+
"utils.validate_infrastructure(deployment, supported_infrastructures)\n",
5456
"\n",
5557
"# 3) Define the APIs and their operations and policies\n",
5658
"\n",

samples/load-balancing/create.ipynb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
"\n",
6565
"# 2) Service-defined parameters (please do not change these)\n",
6666
"rg_name = utils.get_infra_rg_name(deployment, index)\n",
67+
"supported_infrastructures = [INFRASTRUCTURE.AFD_APIM_PE, INFRASTRUCTURE.APIM_ACA]\n",
68+
"utils.validate_infrastructure(deployment, supported_infrastructures)\n",
6769
"\n",
6870
"# 3) Define the APIs and their operations and policies\n",
6971
"\n",

shared/python/apimtypes.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Types and constants for Azure API Management automation and deployment.
33
"""
44

5-
from enum import Enum
5+
from enum import StrEnum
66
from dataclasses import dataclass
77
from typing import List, Optional
88

@@ -51,7 +51,7 @@ def _read_policy_xml(policy_xml_filepath: str) -> str:
5151
# CLASSES
5252
# ------------------------------
5353

54-
class APIMNetworkMode(str, Enum):
54+
class APIMNetworkMode(StrEnum):
5555
"""
5656
Networking configuration modes for Azure API Management (APIM).
5757
"""
@@ -62,7 +62,7 @@ class APIMNetworkMode(str, Enum):
6262
NONE = "None" # No explicit network configuration (legacy or default)
6363

6464

65-
class APIM_SKU(str, Enum):
65+
class APIM_SKU(StrEnum):
6666
"""
6767
APIM SKU types.
6868
"""
@@ -76,7 +76,7 @@ class APIM_SKU(str, Enum):
7676
PREMIUMV2 = "Premiumv2"
7777

7878

79-
class HTTP_VERB(str, Enum):
79+
class HTTP_VERB(StrEnum):
8080
"""
8181
HTTP verbs that can be used for API operations.
8282
"""
@@ -90,7 +90,7 @@ class HTTP_VERB(str, Enum):
9090
HEAD = "HEAD"
9191

9292

93-
class INFRASTRUCTURE(str, Enum):
93+
class INFRASTRUCTURE(StrEnum):
9494
"""
9595
Infrastructure types for APIM automation scenarios.
9696
"""

shared/python/utils.py

Lines changed: 87 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,73 @@ def get(self, key: str, label: str = '', secure: bool = False) -> str | None:
117117
# PRIVATE METHODS
118118
# ------------------------------
119119

120+
def _cleanup_resources(deployment_name: str, rg_name: str) -> None:
121+
"""
122+
Clean up resources associated with a deployment in a resource group.
123+
Deletes and purges Cognitive Services, API Management, and Key Vault resources, then deletes the resource group itself.
124+
125+
Args:
126+
deployment_name (str): The deployment name (string).
127+
rg_name (str): The resource group name.
128+
129+
Returns:
130+
None
131+
132+
Raises:
133+
Exception: If an error occurs during cleanup.
134+
"""
135+
if not deployment_name:
136+
print_error("Missing deployment name parameter.")
137+
return
138+
139+
if not rg_name:
140+
print_error("Missing resource group name parameter.")
141+
return
142+
143+
try:
144+
print_info(f"🧹 Cleaning up resource group '{rg_name}'...")
145+
146+
# Show the deployment details
147+
output = run(f"az deployment group show --name {deployment_name} -g {rg_name} -o json", "Deployment retrieved", "Failed to retrieve the deployment")
148+
149+
if output.success and output.json_data:
150+
provisioning_state = output.json_data.get("properties").get("provisioningState")
151+
print_info(f"Deployment provisioning state: {provisioning_state}")
152+
153+
# Delete and purge CognitiveService accounts
154+
output = run(f" az cognitiveservices account list -g {rg_name}", f"Listed CognitiveService accounts", f"Failed to list CognitiveService accounts")
155+
if output.success and output.json_data:
156+
for resource in output.json_data:
157+
print_info(f"Deleting and purging Cognitive Service Account '{resource['name']}' in resource group '{rg_name}'...")
158+
output = run(f"az cognitiveservices account delete -g {rg_name} -n {resource['name']}", f"Cognitive Services '{resource['name']}' deleted", f"Failed to delete Cognitive Services '{resource['name']}'")
159+
output = run(f"az cognitiveservices account purge -g {rg_name} -n {resource['name']} -l \"{resource['location']}\"", f"Cognitive Services '{resource['name']}' purged", f"Failed to purge Cognitive Services '{resource['name']}'")
160+
161+
# Delete and purge APIM resources
162+
output = run(f" az apim list -g {rg_name}", f"Listed APIM resources", f"Failed to list APIM resources")
163+
if output.success and output.json_data:
164+
for resource in output.json_data:
165+
print_info(f"Deleting and purging API Management '{resource['name']}' in resource group '{rg_name}'...")
166+
output = run(f"az apim delete -n {resource['name']} -g {rg_name} -y", f"API Management '{resource['name']}' deleted", f"Failed to delete API Management '{resource['name']}'")
167+
output = run(f"az apim deletedservice purge --service-name {resource['name']} --location \"{resource['location']}\"", f"API Management '{resource['name']}' purged", f"Failed to purge API Management '{resource['name']}'")
168+
169+
# Delete and purge Key Vault resources
170+
output = run(f" az keyvault list -g {rg_name}", f"Listed Key Vault resources", f"Failed to list Key Vault resources")
171+
if output.success and output.json_data:
172+
for resource in output.json_data:
173+
print_info(f"Deleting and purging Key Vault '{resource['name']}' in resource group '{rg_name}'...")
174+
output = run(f"az keyvault delete -n {resource['name']} -g {rg_name}", f"Key Vault '{resource['name']}' deleted", f"Failed to delete Key Vault '{resource['name']}'")
175+
output = run(f"az keyvault purge -n {resource['name']} --location \"{resource['location']}\"", f"Key Vault '{resource['name']}' purged", f"Failed to purge Key Vault '{resource['name']}'")
176+
177+
# Delete the resource group last
178+
print_message(f"🧹 Deleting resource group '{rg_name}'...")
179+
output = run(f"az group delete --name {rg_name} -y", f"Resource group '{rg_name}' deleted", f"Failed to delete resource group '{rg_name}'")
180+
181+
print_message("🧹 Cleanup completed.")
182+
183+
except Exception as e:
184+
print(f"An error occurred during cleanup: {e}")
185+
traceback.print_exc()
186+
120187
def _print_log(message: str, prefix: str = '', color: str = '', output: str = '', duration: str = '', show_time: bool = False, blank_above: bool = False, blank_below: bool = False) -> None:
121188
"""
122189
Print a formatted log message with optional prefix, color, output, duration, and time.
@@ -163,12 +230,6 @@ def _print_log(message: str, prefix: str = '', color: str = '', output: str = ''
163230
print_warning = lambda msg, output = '', duration = '' : _print_log(msg, '⚠️ ', BOLD_Y, output, duration, True)
164231
print_val = lambda name, value, val_below = False : _print_log(f"{name:<25}:{'\n' if val_below else ' '}{value}", '👉🏽 ', BOLD_B)
165232

166-
# Validation functions will raise ValueError if the value is not valid
167-
168-
validate_http_verb = lambda val: HTTP_VERB(val)
169-
validate_infrastructure = lambda val: INFRASTRUCTURE(val)
170-
validate_sku = lambda val: APIM_SKU(val)
171-
172233
def create_bicep_deployment_group(rg_name: str, rg_location: str, deployment: str | INFRASTRUCTURE, bicep_parameters: dict, bicep_parameters_file: str = 'params.json') -> Output:
173234
"""
174235
Create a Bicep deployment in a resource group, writing parameters to a file and running the deployment.
@@ -279,78 +340,6 @@ def read_policy_xml(policy_xml_filepath: str) -> str:
279340

280341
return policy_template_xml
281342

282-
def _cleanup_resources(deployment_name: str, rg_name: str) -> None:
283-
"""
284-
Clean up resources associated with a deployment in a resource group.
285-
Deletes and purges Cognitive Services, API Management, and Key Vault resources, then deletes the resource group itself.
286-
287-
Args:
288-
deployment_name (str): The deployment name (string).
289-
rg_name (str): The resource group name.
290-
291-
Returns:
292-
None
293-
294-
Raises:
295-
Exception: If an error occurs during cleanup.
296-
"""
297-
if not deployment_name:
298-
print_error("Missing deployment name parameter.")
299-
return
300-
301-
if not rg_name:
302-
print_error("Missing resource group name parameter.")
303-
return
304-
305-
try:
306-
print_info(f"🧹 Cleaning up resource group '{rg_name}'...")
307-
308-
# Show the deployment details
309-
output = run(f"az deployment group show --name {deployment_name} -g {rg_name} -o json", "Deployment retrieved", "Failed to retrieve the deployment")
310-
311-
if output.success and output.json_data:
312-
provisioning_state = output.json_data.get("properties").get("provisioningState")
313-
print_info(f"Deployment provisioning state: {provisioning_state}")
314-
315-
# Delete and purge CognitiveService accounts
316-
output = run(f" az cognitiveservices account list -g {rg_name}", f"Listed CognitiveService accounts", f"Failed to list CognitiveService accounts")
317-
if output.success and output.json_data:
318-
for resource in output.json_data:
319-
print_info(f"Deleting and purging Cognitive Service Account '{resource['name']}' in resource group '{rg_name}'...")
320-
output = run(f"az cognitiveservices account delete -g {rg_name} -n {resource['name']}", f"Cognitive Services '{resource['name']}' deleted", f"Failed to delete Cognitive Services '{resource['name']}'")
321-
output = run(f"az cognitiveservices account purge -g {rg_name} -n {resource['name']} -l \"{resource['location']}\"", f"Cognitive Services '{resource['name']}' purged", f"Failed to purge Cognitive Services '{resource['name']}'")
322-
323-
# Delete and purge APIM resources
324-
output = run(f" az apim list -g {rg_name}", f"Listed APIM resources", f"Failed to list APIM resources")
325-
if output.success and output.json_data:
326-
for resource in output.json_data:
327-
print_info(f"Deleting and purging API Management '{resource['name']}' in resource group '{rg_name}'...")
328-
output = run(f"az apim delete -n {resource['name']} -g {rg_name} -y", f"API Management '{resource['name']}' deleted", f"Failed to delete API Management '{resource['name']}'")
329-
output = run(f"az apim deletedservice purge --service-name {resource['name']} --location \"{resource['location']}\"", f"API Management '{resource['name']}' purged", f"Failed to purge API Management '{resource['name']}'")
330-
331-
# Delete and purge Key Vault resources
332-
output = run(f" az keyvault list -g {rg_name}", f"Listed Key Vault resources", f"Failed to list Key Vault resources")
333-
if output.success and output.json_data:
334-
for resource in output.json_data:
335-
print_info(f"Deleting and purging Key Vault '{resource['name']}' in resource group '{rg_name}'...")
336-
output = run(f"az keyvault delete -n {resource['name']} -g {rg_name}", f"Key Vault '{resource['name']}' deleted", f"Failed to delete Key Vault '{resource['name']}'")
337-
output = run(f"az keyvault purge -n {resource['name']} --location \"{resource['location']}\"", f"Key Vault '{resource['name']}' purged", f"Failed to purge Key Vault '{resource['name']}'")
338-
339-
# Delete the resource group last
340-
print_message(f"🧹 Deleting resource group '{rg_name}'...")
341-
output = run(f"az group delete --name {rg_name} -y", f"Resource group '{rg_name}' deleted", f"Failed to delete resource group '{rg_name}'")
342-
343-
print_message("🧹 Cleanup completed.")
344-
345-
except Exception as e:
346-
print(f"An error occurred during cleanup: {e}")
347-
traceback.print_exc()
348-
349-
350-
# ------------------------------
351-
# PUBLIC METHODS
352-
# ------------------------------
353-
354343
def cleanup_infra_deployments(deployment: INFRASTRUCTURE, indexes: int | list[int] | None = None) -> None:
355344
"""
356345
Clean up infrastructure deployments by deployment enum and index/indexes.
@@ -360,7 +349,6 @@ def cleanup_infra_deployments(deployment: INFRASTRUCTURE, indexes: int | list[in
360349
deployment (INFRASTRUCTURE): The infrastructure deployment enum value.
361350
indexes (int | list[int] | None): A single index, a list of indexes, or None for no index.
362351
"""
363-
validate_infrastructure(deployment)
364352

365353
if indexes is None:
366354
indexes_list = [None]
@@ -545,8 +533,6 @@ def get_infra_rg_name(deployment_name: INFRASTRUCTURE, index: int | None = None)
545533
str: The generated resource group name.
546534
"""
547535

548-
validate_infrastructure(deployment_name)
549-
550536
rg_name = f"apim-infra-{deployment_name.value}"
551537

552538
if index is not None:
@@ -638,3 +624,23 @@ def run(command: str, ok_message: str = '', error_message: str = '', print_outpu
638624
print_message(ok_message if success else error_message, output_text if not success or print_output else "", f"[{int(minutes)}m:{int(seconds)}s]")
639625

640626
return Output(success, output_text)
627+
628+
# Validation functions will raise ValueError if the value is not valid
629+
630+
validate_http_verb = lambda val: HTTP_VERB(val)
631+
validate_sku = lambda val: APIM_SKU(val)
632+
633+
def validate_infrastructure(infra: INFRASTRUCTURE, supported_infras: list[INFRASTRUCTURE]) -> None:
634+
"""
635+
Validate that the provided infrastructure is a supported infrastructure.
636+
637+
Args:
638+
infra (INFRASTRUCTURE): The infrastructure deployment enum value.
639+
supported_infras (list[INFRASTRUCTURE]): List of supported infrastructures.
640+
641+
Raises:
642+
ValueError: If the infrastructure is not supported.
643+
"""
644+
645+
if infra not in supported_infras:
646+
raise ValueError(f"Unsupported infrastructure: {infra}. Supported infrastructures are: {', '.join([i.value for i in supported_infras])}")

tests/python/test_utils.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import pytest
2+
from apimtypes import INFRASTRUCTURE
13
import os
24
import builtins
3-
import pytest
45
from io import StringIO
56
from unittest.mock import patch, MagicMock, mock_open
67
from shared.python import utils
@@ -252,3 +253,22 @@ def test_extract_json_multiple_json_types():
252253
assert utils.extract_json(s) == [1, 2, 3]
253254
s2 = '{"a": 1}[1,2,3]'
254255
assert utils.extract_json(s2) == {"a": 1}
256+
257+
# ------------------------------
258+
# validate_infrastructure
259+
# ------------------------------
260+
261+
def test_validate_infrastructure_supported():
262+
# Should return None for supported infra
263+
assert utils.validate_infrastructure(INFRASTRUCTURE.SIMPLE_APIM, [INFRASTRUCTURE.SIMPLE_APIM]) is None
264+
265+
def test_validate_infrastructure_unsupported():
266+
# Should raise ValueError for unsupported infra
267+
with pytest.raises(ValueError) as exc:
268+
utils.validate_infrastructure(INFRASTRUCTURE.SIMPLE_APIM, [INFRASTRUCTURE.APIM_ACA])
269+
assert "Unsupported infrastructure" in str(exc.value)
270+
271+
def test_validate_infrastructure_multiple_supported():
272+
# Should return True if infra is in the supported list
273+
supported = [INFRASTRUCTURE.SIMPLE_APIM, INFRASTRUCTURE.APIM_ACA]
274+
assert utils.validate_infrastructure(INFRASTRUCTURE.APIM_ACA, supported) is None

0 commit comments

Comments
 (0)