diff --git a/src/akamai/converter.py b/src/akamai/converter.py index a64112f..b47f618 100644 --- a/src/akamai/converter.py +++ b/src/akamai/converter.py @@ -86,6 +86,7 @@ def process_rules( main_setting_name (str): The main setting name for Azion configuration. origin_hostname (str): The origin hostname for Azion configuration. """ + context = {} if isinstance(rules, str): logging.debug("Rules attribute is a string reference. Converting to JSON content.") rules = clean_and_parse_json(rules) @@ -105,10 +106,10 @@ def process_rules( logging.info(f"[Akamai Rules] Found {len(behaviors)} behaviors and {len(children)} children for rule: '{normalized_name}'") if len(behaviors) > 0: - process_rule_behaviors(azion_resources, rules, main_setting_name, origin_hostname, 0, normalized_name) + context = process_rule_behaviors(azion_resources, rules, main_setting_name, origin_hostname, 0, normalized_name) if len(children) > 0: - process_rule_children(azion_resources, children, main_setting_name, origin_hostname, 0, normalized_name) + process_rule_children(azion_resources, children, main_setting_name, origin_hostname, 0, normalized_name, context) elif isinstance(rules, list): logging.debug("Rules provided as a list. Processing each rule.") @@ -120,10 +121,10 @@ def process_rules( logging.info(f"[Akamai Rules] Found {len(behaviors)} behaviors and {len(children)} children for rule: '{normalized_name}'") if behaviors: - process_rule_behaviors(azion_resources, rule, main_setting_name, origin_hostname, index, normalized_name) + context = process_rule_behaviors(azion_resources, rule, main_setting_name, origin_hostname, index, normalized_name) if len(children) > 0: - process_rule_children(azion_resources, children, main_setting_name, origin_hostname, index, normalized_name) + process_rule_children(azion_resources, children, main_setting_name, origin_hostname, index, normalized_name, context) else: logging.warning(f"[Akamai Rules] Unexpected type for rules: {type(rules)}. Skipping rule processing.") @@ -138,7 +139,7 @@ def process_rule_behaviors( origin_hostname: str, index: int, normalized_name: str - ) -> List[Dict[str, Any]]: + ) -> Dict[str, Any]: """ Processes the list of behaviors rules and converts them into Azion resources. @@ -166,9 +167,15 @@ def process_rule_behaviors( for behavior in behaviors: behavior_name = behavior.get("name") - if behavior_name == "caching": # Cache Settings + + if behavior_name == "origin": # Origin + origin = create_origin(azion_resources, behavior, main_setting_name, origin_hostname, context["rule_name"]) + if origin: + azion_resources.append(origin) + context["origin"] = origin + elif behavior_name == "caching": # Cache Settings cache_setting.append(behavior) - cache_setting = create_cache_setting(azion_resources, cache_setting, main_setting_name, context["rule_name"]) + cache_setting = create_cache_setting(azion_resources, cache_setting, main_setting_name, context["rule_name"], context) if cache_setting: azion_resources.append(cache_setting) context["cache_setting"] = cache_setting @@ -187,15 +194,11 @@ def process_rule_behaviors( resources = azion_resources.get_azion_resources() main_settings["attributes"]["edge_application"]["application_acceleration"] = True resources[index_main_settings] = main_settings - elif behavior_name == "origin": # Origin - origin = create_origin(azion_resources, behavior, main_setting_name, origin_hostname, context["rule_name"]) - if origin: - azion_resources.append(origin) - context["origin"] = origin azion_resources.extend(create_rule_engine(azion_resources, rule, context, context["rule_name"])) logging.info(f"[Akamai Rules] Processing behaviors for rules '{normalized_name}'. Finished.") + return context def process_rule_children( @@ -204,7 +207,8 @@ def process_rule_children( main_setting_name: str, origin_hostname: str, parent_rule_index: int, - parent_rule_name: str + parent_rule_name: str, + parent_context: Dict[str, Any] ) -> List[Dict[str, Any]]: """ Processes the list of children rules and converts them into Azion resources. @@ -223,6 +227,7 @@ def process_rule_children( context = {} context["parent_rule_index"] = parent_rule_index context["parent_rule_name"] = parent_rule_name + context["parent_context"] = parent_context context["main_setting_name"] = main_setting_name # Rules Processing @@ -241,42 +246,43 @@ def process_rule_children( try: behaviors = rule.get("behaviors", []) for behavior in behaviors: - if behavior.get("name") == "caching": - cache_setting = create_cache_setting(azion_resources, behaviors, main_setting_name, rule_name) + behavior_name = behavior.get("name") + if behavior_name == "origin": + origin_setting = create_origin(azion_resources, behavior, main_setting_name, origin_hostname, sanitize_name(rule_name)) + if origin_setting: + logging.info(f"Origin setting created for rule: {rule_name}") + azion_resources.append(origin_setting) + context["origin"] = origin_setting + + elif behavior_name == "caching": + cache_setting = create_cache_setting(azion_resources, behaviors, main_setting_name, rule_name, context) if cache_setting: logging.info(f"[Akamai Rules][Children] Cache setting created for rule: {rule_name}") azion_resources.append(cache_setting) context["cache_setting"] = cache_setting - if behavior.get("name") == "imageManager": + elif behavior.get("name") == "imageManager": idx, main_settings = azion_resources.query_azion_resource_by_type('azion_edge_application_main_setting') if main_settings: main_settings["attributes"]["edge_application"]["image_optimization"] = True resources = azion_resources.get_azion_resources() resources[idx] = main_settings - if behavior.get("name") == "allowPost": + elif behavior.get("name") == "allowPost": idx, main_settings = azion_resources.query_azion_resource_by_type('azion_edge_application_main_setting') if main_settings: resources = azion_resources.get_azion_resources() main_settings["attributes"]["edge_application"]["application_acceleration"] = True resources[idx] = main_settings - if behavior.get("name") == "origin": - origin_setting = create_origin(azion_resources, behaviors[0], main_setting_name, origin_hostname, sanitize_name(rule_name)) - if origin_setting: - logging.info(f"Origin setting created for rule: {rule_name}") - azion_resources.append(origin_setting) - context["origin"] = origin_setting - - if behavior.get("name") == "webApplicationFirewall": + elif behavior.get("name") == "webApplicationFirewall": waf_rule = create_waf_rule(azion_resources, behavior) if waf_rule: logging.info(f"WAF rule created for rule: {rule_name}") azion_resources.append(waf_rule) context["waf"] = waf_rule - if behavior.get("name") == "baseDirectory": + elif behavior.get("name") == "baseDirectory": idx, origin = azion_resources.query_azion_resource_by_type('azion_edge_application_origin', sanitize_name(rule_name)) if origin: origin["attributes"]["origin"]["origin_path"] = behavior.get("options", {}).get("value", "") @@ -289,7 +295,7 @@ def process_rule_children( children = rule.get("children", []) if len(children) > 0: logging.info(f"[Akamai Rules][Children] Rule '{rule_name}' has {len(children)} inner children rules. Processing...") - process_rule_children(azion_resources, children, main_setting_name, origin_hostname, index, rule_name) + process_rule_children(azion_resources, children, main_setting_name, origin_hostname, index, rule_name, context) except ValueError as e: logging.error(f"[Akamai Rules][Children] Error processing rule engine for rule {rule_name}: {e}") diff --git a/src/akamai/converter_cache_settings.py b/src/akamai/converter_cache_settings.py index a2ef7b9..432b57b 100644 --- a/src/akamai/converter_cache_settings.py +++ b/src/akamai/converter_cache_settings.py @@ -49,7 +49,8 @@ def create_cache_setting( azion_resources: AzionResource, rules: List[Dict[str, Any]], main_setting_name: str, - cache_name: Optional[str] = None + cache_name: Optional[str] = None, + context: Dict[str, Any] = {} ) -> Optional[Dict[str, Any]]: """ Creates a single Azion cache setting resource. @@ -59,6 +60,7 @@ def create_cache_setting( rules (List[Dict[str, Any]]): List of rules extracted from Akamai configuration. main_setting_name (str): Name of the main Azion edge application resource. cache_name (Optional[str]): Name of the cache setting resource. + context (Dict[str, Any]): Context dictionary to store intermediate results. Returns: Optional[Dict[str, Any]]: Azion-compatible cache setting resource. @@ -113,9 +115,19 @@ def create_cache_setting( #depends_on depends_on = [f"azion_edge_application_main_setting.{main_setting_name}"] - _, origin = azion_resources.query_azion_resource_by_type("azion_edge_application_origin", name) + origin = context.get("origin") if origin: - depends_on.append(f"azion_edge_application_origin.{name}") + depends_on.append(f"azion_edge_application_origin.{origin.get('name')}") + else: + logging.warning("No origin found in context. Attempting to query Azion resources...") + _, origin = azion_resources.query_azion_resource_by_type("azion_edge_application_origin", name, match="prefix") + if origin: + depends_on.append(f"azion_edge_application_origin.{origin.get('name')}") + else: + logging.warning(f"No origin found for rule: {name}... Using fallback origin") + _, origin = azion_resources.query_azion_resource_by_type("azion_edge_application_origin", match="prefix") + if origin: + depends_on.append(f"azion_edge_application_origin.{origin.get('name')}") # Construct the cache setting resource cache_setting = { diff --git a/src/akamai/converter_rules_engine.py b/src/akamai/converter_rules_engine.py index 4329e3f..4094522 100644 --- a/src/akamai/converter_rules_engine.py +++ b/src/akamai/converter_rules_engine.py @@ -1,6 +1,6 @@ import logging import random -from typing import Dict, List, Any, Set, Tuple +from typing import Dict, List, Any, Set, Tuple, Optional from azion_resources import AzionResource from akamai.mapping import MAPPING from akamai.utils import ( @@ -32,7 +32,7 @@ def create_rule_engine( azion_resources: AzionResource, rule: Dict[str, Any], context: Dict[str, Any], - name: str = None + name: str = None, ) -> List[Dict[str, Any]]: """ Create a rule engine resource from Akamai rule data. @@ -77,12 +77,17 @@ def create_rule_engine( depends_on = [f"azion_edge_application_main_setting.{main_setting_name}"] depends_on.extend(list(depends_on_behaviors)) - request_behaviors = list( - filter(lambda behavior: behavior.get('phase', 'request') == 'request', azion_behaviors) - ) - response_behaviors = list( - filter(lambda behavior: behavior.get('phase', 'request') == 'response', azion_behaviors) - ) + # Handling behaviors by phase + request_behaviors = [] + response_behaviors = [] + for behavior in azion_behaviors: + if behavior.get('phase', 'both') == 'both': + request_behaviors.append(behavior) + response_behaviors.append(behavior) + elif behavior.get('phase', 'request') == 'request': + request_behaviors.append(behavior) + elif behavior.get('phase', 'request') == 'response': + response_behaviors.append(behavior) # Create request phase rule if len(request_behaviors) > 0: @@ -92,8 +97,9 @@ def create_rule_engine( azion_criteria, request_behaviors, depends_on) - resources.append(resource) - logging.info(f"[rules_engine] Rule engine resource created for rule: '{rule_name}'") + if resource: + resources.append(resource) + logging.info(f"[rules_engine] Rule engine resource created for rule: '{rule_name}'") # Create response phase rule if len(response_behaviors) > 0: @@ -103,8 +109,9 @@ def create_rule_engine( azion_criteria, response_behaviors, depends_on) - resources.append(resource) - logging.info(f"[rules_engine] Rule engine resource created for rule: '{rule_name}'") + if resource: + resources.append(resource) + logging.info(f"[rules_engine] Rule engine resource created for rule: '{rule_name}'") # Enable image optimization if necessary if "imageManager" in behaviors_names: @@ -127,7 +134,7 @@ def assemble_request_rule( azion_criteria: Dict[str, Any], request_behaviors: List[Dict[str, Any]], depends_on: List[str] - ) -> Dict[str, Any]: + ) -> Optional[Dict[str, Any]]: """ Create a rule engine resource from Akamai rule data. @@ -162,9 +169,13 @@ def assemble_request_rule( } # Only add criteria if we have entries - if azion_criteria: - criteria = azion_criteria.get("request",{}) if azion_criteria.get("request",{}) else azion_criteria.get("request_default",{}) + criteria = azion_criteria.get("request", None) + if criteria: resource["attributes"]["results"]["criteria"] = criteria + else: + logging.warning(f"[rules_engine][assemble_request_rule] No criteria found for rule: '{rule_name}'. Skipping.") + resource = None + return resource def assemble_response_rule( @@ -174,7 +185,7 @@ def assemble_response_rule( azion_criteria: Dict[str, Any], behaviors: List[Dict[str, Any]], depends_on: List[str] - ) -> Dict[str, Any]: + ) -> Optional[Dict[str, Any]]: """ Create a rule engine resource from Akamai rule data. @@ -202,13 +213,18 @@ def assemble_response_rule( if len(criterias) == 1: selected_criteria = azion_criteria.get("response") else: + selection = [] for criteria in criterias: for behavior in behaviors: - if criteria.get("name", "") == behavior.get('name'): - selected_criteria = {"entries": [criteria]} + if criteria.get("name", "") == behavior.get('name') or \ + criteria.get("phase", "both") != "request": + selection.append(criteria) break + selected_criteria = {"entries": selection} else: - selected_criteria = azion_criteria.get("response_default") + #selected_criteria = azion_criteria.get("response_default") + logging.warning(f"[rules_engine][assemble_response_rule] No criteria found for rule: '{rule_name}'. Skipping.") + return None rule_description = rule.get("comments", "").replace("\n", " ").replace("\r", " ").replace("\"", "'") resource = { @@ -227,7 +243,7 @@ def assemble_response_rule( } # Only add criteria if we have entries - if selected_criteria: + if len(selected_criteria) > 0: resource["attributes"]["results"]["criteria"] = selected_criteria return resource @@ -460,10 +476,10 @@ def behavior_cache_setting( cache_setttings = context.get("cache_setting") if cache_setttings is None: _, cache_setttings = azion_resources.query_azion_resource_by_type( - 'azion_edge_application_cache_setting', sanitize_name(parent_rule_name)) + 'azion_edge_application_cache_setting', sanitize_name(parent_rule_name), match="prefix") if cache_setttings is None: _, cache_setttings = azion_resources.query_azion_resource_by_type( - 'azion_edge_application_cache_setting', sanitize_name(rule_name)) + 'azion_edge_application_cache_setting', sanitize_name(rule_name), match="prefix") if cache_setttings: cache_settings_name = cache_setttings.get("name") @@ -506,11 +522,11 @@ def behavior_set_origin( if origin_settings is None: _, origin_settings = azion_resources.query_azion_resource_by_type( "azion_edge_application_origin", - sanitize_name(parent_rule_name)) + sanitize_name(parent_rule_name), match="prefix") if origin_settings is None: _, origin_settings = azion_resources.query_azion_resource_by_type( "azion_edge_application_origin", - sanitize_name(rule_name)) + sanitize_name(rule_name), match="prefix") if origin_settings is None: origin_settings = azion_resources.query_azion_origin_by_address(options.get("hostname", "")) @@ -523,6 +539,8 @@ def behavior_set_origin( "enabled": True, "target": {"target": origin_settings_ref + ".id"}, "description": f"Set origin to {options.get('name', '')}", + "phase": "request", + "akamai_behavior": "setOrigin" } return azion_behavior, origin_settings_ref @@ -698,6 +716,8 @@ def process_behaviors( "enabled": True, "description": f"Add host header to {trueClientIpHeader}", "target": { "target": '"' + f'{trueClientIpHeader}: ' + "$${remote_addr}" + '"' }, + "phase": "request", + "akamai_behavior": "trueClientIpHeader" } unique_key = behavior_key(azion_behavior) diff --git a/src/akamai/mapping.py b/src/akamai/mapping.py index 5e3c146..b39cf78 100644 --- a/src/akamai/mapping.py +++ b/src/akamai/mapping.py @@ -101,9 +101,10 @@ "gzipResponse": {"azion_behavior": "enable_gzip", "phase": "response", "akamai_behavior": "gzipResponse"}, # Cache Control - "noCaching": {"azion_behavior": "bypass_cache_phase"}, + "noCaching": {"azion_behavior": "bypass_cache_phase","phase": "request", "akamai_behavior": "noCaching"}, "caching": { "azion_behavior": "set_cache_policy", + "phase": "request", "target": { "browser_cache_settings": "override", "browser_cache_settings_maximum_ttl": "ttl", @@ -115,12 +116,14 @@ "enable_stale_cache": lambda options: not options.get("mustRevalidate", False), }, }, - "bypassCache": {"azion_behavior": "bypass_cache_phase"}, + "bypassCache": {"azion_behavior": "bypass_cache_phase","phase": "request", "akamai_behavior": "bypassCache"}, "prefreshCache": { "azion_behavior": "set_cache_policy", "target": { "prefresh_value": "prefreshval" - } + }, + "phase": "request", + "akamai_behavior": "prefreshCache" }, #"downstreamCache": { # "azion_behavior": "set_cache_policy", @@ -141,7 +144,9 @@ }, "modifyIncomingRequestCookie": { "azion_behavior": "add_request_cookie", - "target": {"name": "cookie_name", "value": "cookie_value"} + "target": {"name": "cookie_name", "value": "cookie_value"}, + "phase": "request", + "akamai_behavior": "modifyIncomingRequestCookie" }, "removeResponseCookie": { "azion_behavior": "filter_response_cookie", @@ -149,10 +154,23 @@ "phase": "response", "akamai_behavior": "removeResponseCookie" }, - "removeRequestCookie": {"azion_behavior": "filter_request_cookie", "target": "cookie_name"}, - "forwardCookies": {"azion_behavior": "forward_cookies"}, + "removeRequestCookie": { + "azion_behavior": "filter_request_cookie", + "target": "cookie_name", + "phase": "request", + "akamai_behavior": "removeRequestCookie" + }, + "forwardCookies": {"azion_behavior": "forward_cookies", "phase": "request", "akamai_behavior": "forwardCookies"}, "cookies": { - "logCookies": {"azion_behavior": "add_request_header", "target": {"name": "Set-Cookie", "value": "log_cookie"}}, + "logCookies": { + "azion_behavior": "add_request_header", + "target": { + "name": "Set-Cookie", + "value": "log_cookie" + }, + "phase": "request", + "akamai_behavior": "logCookies" + }, }, # Headers (adding/removing/modifying) @@ -175,7 +193,9 @@ "target": { "name": "Transfer-Encoding", "target": "Transfer-Encoding" - } + }, + "phase": "request", + "akamai_behavior": "allowTransferEncoding" }, "removeVary": { "azion_behavior": "filter_response_header", @@ -191,37 +211,42 @@ "target": { "target": get_redirect_target }, + "phase": "request", "akamai_behavior": "redirect" }, - "redirectPermanent": {"azion_behavior": "redirect_http_to_https", "target": "location"}, - "redirectTemporary": {"azion_behavior": "redirect_http_to_https", "target": "location"}, - "redirectToHttps": {"azion_behavior": "redirect_http_to_https"}, + "redirectPermanent": {"azion_behavior": "redirect_http_to_https", "target": "location", "phase": "request", "akamai_behavior": "redirectPermanent"}, + "redirectTemporary": {"azion_behavior": "redirect_http_to_https", "target": "location", "phase": "request", "akamai_behavior": "redirectTemporary"}, + "redirectToHttps": {"azion_behavior": "redirect_http_to_https", "phase": "request", "akamai_behavior": "redirectToHttps"}, # Origin "origin": { "azion_behavior": "set_origin", "target": { "enabled": "enabled" - } + }, + "phase": "request", + "akamai_behavior": "origin" }, "cloudletsOrigin": { "azion_behavior": "set_origin", # Use custom origin behavior in Azion "target": { "addresses": lambda options: [{"address": options.get("originId"), "weight": 1}], "origin_type": "single_origin", - } + }, + "phase": "request", + "akamai_behavior": "cloudletsOrigin" }, # Response - "respondWithNoContent": {"azion_behavior": "no_content"}, + "respondWithNoContent": {"azion_behavior": "no_content", "phase": "request", "akamai_behavior": "respondWithNoContent"}, # Edge Functions - "edgeWorker": {"azion_behavior": "run_function", "target": "function_id"}, - "run_function": {"azion_behavior": "run_function", "target": "function_id"}, + "edgeWorker": {"azion_behavior": "run_function", "target": "function_id", "akamai_behavior": "edgeWorker"}, + "run_function": {"azion_behavior": "run_function", "target": "function_id", "akamai_behavior": "run_function"}, #"webApplicationFirewall": {"azion_behavior": "run_function", "target": {"name": "WAF"}}, # Image Optimization - "imageManager": {"azion_behavior": "optimize_images"}, + "imageManager": {"azion_behavior": "optimize_images", "phase": "request", "akamai_behavior": "imageManager"}, #"prefetch": { # "azion_behavior": "optimize_images", # "target": {}, @@ -238,29 +263,37 @@ "azion_behavior": "rewrite_request", "target": { "target": lambda options: f"\"{replace_variables(options.get('targetUrl','')).strip()}\"" - } + }, + "phase": "request", + "akamai_behavior": "rewriteUrl" }, "rewrite_request": { "azion_behavior": "rewrite_request", - "target": "path" + "target": "path", + "phase": "request", + "akamai_behavior": "rewrite_request" }, "baseDirectory": { "azion_behavior": "rewrite_request", "target": { - "target": lambda options: f"{options.get('baseDirectory', '')}$${{uri}}" # Concatenate baseDirectory with original path + "target": lambda options: f"{options.get('baseDirectory', '')}$${{uri}}", # Concatenate baseDirectory with original path + "phase": "request", + "akamai_behavior": "baseDirectory" } }, # Special Cases "deliver": {"azion_behavior": "deliver"}, - "deny": {"azion_behavior": "deny"}, + "deny": {"azion_behavior": "deny", "phase": "request", "akamai_behavior": "deny"}, "setVariable": { "azion_behavior": "capture_match_groups", "target": { "captured_array": "variableName", "subject": "dynamic_subject", "regex": "regex" - } + }, + "phase": "request", + "akamai_behavior": "setVariable" }, }, "advanced_behaviors": { diff --git a/src/akamai/utils.py b/src/akamai/utils.py index af51f95..eedac0f 100644 --- a/src/akamai/utils.py +++ b/src/akamai/utils.py @@ -105,7 +105,7 @@ def extract_edge_hostname(akamai_config: dict) -> Optional[str]: return edge_hostname except ValueError as e: - print(f"Error in extract_edge_hostname: {e}") + logging.error(f"Error in extract_edge_hostname: {e}") logging.warning("Edge hostname not found in Akamai configuration.") return None @@ -193,13 +193,11 @@ def replace_variables(input_string: str) -> str: str: The string with Akamai variables replaced by Azion equivalents. """ # Regular expression pattern to match Akamai variables, e.g., {{builtin.AK_PATH}} - pattern = r"{{builtin\.[a-zA-Z0-9_\.]+}}" + pattern = r"{{(builtin|user)\.[a-zA-Z0-9_\.]+}}" # Function to replace the matched variable with its mapped Azion value def replace_match(match): variable = match.group(0) - # Remove the '{{builtin.' and '}}' and map it - variable = variable.replace("{{builtin.", "").replace("}}", "") return map_variable(variable) # Replace all occurrences of Akamai variables in the string using the regex pattern @@ -370,13 +368,12 @@ def get_redirect_target(options: Dict[str, Any]) -> str: sibling = options.get('destinationHostnameSibling', '') hostname = '$${host}'.replace('www.', f"{sibling}.") elif hostname_type == 'OTHER': - hostname = options.get('destinationHostnameOther', '$${host}') + hostname = replace_variables(options.get('destinationHostnameOther', '$${host}')) else: hostname = '$${host}' # Handle path and query string path_type = options.get('destinationPath', 'SAME_AS_REQUEST') - if path_type == 'SAME_AS_REQUEST': path = '$${uri}' query_string = '$${args}' if options.get('queryString') == 'APPEND' else '' @@ -387,7 +384,7 @@ def get_redirect_target(options: Dict[str, Any]) -> str: path = f"{prefix}/$${{'uri'}}{suffix}" query_string = '$${args}' if options.get('queryString') == 'APPEND' else '' elif path_type == 'OTHER': - other_path = options.get('destinationPathOther', '') + other_path = replace_variables(options.get('destinationPathOther', '')) if not other_path: path = '$${uri}' query_string = '$${args}' if options.get('queryString') == 'APPEND' else '' diff --git a/src/azion_resources.py b/src/azion_resources.py index 2eaddec..61a5453 100644 --- a/src/azion_resources.py +++ b/src/azion_resources.py @@ -31,7 +31,8 @@ def get_azion_resources(cls) -> List[Dict[str, Any]]: def query_azion_resource_by_type( cls, resource_type: str, - name: Optional[str] = None + name: Optional[str] = None, + match: Optional[str] = "exact" ) -> Tuple[int, Optional[Dict[str, Any]]]: """ Query a list of Azion resources by the 'type' field. Return the first matching resource. @@ -39,14 +40,21 @@ def query_azion_resource_by_type( Parameters: resource_type (str): The value of the 'type' field to search for. name (Optional[str]): The value of the 'name' field to search for. + match (Optional[str]): The way to match the 'name' field. Can be 'exact' or 'prefix'. Returns: Optional[Dict[str, Any]]: The first resource with the matching 'type', or None if not found. """ resources = cls.get_azion_resources() for index, resource in enumerate(resources): - if resource.get("type") == resource_type and (name is None or resource.get("name") == name): - return index, resource + if resource.get("type") == resource_type: + if name is None: + return index, resource + resource_name = resource.get("name", "") + if match == "exact" and resource_name == name: + return index, resource + elif match == "prefix" and resource_name.startswith(name): + return index, resource return -1, None @classmethod diff --git a/src/writer.py b/src/writer.py index e6e6cea..2af0b36 100644 --- a/src/writer.py +++ b/src/writer.py @@ -297,6 +297,8 @@ def write_rule_engine_block(f, resource: Dict[str, Any]) -> None: name = results.get("name", "unnamed_rule") normalized_name = resource.get("name") + if "offload_origin" in normalized_name: + return # Write resource block header write_indented(f, f'resource "azion_edge_application_rule_engine" "{normalized_name}" {{', 0) write_indented(f, f'edge_application_id = {attributes.get("edge_application_id")}', 1)