Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a3b527a

Browse files
committed
move back code to NextGen
1 parent 0bd2e8b commit a3b527a

File tree

2 files changed

+187
-138
lines changed

2 files changed

+187
-138
lines changed

‎localstack-core/localstack/services/apigateway/legacy/provider.py

Lines changed: 17 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import logging
55
import re
66
from copy import deepcopy
7-
from datetime import UTC, datetime
7+
from datetime import datetime
88
from typing import IO, Any
99

1010
from moto.apigateway import models as apigw_models
@@ -360,7 +360,7 @@ def update_rest_api(
360360

361361
fixed_patch_ops.append(patch_op)
362362

363-
_patch_api_gateway_entity(rest_api, fixed_patch_ops)
363+
patch_api_gateway_entity(rest_api, fixed_patch_ops)
364364

365365
# fix data types after patches have been applied
366366
endpoint_configs = rest_api.endpoint_configuration or {}
@@ -684,7 +684,7 @@ def update_resource(
684684
)
685685

686686
# TODO: test with multiple patch operations which would not be compatible between each other
687-
_patch_api_gateway_entity(moto_resource, patch_operations)
687+
patch_api_gateway_entity(moto_resource, patch_operations)
688688

689689
# after setting it, mutate the store
690690
if moto_resource.parent_id != current_parent_id:
@@ -914,7 +914,7 @@ def update_method(
914914
]
915915

916916
# TODO: test with multiple patch operations which would not be compatible between each other
917-
_patch_api_gateway_entity(moto_method, applicable_patch_operations)
917+
patch_api_gateway_entity(moto_method, applicable_patch_operations)
918918

919919
# if we removed all values of those fields, set them to None so that they're not returned anymore
920920
if had_req_params and len(moto_method.request_parameters) == 0:
@@ -985,8 +985,6 @@ def update_method_response(
985985
# TODO: add createdDate / lastUpdatedDate in Stage operations below!
986986
@handler("CreateStage", expand=False)
987987
def create_stage(self, context: RequestContext, request: CreateStageRequest) -> Stage:
988-
# TODO: we need to internalize Stages and Deployments in LocalStack, we have a lot of split logic
989-
990988
call_moto(context)
991989
moto_api = get_moto_rest_api(context, rest_api_id=request["restApiId"])
992990
stage = moto_api.stages.get(request["stageName"])
@@ -996,26 +994,6 @@ def create_stage(self, context: RequestContext, request: CreateStageRequest) ->
996994
if not hasattr(stage, "documentation_version"):
997995
stage.documentation_version = request.get("documentationVersion")
998996

999-
if not hasattr(stage, "canary_settings"):
1000-
# TODO: validate canarySettings
1001-
if canary_settings := request.get("canarySettings"):
1002-
if (
1003-
deployment_id := canary_settings.get("deploymentId")
1004-
) and deployment_id not in moto_api.deployments:
1005-
raise BadRequestException("Deployment id does not exist")
1006-
1007-
default_settings = {
1008-
"deploymentId": stage.deployment_id,
1009-
"percentTraffic": 0.0,
1010-
"useStageCache": False,
1011-
}
1012-
default_settings.update(canary_settings)
1013-
stage.canary_settings = default_settings
1014-
else:
1015-
stage.canary_settings = None
1016-
1017-
# TODO: add createdData, lastUpdatedData
1018-
1019997
# make sure we update the stage_name on the deployment entity in moto
1020998
deployment = moto_api.deployments.get(request["deploymentId"])
1021999
deployment.stage_name = stage.name
@@ -1050,7 +1028,10 @@ def update_stage(
10501028
patch_operations: ListOfPatchOperation = None,
10511029
**kwargs,
10521030
) -> Stage:
1053-
moto_rest_api = get_moto_rest_api(context, rest_api_id)
1031+
call_moto(context)
1032+
1033+
moto_backend = get_moto_backend(context.account_id, context.region)
1034+
moto_rest_api: MotoRestAPI = moto_backend.apis.get(rest_api_id)
10541035
if not (moto_stage := moto_rest_api.stages.get(stage_name)):
10551036
raise NotFoundException("Invalid Stage identifier specified")
10561037

@@ -1059,17 +1040,12 @@ def update_stage(
10591040

10601041
# copy the patch operations to not mutate them, so that we're logging the correct input
10611042
patch_operations = copy.deepcopy(patch_operations) or []
1062-
# we are only passing a subset of operations to Moto as it does not handle properly all of them
1063-
moto_patch_operations = []
1064-
moto_stage_copy = copy.deepcopy(moto_stage)
10651043
for patch_operation in patch_operations:
1066-
skip_moto_apply = False
10671044
patch_path = patch_operation["path"]
1068-
patch_op = patch_operation["op"]
10691045

10701046
# special case: handle updates (op=remove) for wildcard method settings
10711047
patch_path_stripped = patch_path.strip("/")
1072-
if patch_path_stripped == "*/*" and patch_op == "remove":
1048+
if patch_path_stripped == "*/*" and patch_operation["op"] == "remove":
10731049
if not moto_stage.method_settings.pop(patch_path_stripped, None):
10741050
raise BadRequestException(
10751051
"Cannot remove method setting */* because there is no method setting for this method "
@@ -1081,39 +1057,6 @@ def update_stage(
10811057
path_valid = patch_path in STAGE_UPDATE_PATHS or any(
10821058
re.match(regex, patch_path) for regex in path_regexes
10831059
)
1084-
if is_canary := patch_path.startswith("/canarySettings"):
1085-
skip_moto_apply = True
1086-
path_valid = is_canary_settings_update_patch_valid(op=patch_op, path=patch_path)
1087-
# it seems our JSON Patch utility does not handle replace properly if the value does not exists before
1088-
# it seems to maybe be a Stage-only thing, so replacing it here
1089-
if patch_op == "replace":
1090-
patch_operation["op"] = "add"
1091-
1092-
if patch_op == "copy":
1093-
copy_from = patch_operation.get("from")
1094-
if patch_path not in ("/deploymentId", "/variables") or copy_from not in (
1095-
"/canarySettings/deploymentId",
1096-
"/canarySettings/stageVariableOverrides",
1097-
):
1098-
raise BadRequestException(
1099-
"Invalid copy operation with path: /canarySettings/stageVariableOverrides and from /variables. Valid copy:path are [/deploymentId, /variables] and valid copy:from are [/canarySettings/deploymentId, /canarySettings/stageVariableOverrides]"
1100-
)
1101-
1102-
if copy_from.startswith("/canarySettings") and not getattr(
1103-
moto_stage_copy, "canary_settings", None
1104-
):
1105-
raise BadRequestException("Promotion not available. Canary does not exist.")
1106-
1107-
if patch_path == "/variables":
1108-
moto_stage_copy.variables.update(
1109-
moto_stage_copy.canary_settings.get("stageVariableOverrides", {})
1110-
)
1111-
elif patch_path == "/deploymentId":
1112-
moto_stage_copy.deployment_id = moto_stage_copy.canary_settings["deploymentId"]
1113-
1114-
# we manually assign `copy` ops, no need to apply them
1115-
continue
1116-
11171060
if not path_valid:
11181061
valid_paths = f"[{', '.join(STAGE_UPDATE_PATHS)}]"
11191062
# note: weird formatting in AWS - required for snapshot testing
@@ -1131,33 +1074,10 @@ def update_stage(
11311074
if patch_path == "/tracingEnabled" and (value := patch_operation.get("value")):
11321075
patch_operation["value"] = value and value.lower() == "true" or False
11331076

1134-
elif patch_path in ("/canarySettings/deploymentId", "/deploymentId"):
1135-
if patch_op != "copy" and not moto_rest_api.deployments.get(
1136-
patch_operation.get("value")
1137-
):
1138-
raise BadRequestException("Deployment id does not exist")
1139-
1140-
if not skip_moto_apply:
1141-
# we need to copy the patch operation because `_patch_api_gateway_entity` is mutating it in place
1142-
moto_patch_operations.append(dict(patch_operation))
1143-
1144-
# we need to apply patch operation individually to be able to validate the logic
1145-
_patch_api_gateway_entity(moto_stage_copy, [patch_operation])
1146-
if is_canary and (canary_settings := getattr(moto_stage_copy, "canary_settings", None)):
1147-
default_canary_settings = {
1148-
"deploymentId": moto_stage_copy.deployment_id,
1149-
"percentTraffic": 0.0,
1150-
"useStageCache": False,
1151-
}
1152-
default_canary_settings.update(canary_settings)
1153-
moto_stage_copy.canary_settings = default_canary_settings
1154-
1155-
moto_rest_api.stages[stage_name] = moto_stage_copy
1156-
moto_stage_copy.apply_operations(moto_patch_operations)
1157-
1158-
moto_stage_copy.last_updated_date = datetime.now(tz=UTC)
1159-
1160-
response = moto_stage_copy.to_json()
1077+
patch_api_gateway_entity(moto_stage, patch_operations)
1078+
moto_stage.apply_operations(patch_operations)
1079+
1080+
response = moto_stage.to_json()
11611081
self._patch_stage_response(response)
11621082
return response
11631083

@@ -1544,7 +1464,7 @@ def update_documentation_version(
15441464
if not result:
15451465
raise NotFoundException(f"Documentation version not found: {documentation_version}")
15461466

1547-
_patch_api_gateway_entity(result, patch_operations)
1467+
patch_api_gateway_entity(result, patch_operations)
15481468

15491469
return result
15501470

@@ -2091,7 +2011,7 @@ def update_integration(
20912011
raise NotFoundException("Invalid Integration identifier specified")
20922012

20932013
integration = method.method_integration
2094-
_patch_api_gateway_entity(integration, patch_operations)
2014+
patch_api_gateway_entity(integration, patch_operations)
20952015

20962016
# fix data types
20972017
if integration.timeout_in_millis:
@@ -2697,7 +2617,7 @@ def update_gateway_response(
26972617
f"Invalid null or empty value in {param_type}"
26982618
)
26992619

2700-
_patch_api_gateway_entity(patched_entity, patch_operations)
2620+
patch_api_gateway_entity(patched_entity, patch_operations)
27012621

27022622
return patched_entity
27032623

@@ -2819,7 +2739,7 @@ def create_custom_context(
28192739
return ctx
28202740

28212741

2822-
def _patch_api_gateway_entity(entity: Any, patch_operations: ListOfPatchOperation):
2742+
def patch_api_gateway_entity(entity: Any, patch_operations: ListOfPatchOperation):
28232743
patch_operations = patch_operations or []
28242744

28252745
if isinstance(entity, dict):
@@ -2916,33 +2836,6 @@ def to_response_json(model_type, data, api_id=None, self_link=None, id_attr=None
29162836
return result
29172837

29182838

2919-
def is_canary_settings_update_patch_valid(op: str, path: str) -> bool:
2920-
path_regexes = (
2921-
r"\/canarySettings\/percentTraffic",
2922-
r"\/canarySettings\/deploymentId",
2923-
r"\/canarySettings\/stageVariableOverrides\/.+",
2924-
r"\/canarySettings\/useStageCache",
2925-
)
2926-
if path == "/canarySettings" and op == "remove":
2927-
return True
2928-
2929-
matches_path = any(re.match(regex, path) for regex in path_regexes)
2930-
2931-
if op not in ("replace", "copy"):
2932-
if matches_path:
2933-
raise BadRequestException(f"Invalid {op} operation with path: {path}")
2934-
2935-
raise BadRequestException(
2936-
f"Cannot {op} method setting {path.lstrip('/')} because there is no method setting for this method "
2937-
)
2938-
2939-
# stageVariableOverrides is a bit special as it's nested, it doesn't return the same error message
2940-
if not matches_path and path != "/canarySettings/stageVariableOverrides":
2941-
return False
2942-
2943-
return True
2944-
2945-
29462839
DEFAULT_EMPTY_MODEL = Model(
29472840
id=short_uid()[:6],
29482841
name=EMPTY_MODEL,

0 commit comments

Comments
 (0)