localstack-core 4.6.1.dev60__py3-none-any.whl → 4.10.1.dev12__py3-none-any.whl

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 (672) hide show
  1. localstack/aws/api/apigateway/__init__.py +87 -110
  2. localstack/aws/api/cloudformation/__init__.py +18 -4
  3. localstack/aws/api/cloudwatch/__init__.py +41 -1
  4. localstack/aws/api/config/__init__.py +4 -0
  5. localstack/aws/api/core.py +8 -5
  6. localstack/aws/api/dynamodb/__init__.py +30 -0
  7. localstack/aws/api/ec2/__init__.py +1545 -66
  8. localstack/aws/api/events/__init__.py +12 -16
  9. localstack/aws/api/iam/__init__.py +7 -0
  10. localstack/aws/api/kinesis/__init__.py +19 -0
  11. localstack/aws/api/kms/__init__.py +6 -0
  12. localstack/aws/api/lambda_/__init__.py +36 -23
  13. localstack/aws/api/logs/__init__.py +20 -8
  14. localstack/aws/api/opensearch/__init__.py +16 -0
  15. localstack/aws/api/pipes/__init__.py +24 -32
  16. localstack/aws/api/redshift/__init__.py +9 -3
  17. localstack/aws/api/route53/__init__.py +5 -0
  18. localstack/aws/api/s3/__init__.py +12 -0
  19. localstack/aws/api/s3control/__init__.py +56 -0
  20. localstack/aws/api/scheduler/__init__.py +14 -16
  21. localstack/aws/api/ssm/__init__.py +2 -0
  22. localstack/aws/api/stepfunctions/__init__.py +88 -114
  23. localstack/aws/api/support/__init__.py +8 -9
  24. localstack/aws/api/transcribe/__init__.py +17 -0
  25. localstack/aws/chain.py +2 -2
  26. localstack/aws/client.py +14 -11
  27. localstack/aws/connect.py +42 -41
  28. localstack/aws/forwarder.py +57 -9
  29. localstack/aws/gateway.py +1 -3
  30. localstack/aws/handlers/analytics.py +2 -3
  31. localstack/aws/handlers/cors.py +4 -5
  32. localstack/aws/handlers/internal_requests.py +6 -1
  33. localstack/aws/handlers/logging.py +13 -4
  34. localstack/aws/handlers/metric_handler.py +44 -5
  35. localstack/aws/handlers/service.py +48 -28
  36. localstack/aws/mocking.py +18 -27
  37. localstack/aws/patches.py +2 -2
  38. localstack/aws/protocol/op_router.py +11 -10
  39. localstack/aws/protocol/parser.py +475 -49
  40. localstack/aws/protocol/serializer.py +723 -106
  41. localstack/aws/protocol/service_router.py +133 -33
  42. localstack/aws/protocol/validate.py +6 -6
  43. localstack/aws/scaffold.py +9 -10
  44. localstack/aws/serving/edge.py +5 -6
  45. localstack/aws/serving/hypercorn.py +2 -2
  46. localstack/aws/serving/twisted.py +1 -2
  47. localstack/aws/serving/werkzeug.py +2 -2
  48. localstack/aws/skeleton.py +12 -11
  49. localstack/aws/spec-patches.json +58 -0
  50. localstack/aws/spec.py +66 -46
  51. localstack/cli/exceptions.py +1 -1
  52. localstack/cli/localstack.py +11 -11
  53. localstack/cli/lpm.py +4 -5
  54. localstack/cli/plugins.py +1 -1
  55. localstack/cli/profiles.py +1 -2
  56. localstack/config.py +44 -30
  57. localstack/constants.py +4 -29
  58. localstack/deprecations.py +5 -5
  59. localstack/dev/kubernetes/__main__.py +130 -7
  60. localstack/dev/run/__main__.py +5 -5
  61. localstack/dev/run/configurators.py +1 -4
  62. localstack/dev/run/paths.py +6 -6
  63. localstack/dns/models.py +2 -1
  64. localstack/dns/plugins.py +5 -1
  65. localstack/dns/server.py +16 -6
  66. localstack/http/dispatcher.py +1 -2
  67. localstack/http/response.py +2 -2
  68. localstack/http/router.py +1 -1
  69. localstack/http/trace.py +2 -1
  70. localstack/logging/format.py +6 -6
  71. localstack/packages/api.py +13 -12
  72. localstack/packages/core.py +4 -4
  73. localstack/packages/debugpy.py +1 -3
  74. localstack/packages/ffmpeg.py +1 -2
  75. localstack/packages/java.py +38 -12
  76. localstack/packages/plugins.py +0 -8
  77. localstack/runtime/analytics.py +3 -0
  78. localstack/runtime/hooks.py +1 -1
  79. localstack/runtime/init.py +8 -9
  80. localstack/runtime/main.py +5 -5
  81. localstack/runtime/patches.py +2 -2
  82. localstack/runtime/shutdown.py +2 -1
  83. localstack/services/apigateway/exporter.py +1 -2
  84. localstack/services/apigateway/helpers.py +7 -10
  85. localstack/services/apigateway/legacy/context.py +21 -21
  86. localstack/services/apigateway/legacy/helpers.py +27 -28
  87. localstack/services/apigateway/legacy/integration.py +11 -10
  88. localstack/services/apigateway/legacy/invocations.py +6 -5
  89. localstack/services/apigateway/legacy/provider.py +148 -68
  90. localstack/services/apigateway/legacy/router_asf.py +2 -2
  91. localstack/services/apigateway/legacy/templates.py +6 -6
  92. localstack/services/apigateway/models.py +16 -16
  93. localstack/services/apigateway/next_gen/execute_api/api.py +2 -2
  94. localstack/services/apigateway/next_gen/execute_api/context.py +25 -25
  95. localstack/services/apigateway/next_gen/execute_api/handlers/api_key_validation.py +2 -5
  96. localstack/services/apigateway/next_gen/execute_api/handlers/method_request.py +7 -2
  97. localstack/services/apigateway/next_gen/execute_api/handlers/parse.py +1 -2
  98. localstack/services/apigateway/next_gen/execute_api/handlers/resource_router.py +2 -3
  99. localstack/services/apigateway/next_gen/execute_api/header_utils.py +1 -1
  100. localstack/services/apigateway/next_gen/execute_api/helpers.py +2 -2
  101. localstack/services/apigateway/next_gen/execute_api/integrations/aws.py +9 -6
  102. localstack/services/apigateway/next_gen/execute_api/integrations/http.py +12 -12
  103. localstack/services/apigateway/next_gen/execute_api/router.py +31 -0
  104. localstack/services/apigateway/next_gen/execute_api/template_mapping.py +2 -2
  105. localstack/services/apigateway/next_gen/execute_api/test_invoke.py +114 -9
  106. localstack/services/apigateway/next_gen/execute_api/variables.py +63 -63
  107. localstack/services/apigateway/next_gen/provider.py +5 -0
  108. localstack/services/apigateway/resource_providers/aws_apigateway_account.py +3 -3
  109. localstack/services/apigateway/resource_providers/aws_apigateway_account_plugin.py +1 -3
  110. localstack/services/apigateway/resource_providers/aws_apigateway_apikey.py +14 -14
  111. localstack/services/apigateway/resource_providers/aws_apigateway_apikey_plugin.py +1 -3
  112. localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping.py +5 -5
  113. localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping_plugin.py +1 -3
  114. localstack/services/apigateway/resource_providers/aws_apigateway_deployment.py +46 -46
  115. localstack/services/apigateway/resource_providers/aws_apigateway_deployment_plugin.py +1 -3
  116. localstack/services/apigateway/resource_providers/aws_apigateway_domainname.py +18 -18
  117. localstack/services/apigateway/resource_providers/aws_apigateway_domainname_plugin.py +1 -3
  118. localstack/services/apigateway/resource_providers/aws_apigateway_gatewayresponse.py +7 -7
  119. localstack/services/apigateway/resource_providers/aws_apigateway_gatewayresponse_plugin.py +1 -3
  120. localstack/services/apigateway/resource_providers/aws_apigateway_method.py +36 -36
  121. localstack/services/apigateway/resource_providers/aws_apigateway_method_plugin.py +1 -3
  122. localstack/services/apigateway/resource_providers/aws_apigateway_model.py +6 -6
  123. localstack/services/apigateway/resource_providers/aws_apigateway_model_plugin.py +1 -3
  124. localstack/services/apigateway/resource_providers/aws_apigateway_requestvalidator.py +6 -6
  125. localstack/services/apigateway/resource_providers/aws_apigateway_requestvalidator_plugin.py +1 -3
  126. localstack/services/apigateway/resource_providers/aws_apigateway_resource.py +6 -6
  127. localstack/services/apigateway/resource_providers/aws_apigateway_resource_plugin.py +1 -3
  128. localstack/services/apigateway/resource_providers/aws_apigateway_restapi.py +26 -26
  129. localstack/services/apigateway/resource_providers/aws_apigateway_restapi_plugin.py +1 -3
  130. localstack/services/apigateway/resource_providers/aws_apigateway_stage.py +33 -33
  131. localstack/services/apigateway/resource_providers/aws_apigateway_stage_plugin.py +1 -3
  132. localstack/services/apigateway/resource_providers/aws_apigateway_usageplan.py +18 -18
  133. localstack/services/apigateway/resource_providers/aws_apigateway_usageplan_plugin.py +1 -3
  134. localstack/services/apigateway/resource_providers/aws_apigateway_usageplankey.py +5 -5
  135. localstack/services/apigateway/resource_providers/aws_apigateway_usageplankey_plugin.py +1 -3
  136. localstack/services/cdk/resource_providers/cdk_metadata.py +4 -3
  137. localstack/services/cdk/resource_providers/cdk_metadata_plugin.py +1 -3
  138. localstack/services/certificatemanager/resource_providers/aws_certificatemanager_certificate.py +14 -14
  139. localstack/services/certificatemanager/resource_providers/aws_certificatemanager_certificate_plugin.py +1 -3
  140. localstack/services/cloudformation/api_utils.py +4 -8
  141. localstack/services/cloudformation/cfn_utils.py +2 -2
  142. localstack/services/cloudformation/deployment_utils.py +14 -12
  143. localstack/services/cloudformation/engine/changes.py +3 -3
  144. localstack/services/cloudformation/engine/entities.py +27 -17
  145. localstack/services/cloudformation/engine/parameters.py +4 -4
  146. localstack/services/cloudformation/engine/template_deployer.py +15 -14
  147. localstack/services/cloudformation/engine/template_utils.py +34 -12
  148. localstack/services/cloudformation/engine/transformers.py +11 -8
  149. localstack/services/cloudformation/engine/types.py +5 -4
  150. localstack/services/cloudformation/engine/v2/change_set_model.py +336 -39
  151. localstack/services/cloudformation/engine/v2/change_set_model_describer.py +96 -17
  152. localstack/services/cloudformation/engine/v2/change_set_model_executor.py +289 -136
  153. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +315 -146
  154. localstack/services/cloudformation/engine/v2/change_set_model_transform.py +380 -105
  155. localstack/services/cloudformation/engine/v2/change_set_model_validator.py +183 -0
  156. localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +6 -0
  157. localstack/services/cloudformation/engine/v2/resolving.py +102 -0
  158. localstack/services/cloudformation/engine/yaml_parser.py +9 -2
  159. localstack/services/cloudformation/provider.py +11 -6
  160. localstack/services/cloudformation/provider_utils.py +34 -4
  161. localstack/services/cloudformation/resource_provider.py +31 -21
  162. localstack/services/cloudformation/resource_providers/aws_cloudformation_macro.py +7 -7
  163. localstack/services/cloudformation/resource_providers/aws_cloudformation_macro_plugin.py +1 -3
  164. localstack/services/cloudformation/resource_providers/aws_cloudformation_stack.py +9 -9
  165. localstack/services/cloudformation/resource_providers/aws_cloudformation_stack_plugin.py +1 -3
  166. localstack/services/cloudformation/resource_providers/aws_cloudformation_waitcondition.py +6 -6
  167. localstack/services/cloudformation/resource_providers/aws_cloudformation_waitcondition_plugin.py +1 -3
  168. localstack/services/cloudformation/resource_providers/aws_cloudformation_waitconditionhandle.py +2 -2
  169. localstack/services/cloudformation/resource_providers/aws_cloudformation_waitconditionhandle_plugin.py +1 -3
  170. localstack/services/cloudformation/resources.py +24149 -0
  171. localstack/services/cloudformation/scaffolding/__main__.py +13 -12
  172. localstack/services/cloudformation/scaffolding/propgen.py +2 -2
  173. localstack/services/cloudformation/service_models.py +2 -2
  174. localstack/services/cloudformation/stores.py +33 -22
  175. localstack/services/cloudformation/v2/entities.py +103 -88
  176. localstack/services/cloudformation/v2/provider.py +872 -131
  177. localstack/services/cloudformation/v2/types.py +38 -0
  178. localstack/services/cloudformation/v2/utils.py +4 -1
  179. localstack/services/cloudwatch/alarm_scheduler.py +11 -8
  180. localstack/services/cloudwatch/cloudwatch_database_helper.py +4 -5
  181. localstack/services/cloudwatch/models.py +5 -7
  182. localstack/services/cloudwatch/provider.py +30 -25
  183. localstack/services/cloudwatch/provider_v2.py +27 -32
  184. localstack/services/cloudwatch/resource_providers/aws_cloudwatch_alarm.py +40 -40
  185. localstack/services/cloudwatch/resource_providers/aws_cloudwatch_alarm_plugin.py +1 -3
  186. localstack/services/cloudwatch/resource_providers/aws_cloudwatch_compositealarm.py +12 -12
  187. localstack/services/cloudwatch/resource_providers/aws_cloudwatch_compositealarm_plugin.py +1 -3
  188. localstack/services/dynamodb/packages.py +3 -3
  189. localstack/services/dynamodb/provider.py +159 -18
  190. localstack/services/dynamodb/resource_providers/aws_dynamodb_globaltable.py +63 -63
  191. localstack/services/dynamodb/resource_providers/aws_dynamodb_globaltable_plugin.py +1 -3
  192. localstack/services/dynamodb/resource_providers/aws_dynamodb_table.py +57 -57
  193. localstack/services/dynamodb/resource_providers/aws_dynamodb_table_plugin.py +1 -3
  194. localstack/services/dynamodb/server.py +2 -2
  195. localstack/services/dynamodb/utils.py +13 -14
  196. localstack/services/dynamodb/v2/provider.py +157 -18
  197. localstack/services/dynamodbstreams/dynamodbstreams_api.py +2 -2
  198. localstack/services/dynamodbstreams/models.py +1 -3
  199. localstack/services/ec2/patches.py +26 -5
  200. localstack/services/ec2/provider.py +3 -3
  201. localstack/services/ec2/resource_providers/aws_ec2_dhcpoptions.py +10 -10
  202. localstack/services/ec2/resource_providers/aws_ec2_dhcpoptions_plugin.py +1 -3
  203. localstack/services/ec2/resource_providers/aws_ec2_instance.py +96 -96
  204. localstack/services/ec2/resource_providers/aws_ec2_instance_plugin.py +1 -3
  205. localstack/services/ec2/resource_providers/aws_ec2_internetgateway.py +5 -5
  206. localstack/services/ec2/resource_providers/aws_ec2_internetgateway_plugin.py +1 -3
  207. localstack/services/ec2/resource_providers/aws_ec2_keypair.py +10 -10
  208. localstack/services/ec2/resource_providers/aws_ec2_keypair_plugin.py +1 -3
  209. localstack/services/ec2/resource_providers/aws_ec2_natgateway.py +13 -13
  210. localstack/services/ec2/resource_providers/aws_ec2_natgateway_plugin.py +1 -3
  211. localstack/services/ec2/resource_providers/aws_ec2_networkacl.py +6 -6
  212. localstack/services/ec2/resource_providers/aws_ec2_networkacl_plugin.py +1 -3
  213. localstack/services/ec2/resource_providers/aws_ec2_prefixlist.py +14 -14
  214. localstack/services/ec2/resource_providers/aws_ec2_prefixlist_plugin.py +1 -3
  215. localstack/services/ec2/resource_providers/aws_ec2_route.py +15 -15
  216. localstack/services/ec2/resource_providers/aws_ec2_route_plugin.py +1 -3
  217. localstack/services/ec2/resource_providers/aws_ec2_routetable.py +6 -6
  218. localstack/services/ec2/resource_providers/aws_ec2_routetable_plugin.py +1 -3
  219. localstack/services/ec2/resource_providers/aws_ec2_securitygroup.py +29 -29
  220. localstack/services/ec2/resource_providers/aws_ec2_securitygroup_plugin.py +1 -3
  221. localstack/services/ec2/resource_providers/aws_ec2_subnet.py +19 -19
  222. localstack/services/ec2/resource_providers/aws_ec2_subnet_plugin.py +1 -3
  223. localstack/services/ec2/resource_providers/aws_ec2_subnetroutetableassociation.py +4 -4
  224. localstack/services/ec2/resource_providers/aws_ec2_subnetroutetableassociation_plugin.py +1 -3
  225. localstack/services/ec2/resource_providers/aws_ec2_transitgateway.py +16 -16
  226. localstack/services/ec2/resource_providers/aws_ec2_transitgateway_plugin.py +1 -3
  227. localstack/services/ec2/resource_providers/aws_ec2_transitgatewayattachment.py +9 -9
  228. localstack/services/ec2/resource_providers/aws_ec2_transitgatewayattachment_plugin.py +1 -3
  229. localstack/services/ec2/resource_providers/aws_ec2_vpc.py +15 -15
  230. localstack/services/ec2/resource_providers/aws_ec2_vpc_plugin.py +1 -3
  231. localstack/services/ec2/resource_providers/aws_ec2_vpcendpoint.py +29 -22
  232. localstack/services/ec2/resource_providers/aws_ec2_vpcendpoint_plugin.py +1 -3
  233. localstack/services/ec2/resource_providers/aws_ec2_vpcgatewayattachment.py +5 -5
  234. localstack/services/ec2/resource_providers/aws_ec2_vpcgatewayattachment_plugin.py +1 -3
  235. localstack/services/ecr/resource_providers/aws_ecr_repository.py +22 -19
  236. localstack/services/ecr/resource_providers/aws_ecr_repository_plugin.py +1 -3
  237. localstack/services/edge.py +6 -6
  238. localstack/services/es/provider.py +21 -21
  239. localstack/services/events/archive.py +2 -2
  240. localstack/services/events/connection.py +5 -5
  241. localstack/services/events/event_bus.py +9 -9
  242. localstack/services/events/event_rule_engine.py +31 -13
  243. localstack/services/events/models.py +29 -30
  244. localstack/services/events/provider.py +29 -26
  245. localstack/services/events/replay.py +3 -3
  246. localstack/services/events/resource_providers/aws_events_apidestination.py +8 -8
  247. localstack/services/events/resource_providers/aws_events_apidestination_plugin.py +1 -3
  248. localstack/services/events/resource_providers/aws_events_connection.py +27 -27
  249. localstack/services/events/resource_providers/aws_events_connection_plugin.py +1 -3
  250. localstack/services/events/resource_providers/aws_events_eventbus.py +9 -9
  251. localstack/services/events/resource_providers/aws_events_eventbus_plugin.py +1 -3
  252. localstack/services/events/resource_providers/aws_events_eventbuspolicy.py +11 -11
  253. localstack/services/events/resource_providers/aws_events_eventbuspolicy_plugin.py +1 -3
  254. localstack/services/events/resource_providers/aws_events_rule.py +82 -82
  255. localstack/services/events/resource_providers/aws_events_rule_plugin.py +1 -3
  256. localstack/services/events/rule.py +15 -15
  257. localstack/services/events/target.py +21 -13
  258. localstack/services/events/utils.py +7 -7
  259. localstack/services/events/v1/models.py +1 -3
  260. localstack/services/events/v1/provider.py +15 -15
  261. localstack/services/firehose/models.py +1 -3
  262. localstack/services/firehose/provider.py +25 -16
  263. localstack/services/iam/iam_patches.py +5 -6
  264. localstack/services/iam/provider.py +14 -119
  265. localstack/services/iam/resource_providers/aws_iam_accesskey.py +6 -6
  266. localstack/services/iam/resource_providers/aws_iam_accesskey_plugin.py +1 -3
  267. localstack/services/iam/resource_providers/aws_iam_group.py +9 -9
  268. localstack/services/iam/resource_providers/aws_iam_group_plugin.py +1 -3
  269. localstack/services/iam/resource_providers/aws_iam_instanceprofile.py +5 -5
  270. localstack/services/iam/resource_providers/aws_iam_instanceprofile_plugin.py +1 -3
  271. localstack/services/iam/resource_providers/aws_iam_managedpolicy.py +9 -9
  272. localstack/services/iam/resource_providers/aws_iam_managedpolicy_plugin.py +1 -3
  273. localstack/services/iam/resource_providers/aws_iam_policy.py +7 -7
  274. localstack/services/iam/resource_providers/aws_iam_policy_plugin.py +1 -3
  275. localstack/services/iam/resource_providers/aws_iam_role.py +16 -16
  276. localstack/services/iam/resource_providers/aws_iam_role_plugin.py +1 -3
  277. localstack/services/iam/resource_providers/aws_iam_servercertificate.py +10 -10
  278. localstack/services/iam/resource_providers/aws_iam_servercertificate_plugin.py +1 -3
  279. localstack/services/iam/resource_providers/aws_iam_servicelinkedrole.py +5 -5
  280. localstack/services/iam/resource_providers/aws_iam_servicelinkedrole_plugin.py +1 -3
  281. localstack/services/iam/resource_providers/aws_iam_user.py +17 -17
  282. localstack/services/iam/resource_providers/aws_iam_user_plugin.py +1 -3
  283. localstack/services/iam/resources/policy_simulator.py +133 -0
  284. localstack/services/kinesis/kinesis_mock_server.py +7 -8
  285. localstack/services/kinesis/models.py +17 -5
  286. localstack/services/kinesis/packages.py +3 -3
  287. localstack/services/kinesis/provider.py +86 -3
  288. localstack/services/kinesis/resource_providers/aws_kinesis_stream.py +13 -13
  289. localstack/services/kinesis/resource_providers/aws_kinesis_stream_plugin.py +1 -3
  290. localstack/services/kinesis/resource_providers/aws_kinesis_streamconsumer.py +7 -7
  291. localstack/services/kinesis/resource_providers/aws_kinesis_streamconsumer_plugin.py +1 -3
  292. localstack/services/kinesisfirehose/resource_providers/aws_kinesisfirehose_deliverystream.py +191 -191
  293. localstack/services/kinesisfirehose/resource_providers/aws_kinesisfirehose_deliverystream_plugin.py +1 -3
  294. localstack/services/kms/models.py +21 -18
  295. localstack/services/kms/provider.py +62 -26
  296. localstack/services/kms/resource_providers/aws_kms_alias.py +3 -3
  297. localstack/services/kms/resource_providers/aws_kms_alias_plugin.py +1 -3
  298. localstack/services/kms/resource_providers/aws_kms_key.py +14 -14
  299. localstack/services/kms/resource_providers/aws_kms_key_plugin.py +1 -3
  300. localstack/services/kms/utils.py +4 -3
  301. localstack/services/lambda_/api_utils.py +19 -16
  302. localstack/services/lambda_/custom_endpoints.py +2 -2
  303. localstack/services/lambda_/event_source_mapping/esm_worker_factory.py +4 -7
  304. localstack/services/lambda_/event_source_mapping/pipe_utils.py +2 -2
  305. localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py +1 -1
  306. localstack/services/lambda_/event_source_mapping/senders/sender_utils.py +2 -1
  307. localstack/services/lambda_/hooks.py +6 -1
  308. localstack/services/lambda_/invocation/assignment.py +1 -2
  309. localstack/services/lambda_/invocation/docker_runtime_executor.py +7 -11
  310. localstack/services/lambda_/invocation/event_manager.py +1 -1
  311. localstack/services/lambda_/invocation/execution_environment.py +4 -4
  312. localstack/services/lambda_/invocation/executor_endpoint.py +8 -11
  313. localstack/services/lambda_/invocation/internal_sqs_queue.py +6 -10
  314. localstack/services/lambda_/invocation/lambda_models.py +33 -30
  315. localstack/services/lambda_/invocation/lambda_service.py +12 -5
  316. localstack/services/lambda_/invocation/logs.py +2 -3
  317. localstack/services/lambda_/invocation/runtime_executor.py +3 -3
  318. localstack/services/lambda_/invocation/version_manager.py +31 -8
  319. localstack/services/lambda_/ldm.py +14 -0
  320. localstack/services/lambda_/packages.py +3 -4
  321. localstack/services/lambda_/provider.py +9 -26
  322. localstack/services/lambda_/provider_utils.py +1 -1
  323. localstack/services/lambda_/resource_providers/aws_lambda_codesigningconfig.py +8 -8
  324. localstack/services/lambda_/resource_providers/aws_lambda_codesigningconfig_plugin.py +1 -3
  325. localstack/services/lambda_/resource_providers/aws_lambda_eventinvokeconfig.py +11 -11
  326. localstack/services/lambda_/resource_providers/aws_lambda_eventinvokeconfig_plugin.py +1 -3
  327. localstack/services/lambda_/resource_providers/aws_lambda_eventsourcemapping.py +39 -39
  328. localstack/services/lambda_/resource_providers/aws_lambda_eventsourcemapping_plugin.py +1 -3
  329. localstack/services/lambda_/resource_providers/aws_lambda_function.py +54 -54
  330. localstack/services/lambda_/resource_providers/aws_lambda_function_plugin.py +1 -3
  331. localstack/services/lambda_/resource_providers/aws_lambda_layerversion.py +11 -11
  332. localstack/services/lambda_/resource_providers/aws_lambda_layerversion_plugin.py +1 -3
  333. localstack/services/lambda_/resource_providers/aws_lambda_layerversionpermission.py +6 -6
  334. localstack/services/lambda_/resource_providers/aws_lambda_layerversionpermission_plugin.py +1 -3
  335. localstack/services/lambda_/resource_providers/aws_lambda_permission.py +10 -10
  336. localstack/services/lambda_/resource_providers/aws_lambda_permission_plugin.py +1 -3
  337. localstack/services/lambda_/resource_providers/aws_lambda_url.py +15 -15
  338. localstack/services/lambda_/resource_providers/aws_lambda_url_plugin.py +1 -3
  339. localstack/services/lambda_/resource_providers/aws_lambda_version.py +8 -8
  340. localstack/services/lambda_/resource_providers/aws_lambda_version_plugin.py +1 -3
  341. localstack/services/lambda_/resource_providers/lambda_alias.py +12 -12
  342. localstack/services/lambda_/resource_providers/lambda_alias_plugin.py +1 -3
  343. localstack/services/lambda_/runtimes.py +1 -3
  344. localstack/services/lambda_/urlrouter.py +14 -1
  345. localstack/services/logs/models.py +1 -3
  346. localstack/services/logs/provider.py +39 -22
  347. localstack/services/logs/resource_providers/aws_logs_loggroup.py +9 -9
  348. localstack/services/logs/resource_providers/aws_logs_loggroup_plugin.py +1 -3
  349. localstack/services/logs/resource_providers/aws_logs_logstream.py +4 -4
  350. localstack/services/logs/resource_providers/aws_logs_logstream_plugin.py +1 -3
  351. localstack/services/logs/resource_providers/aws_logs_subscriptionfilter.py +7 -7
  352. localstack/services/logs/resource_providers/aws_logs_subscriptionfilter_plugin.py +1 -3
  353. localstack/services/moto.py +5 -4
  354. localstack/services/opensearch/cluster.py +28 -20
  355. localstack/services/opensearch/cluster_manager.py +13 -14
  356. localstack/services/opensearch/models.py +1 -3
  357. localstack/services/opensearch/packages.py +27 -9
  358. localstack/services/opensearch/provider.py +15 -10
  359. localstack/services/opensearch/resource_providers/aws_elasticsearch_domain.py +61 -61
  360. localstack/services/opensearch/resource_providers/aws_elasticsearch_domain_plugin.py +1 -3
  361. localstack/services/opensearch/resource_providers/aws_opensearchservice_domain.py +89 -89
  362. localstack/services/opensearch/resource_providers/aws_opensearchservice_domain_plugin.py +1 -3
  363. localstack/services/opensearch/versions.py +57 -10
  364. localstack/services/plugins.py +37 -32
  365. localstack/services/providers.py +10 -2
  366. localstack/services/redshift/provider.py +0 -21
  367. localstack/services/redshift/resource_providers/aws_redshift_cluster.py +57 -57
  368. localstack/services/redshift/resource_providers/aws_redshift_cluster_plugin.py +1 -3
  369. localstack/services/resource_groups/resource_providers/aws_resourcegroups_group.py +21 -21
  370. localstack/services/resource_groups/resource_providers/aws_resourcegroups_group_plugin.py +1 -3
  371. localstack/services/route53/models.py +1 -3
  372. localstack/services/route53/provider.py +1 -2
  373. localstack/services/route53/resource_providers/aws_route53_healthcheck.py +6 -6
  374. localstack/services/route53/resource_providers/aws_route53_healthcheck_plugin.py +1 -3
  375. localstack/services/route53/resource_providers/aws_route53_recordset.py +27 -27
  376. localstack/services/route53/resource_providers/aws_route53_recordset_plugin.py +1 -3
  377. localstack/services/route53resolver/models.py +8 -10
  378. localstack/services/route53resolver/provider.py +12 -12
  379. localstack/services/s3/codec.py +2 -2
  380. localstack/services/s3/constants.py +5 -2
  381. localstack/services/s3/cors.py +8 -8
  382. localstack/services/s3/models.py +73 -73
  383. localstack/services/s3/notifications.py +74 -58
  384. localstack/services/s3/presigned_url.py +41 -59
  385. localstack/services/s3/provider.py +86 -29
  386. localstack/services/s3/resource_providers/aws_s3_bucket.py +180 -180
  387. localstack/services/s3/resource_providers/aws_s3_bucket_plugin.py +1 -3
  388. localstack/services/s3/resource_providers/aws_s3_bucketpolicy.py +4 -4
  389. localstack/services/s3/resource_providers/aws_s3_bucketpolicy_plugin.py +1 -3
  390. localstack/services/s3/storage/core.py +4 -3
  391. localstack/services/s3/storage/ephemeral.py +7 -6
  392. localstack/services/s3/utils.py +51 -31
  393. localstack/services/s3/validation.py +47 -33
  394. localstack/services/s3/website_hosting.py +9 -7
  395. localstack/services/scheduler/resource_providers/aws_scheduler_schedule.py +60 -60
  396. localstack/services/scheduler/resource_providers/aws_scheduler_schedule_plugin.py +1 -3
  397. localstack/services/scheduler/resource_providers/aws_scheduler_schedulegroup.py +9 -9
  398. localstack/services/scheduler/resource_providers/aws_scheduler_schedulegroup_plugin.py +1 -3
  399. localstack/services/secretsmanager/provider.py +10 -12
  400. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_resourcepolicy.py +5 -5
  401. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_resourcepolicy_plugin.py +1 -3
  402. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_rotationschedule.py +21 -21
  403. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_rotationschedule_plugin.py +1 -3
  404. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secret.py +23 -23
  405. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secret_plugin.py +1 -3
  406. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secrettargetattachment.py +5 -5
  407. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secrettargetattachment_plugin.py +1 -3
  408. localstack/services/ses/models.py +8 -1
  409. localstack/services/ses/provider.py +128 -55
  410. localstack/services/ses/resource_providers/aws_ses_emailidentity.py +21 -21
  411. localstack/services/ses/resource_providers/aws_ses_emailidentity_plugin.py +1 -3
  412. localstack/services/sns/constants.py +7 -1
  413. localstack/services/sns/executor.py +9 -2
  414. localstack/services/sns/models.py +25 -25
  415. localstack/services/sns/provider.py +9 -7
  416. localstack/services/sns/publisher.py +37 -23
  417. localstack/services/sns/resource_providers/aws_sns_subscription.py +13 -13
  418. localstack/services/sns/resource_providers/aws_sns_subscription_plugin.py +1 -3
  419. localstack/services/sns/resource_providers/aws_sns_topic.py +16 -16
  420. localstack/services/sns/resource_providers/aws_sns_topic_plugin.py +1 -3
  421. localstack/services/sns/resource_providers/aws_sns_topicpolicy.py +4 -4
  422. localstack/services/sns/resource_providers/aws_sns_topicpolicy_plugin.py +1 -3
  423. localstack/services/sns/v2/models.py +167 -0
  424. localstack/services/sns/v2/provider.py +867 -0
  425. localstack/services/sns/v2/utils.py +130 -0
  426. localstack/services/sqs/constants.py +2 -2
  427. localstack/services/sqs/developer_api.py +205 -0
  428. localstack/services/sqs/models.py +71 -36
  429. localstack/services/sqs/provider.py +56 -332
  430. localstack/services/sqs/query_api.py +8 -5
  431. localstack/services/sqs/resource_providers/aws_sqs_queue.py +21 -21
  432. localstack/services/sqs/resource_providers/aws_sqs_queue_plugin.py +1 -3
  433. localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.py +7 -5
  434. localstack/services/sqs/resource_providers/aws_sqs_queuepolicy_plugin.py +1 -3
  435. localstack/services/sqs/utils.py +123 -4
  436. localstack/services/ssm/provider.py +3 -4
  437. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindow.py +15 -15
  438. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindow_plugin.py +1 -3
  439. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtarget.py +10 -10
  440. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtarget_plugin.py +1 -3
  441. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtask.py +48 -48
  442. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtask_plugin.py +1 -3
  443. localstack/services/ssm/resource_providers/aws_ssm_parameter.py +10 -10
  444. localstack/services/ssm/resource_providers/aws_ssm_parameter_plugin.py +1 -3
  445. localstack/services/ssm/resource_providers/aws_ssm_patchbaseline.py +29 -29
  446. localstack/services/ssm/resource_providers/aws_ssm_patchbaseline_plugin.py +1 -3
  447. localstack/services/stepfunctions/asl/antlt4utils/antlr4utils.py +3 -4
  448. localstack/services/stepfunctions/asl/component/common/assign/assign_decl.py +1 -1
  449. localstack/services/stepfunctions/asl/component/common/assign/assign_decl_binding.py +1 -1
  450. localstack/services/stepfunctions/asl/component/common/assign/assign_template_value_array.py +1 -1
  451. localstack/services/stepfunctions/asl/component/common/assign/assign_template_value_object.py +1 -1
  452. localstack/services/stepfunctions/asl/component/common/catch/catcher_decl.py +9 -9
  453. localstack/services/stepfunctions/asl/component/common/error_name/custom_error_name.py +2 -2
  454. localstack/services/stepfunctions/asl/component/common/error_name/error_name.py +4 -4
  455. localstack/services/stepfunctions/asl/component/common/error_name/failure_event.py +8 -8
  456. localstack/services/stepfunctions/asl/component/common/error_name/states_error_name_type.py +1 -1
  457. localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_binding.py +2 -2
  458. localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_value_array.py +1 -1
  459. localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_value_object.py +1 -1
  460. localstack/services/stepfunctions/asl/component/common/path/input_path.py +4 -4
  461. localstack/services/stepfunctions/asl/component/common/path/output_path.py +4 -4
  462. localstack/services/stepfunctions/asl/component/common/path/result_path.py +3 -3
  463. localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadarr/payload_arr.py +1 -1
  464. localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding.py +3 -3
  465. localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadtmpl/payload_tmpl.py +1 -1
  466. localstack/services/stepfunctions/asl/component/common/retry/retrier_decl.py +8 -8
  467. localstack/services/stepfunctions/asl/component/common/string/string_expression.py +3 -3
  468. localstack/services/stepfunctions/asl/component/common/timeouts/timeout.py +3 -3
  469. localstack/services/stepfunctions/asl/component/eval_component.py +2 -3
  470. localstack/services/stepfunctions/asl/component/intrinsic/argument/argument.py +4 -4
  471. localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/array/array_partition.py +1 -1
  472. localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/generic/string_format.py +1 -1
  473. localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/states_function_array.py +1 -1
  474. localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/states_function_format.py +1 -1
  475. localstack/services/stepfunctions/asl/component/intrinsic/jsonata.py +3 -3
  476. localstack/services/stepfunctions/asl/component/intrinsic/member.py +1 -1
  477. localstack/services/stepfunctions/asl/component/program/program.py +9 -9
  478. localstack/services/stepfunctions/asl/component/program/states.py +1 -1
  479. localstack/services/stepfunctions/asl/component/state/state.py +10 -11
  480. localstack/services/stepfunctions/asl/component/state/state_choice/choice_rule.py +11 -11
  481. localstack/services/stepfunctions/asl/component/state/state_choice/comparison/comparison.py +5 -11
  482. localstack/services/stepfunctions/asl/component/state/state_choice/comparison/operator/implementations/is_operator.py +2 -2
  483. localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py +3 -5
  484. localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py +9 -9
  485. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/item_reader_decl.py +7 -7
  486. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/reader_config/reader_config_decl.py +5 -5
  487. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_s3.py +2 -1
  488. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_csv.py +2 -2
  489. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/distributed_iteration_component.py +8 -8
  490. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/inline_iteration_component.py +7 -7
  491. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor_worker.py +4 -4
  492. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor_worker.py +5 -5
  493. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/map_run_record.py +10 -10
  494. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_component.py +3 -3
  495. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_declaration.py +3 -3
  496. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_worker.py +2 -2
  497. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/distributed_iterator_worker.py +3 -5
  498. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/inline_iterator.py +1 -2
  499. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/inline_iterator_worker.py +5 -5
  500. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/job.py +9 -9
  501. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/result_writer/resource_eval/resource_eval_s3.py +2 -1
  502. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py +12 -13
  503. localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/branch_worker.py +3 -3
  504. localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/branches_decl.py +7 -7
  505. localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/state_parallel.py +2 -3
  506. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py +7 -7
  507. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/resource.py +3 -3
  508. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py +10 -10
  509. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_api_gateway.py +18 -18
  510. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_aws_sdk.py +1 -1
  511. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_batch.py +8 -7
  512. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py +18 -17
  513. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_dynamodb.py +2 -2
  514. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_ecs.py +5 -4
  515. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_events.py +4 -4
  516. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_glue.py +7 -6
  517. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py +4 -4
  518. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sfn.py +9 -8
  519. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sns.py +2 -2
  520. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py +4 -4
  521. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task.py +5 -5
  522. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task_lambda.py +2 -2
  523. localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py +3 -5
  524. localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py +5 -7
  525. localstack/services/stepfunctions/asl/component/state/state_succeed/state_succeed.py +1 -1
  526. localstack/services/stepfunctions/asl/component/state/state_wait/state_wait.py +1 -1
  527. localstack/services/stepfunctions/asl/component/state/state_wait/wait_function/timestamp.py +2 -2
  528. localstack/services/stepfunctions/asl/eval/callback/callback.py +18 -18
  529. localstack/services/stepfunctions/asl/eval/environment.py +22 -24
  530. localstack/services/stepfunctions/asl/eval/evaluation_details.py +3 -5
  531. localstack/services/stepfunctions/asl/eval/event/event_manager.py +10 -10
  532. localstack/services/stepfunctions/asl/eval/event/logging.py +3 -3
  533. localstack/services/stepfunctions/asl/eval/program_state.py +8 -8
  534. localstack/services/stepfunctions/asl/eval/states.py +12 -12
  535. localstack/services/stepfunctions/asl/eval/test_state/environment.py +3 -5
  536. localstack/services/stepfunctions/asl/eval/variable_store.py +6 -6
  537. localstack/services/stepfunctions/asl/jsonata/jsonata.py +7 -6
  538. localstack/services/stepfunctions/asl/parse/asl_parser.py +1 -1
  539. localstack/services/stepfunctions/asl/parse/intrinsic/preprocessor.py +2 -3
  540. localstack/services/stepfunctions/asl/parse/preprocessor.py +44 -44
  541. localstack/services/stepfunctions/asl/parse/typed_props.py +2 -2
  542. localstack/services/stepfunctions/asl/static_analyser/intrinsic/variable_names_intrinsic_static_analyser.py +1 -1
  543. localstack/services/stepfunctions/asl/static_analyser/variable_references_static_analyser.py +2 -2
  544. localstack/services/stepfunctions/asl/utils/encoding.py +2 -2
  545. localstack/services/stepfunctions/asl/utils/json_path.py +2 -2
  546. localstack/services/stepfunctions/backend/activity.py +4 -4
  547. localstack/services/stepfunctions/backend/alias.py +8 -8
  548. localstack/services/stepfunctions/backend/execution.py +29 -30
  549. localstack/services/stepfunctions/backend/execution_worker.py +7 -7
  550. localstack/services/stepfunctions/backend/state_machine.py +28 -28
  551. localstack/services/stepfunctions/backend/test_state/execution.py +3 -4
  552. localstack/services/stepfunctions/backend/test_state/execution_worker.py +1 -3
  553. localstack/services/stepfunctions/mocking/mock_config.py +9 -9
  554. localstack/services/stepfunctions/mocking/mock_config_file.py +10 -10
  555. localstack/services/stepfunctions/packages.py +14 -5
  556. localstack/services/stepfunctions/provider.py +34 -44
  557. localstack/services/stepfunctions/quotas.py +2 -3
  558. localstack/services/stepfunctions/resource_providers/aws_stepfunctions_activity.py +6 -6
  559. localstack/services/stepfunctions/resource_providers/aws_stepfunctions_activity_plugin.py +1 -3
  560. localstack/services/stepfunctions/resource_providers/aws_stepfunctions_statemachine.py +25 -25
  561. localstack/services/stepfunctions/resource_providers/aws_stepfunctions_statemachine_plugin.py +1 -3
  562. localstack/services/stepfunctions/stepfunctions_utils.py +1 -2
  563. localstack/services/stores.py +8 -8
  564. localstack/services/transcribe/packages.py +1 -3
  565. localstack/services/transcribe/provider.py +8 -3
  566. localstack/state/codecs.py +61 -0
  567. localstack/state/core.py +11 -5
  568. localstack/state/inspect.py +4 -4
  569. localstack/state/pickle.py +36 -23
  570. localstack/testing/aws/asf_utils.py +3 -2
  571. localstack/testing/aws/cloudformation_utils.py +1 -1
  572. localstack/testing/aws/lambda_utils.py +15 -14
  573. localstack/testing/aws/util.py +3 -2
  574. localstack/testing/pytest/cloudformation/fixtures.py +68 -18
  575. localstack/testing/pytest/container.py +5 -5
  576. localstack/testing/pytest/filters.py +1 -3
  577. localstack/testing/pytest/fixtures.py +188 -49
  578. localstack/testing/pytest/in_memory_localstack.py +1 -3
  579. localstack/testing/pytest/marking.py +42 -15
  580. localstack/testing/pytest/path_filter.py +1 -1
  581. localstack/testing/pytest/stepfunctions/fixtures.py +4 -4
  582. localstack/testing/pytest/stepfunctions/utils.py +11 -10
  583. localstack/testing/pytest/util.py +1 -1
  584. localstack/testing/pytest/validation_tracking.py +3 -4
  585. localstack/testing/scenario/provisioning.py +11 -10
  586. localstack/testing/snapshots/transformer_utility.py +8 -3
  587. localstack/testing/testselection/matching.py +2 -2
  588. localstack/testing/testselection/opt_out.py +1 -1
  589. localstack/testing/testselection/scripts/filter_by_test_selection.py +1 -1
  590. localstack/testing/testselection/scripts/generate_test_selection.py +1 -1
  591. localstack/testing/testselection/testselection.py +2 -2
  592. localstack/utils/analytics/cli.py +2 -3
  593. localstack/utils/analytics/client.py +5 -5
  594. localstack/utils/analytics/events.py +2 -2
  595. localstack/utils/analytics/metadata.py +6 -4
  596. localstack/utils/analytics/metrics/counter.py +11 -18
  597. localstack/utils/analytics/metrics/registry.py +2 -2
  598. localstack/utils/analytics/publisher.py +4 -5
  599. localstack/utils/analytics/service_providers.py +19 -0
  600. localstack/utils/analytics/service_request_aggregator.py +4 -4
  601. localstack/utils/archives.py +12 -12
  602. localstack/utils/asyncio.py +2 -2
  603. localstack/utils/aws/arns.py +26 -31
  604. localstack/utils/aws/aws_responses.py +21 -28
  605. localstack/utils/aws/aws_stack.py +7 -12
  606. localstack/utils/aws/dead_letter_queue.py +4 -9
  607. localstack/utils/aws/message_forwarding.py +8 -11
  608. localstack/utils/aws/request_context.py +5 -6
  609. localstack/utils/aws/resources.py +1 -1
  610. localstack/utils/aws/templating.py +4 -4
  611. localstack/utils/batch_policy.py +4 -4
  612. localstack/utils/bootstrap.py +37 -30
  613. localstack/utils/catalog/catalog.py +139 -0
  614. localstack/utils/catalog/catalog_loader.py +119 -0
  615. localstack/utils/catalog/common.py +58 -0
  616. localstack/utils/catalog/plugins.py +28 -0
  617. localstack/utils/cloudwatch/cloudwatch_util.py +5 -5
  618. localstack/utils/collections.py +33 -27
  619. localstack/utils/config_listener.py +2 -2
  620. localstack/utils/container_networking.py +5 -6
  621. localstack/utils/container_utils/container_client.py +156 -160
  622. localstack/utils/container_utils/docker_cmd_client.py +97 -81
  623. localstack/utils/container_utils/docker_sdk_client.py +75 -72
  624. localstack/utils/crypto.py +12 -13
  625. localstack/utils/diagnose.py +11 -12
  626. localstack/utils/docker_utils.py +11 -7
  627. localstack/utils/files.py +34 -15
  628. localstack/utils/functions.py +5 -4
  629. localstack/utils/http.py +14 -14
  630. localstack/utils/iputils.py +2 -1
  631. localstack/utils/json.py +21 -7
  632. localstack/utils/kinesis/kinesis_connector.py +2 -1
  633. localstack/utils/net.py +25 -17
  634. localstack/utils/no_exit_argument_parser.py +2 -2
  635. localstack/utils/numbers.py +9 -2
  636. localstack/utils/objects.py +15 -14
  637. localstack/utils/patch.py +14 -7
  638. localstack/utils/platform.py +2 -2
  639. localstack/utils/run.py +15 -14
  640. localstack/utils/scheduler.py +13 -12
  641. localstack/utils/server/tcp_proxy.py +2 -2
  642. localstack/utils/serving.py +3 -4
  643. localstack/utils/strings.py +15 -16
  644. localstack/utils/sync.py +126 -1
  645. localstack/utils/tagging.py +10 -8
  646. localstack/utils/testutil.py +17 -17
  647. localstack/utils/threads.py +3 -3
  648. localstack/utils/time.py +12 -4
  649. localstack/utils/urls.py +1 -3
  650. localstack/utils/xml.py +1 -1
  651. localstack/utils/xray/traceid.py +1 -1
  652. localstack/version.py +16 -3
  653. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/METADATA +18 -13
  654. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/RECORD +663 -655
  655. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/entry_points.txt +8 -4
  656. localstack_core-4.10.1.dev12.dist-info/plux.json +1 -0
  657. localstack/packages/terraform.py +0 -47
  658. localstack/services/cloudformation/deploy.html +0 -144
  659. localstack/services/cloudformation/deploy_ui.py +0 -47
  660. localstack/services/cloudformation/plugins.py +0 -12
  661. localstack/services/lambda_/lambda_debug_mode/ldm.py +0 -375
  662. localstack/services/lambda_/lambda_debug_mode/ldm_config_file.py +0 -178
  663. localstack/services/lambda_/lambda_debug_mode/ldm_types.py +0 -11
  664. localstack/services/lambda_/lambda_debug_mode/ldm_utils.py +0 -43
  665. localstack_core-4.6.1.dev60.dist-info/plux.json +0 -1
  666. /localstack/{services/lambda_/lambda_debug_mode/__init__.py → testing/pytest/cloudformation/transformers.py} +0 -0
  667. {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack +0 -0
  668. {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack-supervisor +0 -0
  669. {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack.bat +0 -0
  670. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/WHEEL +0 -0
  671. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/licenses/LICENSE.txt +0 -0
  672. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/top_level.txt +0 -0
@@ -3,18 +3,15 @@ from __future__ import annotations
3
3
  import base64
4
4
  import copy
5
5
  import re
6
- from typing import Any, Callable, Final, Generic, Optional, TypeVar
6
+ from collections.abc import Callable
7
+ from typing import Any, Final, Generic, TypeVar
7
8
 
8
9
  from botocore.exceptions import ClientError
9
10
 
10
11
  from localstack import config
12
+ from localstack.aws.api.cloudformation import ResourceStatus
11
13
  from localstack.aws.api.ec2 import AvailabilityZoneList, DescribeAvailabilityZonesResult
12
14
  from localstack.aws.connect import connect_to
13
- from localstack.services.cloudformation.engine.transformers import (
14
- Transformer,
15
- execute_macro,
16
- transformers,
17
- )
18
15
  from localstack.services.cloudformation.engine.v2.change_set_model import (
19
16
  ChangeSetEntity,
20
17
  ChangeType,
@@ -33,6 +30,7 @@ from localstack.services.cloudformation.engine.v2.change_set_model import (
33
30
  NodeProperties,
34
31
  NodeProperty,
35
32
  NodeResource,
33
+ NodeResources,
36
34
  NodeTemplate,
37
35
  Nothing,
38
36
  NothingType,
@@ -47,9 +45,19 @@ from localstack.services.cloudformation.engine.v2.change_set_model import (
47
45
  from localstack.services.cloudformation.engine.v2.change_set_model_visitor import (
48
46
  ChangeSetModelVisitor,
49
47
  )
50
- from localstack.services.cloudformation.stores import get_cloudformation_store
48
+ from localstack.services.cloudformation.engine.v2.resolving import (
49
+ REGEX_DYNAMIC_REF,
50
+ extract_dynamic_reference,
51
+ perform_dynamic_reference_lookup,
52
+ )
53
+ from localstack.services.cloudformation.engine.validations import ValidationError
54
+ from localstack.services.cloudformation.stores import (
55
+ exports_map,
56
+ )
51
57
  from localstack.services.cloudformation.v2.entities import ChangeSet
58
+ from localstack.services.cloudformation.v2.types import ResolvedResource
52
59
  from localstack.utils.aws.arns import get_partition
60
+ from localstack.utils.numbers import to_number
53
61
  from localstack.utils.objects import get_value_from_path
54
62
  from localstack.utils.run import to_str
55
63
  from localstack.utils.strings import to_bytes
@@ -70,9 +78,15 @@ _PSEUDO_PARAMETERS: Final[set[str]] = {
70
78
 
71
79
  TBefore = TypeVar("TBefore")
72
80
  TAfter = TypeVar("TAfter")
81
+ _T = TypeVar("_T")
73
82
 
83
+ REGEX_OUTPUT_APIGATEWAY = re.compile(
84
+ rf"^(https?://.+\.execute-api\.)(?:[^-]+-){{2,3}}\d\.(amazonaws\.com|{_AWS_URL_SUFFIX})/?(.*)$"
85
+ )
74
86
  MOCKED_REFERENCE = "unknown"
75
87
 
88
+ VALID_LOGICAL_RESOURCE_ID_RE = re.compile(r"^[A-Za-z0-9]+$")
89
+
76
90
 
77
91
  class PreprocEntityDelta(Generic[TBefore, TAfter]):
78
92
  before: Maybe[TBefore]
@@ -102,20 +116,24 @@ class PreprocProperties:
102
116
 
103
117
  class PreprocResource:
104
118
  logical_id: str
105
- physical_resource_id: Optional[str]
106
- condition: Optional[bool]
119
+ physical_resource_id: str | None
120
+ condition: bool | None
107
121
  resource_type: str
108
122
  properties: PreprocProperties
109
- depends_on: Optional[list[str]]
123
+ depends_on: list[str] | None
124
+ requires_replacement: bool
125
+ status: ResourceStatus | None
110
126
 
111
127
  def __init__(
112
128
  self,
113
129
  logical_id: str,
114
130
  physical_resource_id: str,
115
- condition: Optional[bool],
131
+ condition: bool | None,
116
132
  resource_type: str,
117
133
  properties: PreprocProperties,
118
- depends_on: Optional[list[str]],
134
+ depends_on: list[str] | None,
135
+ requires_replacement: bool,
136
+ status: ResourceStatus | None = None,
119
137
  ):
120
138
  self.logical_id = logical_id
121
139
  self.physical_resource_id = physical_resource_id
@@ -123,6 +141,8 @@ class PreprocResource:
123
141
  self.resource_type = resource_type
124
142
  self.properties = properties
125
143
  self.depends_on = depends_on
144
+ self.requires_replacement = requires_replacement
145
+ self.status = status
126
146
 
127
147
  @staticmethod
128
148
  def _compare_conditions(c1: bool, c2: bool):
@@ -147,10 +167,10 @@ class PreprocResource:
147
167
  class PreprocOutput:
148
168
  name: str
149
169
  value: Any
150
- export: Optional[Any]
151
- condition: Optional[bool]
170
+ export: Any | None
171
+ condition: bool | None
152
172
 
153
- def __init__(self, name: str, value: Any, export: Optional[Any], condition: Optional[bool]):
173
+ def __init__(self, name: str, value: Any, export: Any | None, condition: bool | None):
154
174
  self.name = name
155
175
  self.value = value
156
176
  self.export = export
@@ -178,8 +198,8 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
178
198
  def __init__(self, change_set: ChangeSet):
179
199
  self._change_set = change_set
180
200
  self._before_resolved_resources = change_set.stack.resolved_resources
181
- self._before_cache = dict()
182
- self._after_cache = dict()
201
+ self._before_cache = {}
202
+ self._after_cache = {}
183
203
 
184
204
  def _setup_runtime_cache(self) -> None:
185
205
  runtime_cache_key = self.__class__.__name__
@@ -207,6 +227,8 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
207
227
  def process(self) -> None:
208
228
  self._setup_runtime_cache()
209
229
  node_template = self._change_set.update_model.node_template
230
+ node_conditions = self._change_set.update_model.node_template.conditions
231
+ self.visit(node_conditions)
210
232
  self.visit(node_template)
211
233
  self._save_runtime_cache()
212
234
 
@@ -218,11 +240,13 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
218
240
  if node_resource.name == resource_name:
219
241
  self.visit(node_resource)
220
242
  return node_resource
221
- raise RuntimeError(f"No resource '{resource_name}' was found")
243
+ raise ValidationError(
244
+ f"Template format error: Unresolved resource dependencies [{resource_name}] in the Resources block of the template"
245
+ )
222
246
 
223
247
  def _get_node_property_for(
224
248
  self, property_name: str, node_resource: NodeResource
225
- ) -> Optional[NodeProperty]:
249
+ ) -> NodeProperty | None:
226
250
  # TODO: this could be improved with hashmap lookups if the Node contained bindings and not lists.
227
251
  for node_property in node_resource.properties.properties:
228
252
  if node_property.name == property_name:
@@ -233,7 +257,8 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
233
257
  def _deployed_property_value_of(
234
258
  self, resource_logical_id: str, property_name: str, resolved_resources: dict
235
259
  ) -> Any:
236
- # TODO: typing around resolved resources is needed and should be reflected here.
260
+ # We have to override this function to make sure it does not try to access the
261
+ # resolved resource
237
262
 
238
263
  # Before we can obtain deployed value for a resource, we need to first ensure to
239
264
  # process the resource if this wasn't processed already. Ideally, values should only
@@ -248,17 +273,17 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
248
273
  raise RuntimeError(
249
274
  f"No deployed instances of resource '{resource_logical_id}' were found"
250
275
  )
251
- properties = resolved_resource.get("Properties", dict())
252
- # support structured properties, e.g. NestedStack.Outputs.OutputName
253
- property_value: Optional[Any] = get_value_from_path(properties, property_name)
276
+ properties = resolved_resource.get("Properties", {})
277
+ # TODO support structured properties, e.g. NestedStack.Outputs.OutputName
278
+ property_value: Any | None = get_value_from_path(properties, property_name)
254
279
 
255
280
  if property_value:
256
- if not isinstance(property_value, str):
257
- # TODO: is this correct? If there is a bug in the logic here, it's probably
258
- # better to know about it with a clear error message than to receive some form
259
- # of message about trying to use a dictionary in place of a string
281
+ if not isinstance(property_value, (str, list, dict)):
282
+ # Str: Standard expected type. TODO validate bools and numbers
283
+ # List: Multiple resource types can return a list of values e.g. AWS::EC2::VPC.
284
+ # Dict: Custom resources in CloudFormation can return arbitrary data structures.
260
285
  raise RuntimeError(
261
- f"Accessing property '{property_name}' from '{resource_logical_id}' resulted in a non-string value"
286
+ f"Accessing property '{property_name}' from '{resource_logical_id}' resulted in a non-string value nor list"
262
287
  )
263
288
  return property_value
264
289
  elif config.CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES:
@@ -277,7 +302,7 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
277
302
 
278
303
  def _after_deployed_property_value_of(
279
304
  self, resource_logical_id: str, property_name: str
280
- ) -> Optional[str]:
305
+ ) -> str | None:
281
306
  return self._before_deployed_property_value_of(
282
307
  resource_logical_id=resource_logical_id, property_name=property_name
283
308
  )
@@ -367,8 +392,12 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
367
392
  node_mapping: NodeMapping = self._get_node_mapping(map_name=map_name)
368
393
  top_level_value = node_mapping.bindings.bindings.get(top_level_key)
369
394
  if not isinstance(top_level_value, NodeObject):
370
- raise RuntimeError()
395
+ error_key = "::".join([map_name, top_level_key, second_level_key])
396
+ raise ValidationError(f"Template error: Unable to get mapping for {error_key}")
371
397
  second_level_value = top_level_value.bindings.get(second_level_key)
398
+ if not isinstance(second_level_value, (TerminalValue, NodeArray, NodeObject)):
399
+ error_key = "::".join([map_name, top_level_key, second_level_key])
400
+ raise ValidationError(f"Template error: Unable to get mapping for {error_key}")
372
401
  mapping_value_delta = self.visit(second_level_value)
373
402
  return mapping_value_delta
374
403
 
@@ -380,10 +409,63 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
380
409
  return PreprocEntityDelta(before=before, after=after)
381
410
  delta = super().visit(change_set_entity=change_set_entity)
382
411
  if isinstance(delta, PreprocEntityDelta):
412
+ delta = self._maybe_perform_replacements(delta)
383
413
  self._before_cache[entity_scope] = delta.before
384
414
  self._after_cache[entity_scope] = delta.after
385
415
  return delta
386
416
 
417
+ def _maybe_perform_replacements(self, delta: PreprocEntityDelta) -> PreprocEntityDelta:
418
+ delta = self._maybe_perform_static_replacements(delta)
419
+ delta = self._maybe_perform_dynamic_replacements(delta)
420
+ return delta
421
+
422
+ def _maybe_perform_static_replacements(self, delta: PreprocEntityDelta) -> PreprocEntityDelta:
423
+ return self._maybe_perform_on_delta(delta, self._perform_static_replacements)
424
+
425
+ def _maybe_perform_dynamic_replacements(self, delta: PreprocEntityDelta) -> PreprocEntityDelta:
426
+ return self._maybe_perform_on_delta(delta, self._perform_dynamic_replacements)
427
+
428
+ def _maybe_perform_on_delta(
429
+ self, delta: PreprocEntityDelta | None, f: Callable[[_T], _T]
430
+ ) -> PreprocEntityDelta | None:
431
+ if isinstance(delta.before, str):
432
+ delta.before = f(delta.before)
433
+ if isinstance(delta.after, str):
434
+ delta.after = f(delta.after)
435
+ return delta
436
+
437
+ def _perform_dynamic_replacements(self, value: _T) -> _T:
438
+ if not isinstance(value, str):
439
+ return value
440
+
441
+ if dynamic_ref := extract_dynamic_reference(value):
442
+ new_value = perform_dynamic_reference_lookup(
443
+ reference=dynamic_ref,
444
+ account_id=self._change_set.account_id,
445
+ region_name=self._change_set.region_name,
446
+ )
447
+ if new_value:
448
+ # We need to use a function here, to avoid backslash processing by regex.
449
+ # From the regex sub documentation:
450
+ # repl can be a string or a function; if it is a string, any backslash escapes in it are processed.
451
+ # Using a function, we can avoid this processing.
452
+ return REGEX_DYNAMIC_REF.sub(lambda _: new_value, value)
453
+
454
+ return value
455
+
456
+ @staticmethod
457
+ def _perform_static_replacements(value: str) -> str:
458
+ api_match = REGEX_OUTPUT_APIGATEWAY.match(value)
459
+ if api_match and value not in config.CFN_STRING_REPLACEMENT_DENY_LIST:
460
+ prefix = api_match[1]
461
+ host = api_match[2]
462
+ path = api_match[3]
463
+ port = localstack_host().port
464
+ value = f"{prefix}{host}:{port}/{path}"
465
+ return value
466
+
467
+ return value
468
+
387
469
  def _cached_apply(
388
470
  self, scope: Scope, arguments_delta: PreprocEntityDelta, resolver: Callable[[Any], Any]
389
471
  ) -> PreprocEntityDelta:
@@ -432,6 +514,9 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
432
514
 
433
515
  return PreprocEntityDelta(before=before, after=after)
434
516
 
517
+ def visit_node_property(self, node_property: NodeProperty) -> PreprocEntityDelta:
518
+ return self.visit(node_property.value)
519
+
435
520
  def visit_terminal_value_modified(
436
521
  self, terminal_value_modified: TerminalValueModified
437
522
  ) -> PreprocEntityDelta:
@@ -465,15 +550,15 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
465
550
 
466
551
  def visit_node_object(self, node_object: NodeObject) -> PreprocEntityDelta:
467
552
  node_change_type = node_object.change_type
468
- before = dict() if node_change_type != ChangeType.CREATED else Nothing
469
- after = dict() if node_change_type != ChangeType.REMOVED else Nothing
553
+ before = {} if node_change_type != ChangeType.CREATED else Nothing
554
+ after = {} if node_change_type != ChangeType.REMOVED else Nothing
470
555
  for name, change_set_entity in node_object.bindings.items():
471
556
  delta: PreprocEntityDelta = self.visit(change_set_entity=change_set_entity)
472
557
  delta_before = delta.before
473
558
  delta_after = delta.after
474
- if not is_nothing(before) and not is_nothing(delta_before) and delta_before is not None:
559
+ if not is_nothing(before) and not is_nothing(delta_before):
475
560
  before[name] = delta_before
476
- if not is_nothing(after) and not is_nothing(delta_after) and delta_after is not None:
561
+ if not is_nothing(after) and not is_nothing(delta_after):
477
562
  after[name] = delta_after
478
563
  return PreprocEntityDelta(before=before, after=after)
479
564
 
@@ -484,33 +569,57 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
484
569
  arguments_list = arguments.split(".")
485
570
  else:
486
571
  arguments_list = arguments
572
+
573
+ if len(arguments_list) < 2:
574
+ raise ValidationError(
575
+ "Template error: every Fn::GetAtt object requires two non-empty parameters, the resource name and the resource attribute"
576
+ )
577
+
487
578
  logical_name_of_resource = arguments_list[0]
488
- attribute_name = arguments_list[1]
579
+ attribute_name = ".".join(arguments_list[1:])
489
580
 
490
581
  node_resource = self._get_node_resource_for(
491
582
  resource_name=logical_name_of_resource,
492
583
  node_template=self._change_set.update_model.node_template,
493
584
  )
494
- node_property: Optional[NodeProperty] = self._get_node_property_for(
585
+
586
+ if not is_nothing(node_resource.condition_reference):
587
+ condition = self._get_node_condition_if_exists(node_resource.condition_reference.value)
588
+ evaluation_result = self._resolve_condition(condition.name)
589
+
590
+ if select_before and not evaluation_result.before:
591
+ raise ValidationError(
592
+ f"Template format error: Unresolved resource dependencies [{logical_name_of_resource}] in the Resources block of the template"
593
+ )
594
+
595
+ if not select_before and not evaluation_result.after:
596
+ raise ValidationError(
597
+ f"Template format error: Unresolved resource dependencies [{logical_name_of_resource}] in the Resources block of the template"
598
+ )
599
+
600
+ # Custom Resources can mutate their definition
601
+ # So the preproc should search first in the resource values and then check the template
602
+ if select_before:
603
+ value = self._before_deployed_property_value_of(
604
+ resource_logical_id=logical_name_of_resource,
605
+ property_name=attribute_name,
606
+ )
607
+ else:
608
+ value = self._after_deployed_property_value_of(
609
+ resource_logical_id=logical_name_of_resource,
610
+ property_name=attribute_name,
611
+ )
612
+ if value is not None:
613
+ return value
614
+
615
+ node_property: NodeProperty | None = self._get_node_property_for(
495
616
  property_name=attribute_name, node_resource=node_resource
496
617
  )
497
618
  if node_property is not None:
498
619
  # The property is statically defined in the template and its value can be computed.
499
620
  property_delta = self.visit(node_property)
500
621
  value = property_delta.before if select_before else property_delta.after
501
- else:
502
- # The property is not statically defined and must therefore be available in
503
- # the properties deployed set.
504
- if select_before:
505
- value = self._before_deployed_property_value_of(
506
- resource_logical_id=logical_name_of_resource,
507
- property_name=attribute_name,
508
- )
509
- else:
510
- value = self._after_deployed_property_value_of(
511
- resource_logical_id=logical_name_of_resource,
512
- property_name=attribute_name,
513
- )
622
+
514
623
  return value
515
624
 
516
625
  def visit_node_intrinsic_function_fn_get_att(
@@ -539,6 +648,12 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
539
648
  return args[0] == args[1]
540
649
 
541
650
  arguments_delta = self.visit(node_intrinsic_function.arguments)
651
+
652
+ if isinstance(arguments_delta.after, list) and len(arguments_delta.after) != 2:
653
+ raise ValidationError(
654
+ "Template error: every Fn::Equals object requires a list of 2 string parameters."
655
+ )
656
+
542
657
  delta = self._cached_apply(
543
658
  scope=node_intrinsic_function.scope,
544
659
  arguments_delta=arguments_delta,
@@ -549,21 +664,38 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
549
664
  def visit_node_intrinsic_function_fn_if(
550
665
  self, node_intrinsic_function: NodeIntrinsicFunction
551
666
  ) -> PreprocEntityDelta:
552
- def _compute_delta_for_if_statement(args: list[Any]) -> PreprocEntityDelta:
553
- condition_name = args[0]
554
- boolean_expression_delta = self._resolve_condition(logical_id=condition_name)
555
- return PreprocEntityDelta(
556
- before=args[1] if boolean_expression_delta.before else args[2],
557
- after=args[1] if boolean_expression_delta.after else args[2],
667
+ # `if` needs to be short-circuiting i.e. if the condition is True we don't evaluate the
668
+ # False branch. If the condition is False, we don't evaluate the True branch.
669
+ if len(node_intrinsic_function.arguments.array) != 3:
670
+ raise ValueError(
671
+ f"Incorrectly constructed Fn::If usage, expected 3 arguments, found {len(node_intrinsic_function.arguments.array)}"
558
672
  )
559
673
 
560
- arguments_delta = self.visit(node_intrinsic_function.arguments)
561
- delta = self._cached_apply(
562
- scope=node_intrinsic_function.scope,
563
- arguments_delta=arguments_delta,
564
- resolver=_compute_delta_for_if_statement,
565
- )
566
- return delta
674
+ condition_delta = self.visit(node_intrinsic_function.arguments.array[0])
675
+ if_delta = PreprocEntityDelta()
676
+ if not is_nothing(condition_delta.before):
677
+ node_condition = self._get_node_condition_if_exists(
678
+ condition_name=condition_delta.before
679
+ )
680
+ condition_value = self.visit(node_condition).before
681
+ if condition_value:
682
+ arg_delta = self.visit(node_intrinsic_function.arguments.array[1])
683
+ else:
684
+ arg_delta = self.visit(node_intrinsic_function.arguments.array[2])
685
+ if_delta.before = arg_delta.before
686
+
687
+ if not is_nothing(condition_delta.after):
688
+ node_condition = self._get_node_condition_if_exists(
689
+ condition_name=condition_delta.after
690
+ )
691
+ condition_value = self.visit(node_condition).after
692
+ if condition_value:
693
+ arg_delta = self.visit(node_intrinsic_function.arguments.array[1])
694
+ else:
695
+ arg_delta = self.visit(node_intrinsic_function.arguments.array[2])
696
+ if_delta.after = arg_delta.after
697
+
698
+ return if_delta
567
699
 
568
700
  def visit_node_intrinsic_function_fn_and(
569
701
  self, node_intrinsic_function: NodeIntrinsicFunction
@@ -598,8 +730,12 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
598
730
  def visit_node_intrinsic_function_fn_not(
599
731
  self, node_intrinsic_function: NodeIntrinsicFunction
600
732
  ) -> PreprocEntityDelta:
601
- def _compute_fn_not(arg: bool) -> bool:
602
- return not arg
733
+ def _compute_fn_not(arg: list[bool] | bool) -> bool:
734
+ # Is the argument ever a lone boolean?
735
+ if isinstance(arg, list):
736
+ return not arg[0]
737
+ else:
738
+ return not arg
603
739
 
604
740
  arguments_delta = self.visit(node_intrinsic_function.arguments)
605
741
  delta = self._cached_apply(
@@ -609,65 +745,6 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
609
745
  )
610
746
  return delta
611
747
 
612
- def _compute_fn_transform(self, args: dict[str, Any]) -> Any:
613
- # TODO: add typing to arguments before this level.
614
- # TODO: add schema validation
615
- # TODO: add support for other transform types
616
-
617
- account_id = self._change_set.account_id
618
- region_name = self._change_set.region_name
619
- transform_name: str = args.get("Name")
620
- if not isinstance(transform_name, str):
621
- raise RuntimeError("Invalid or missing Fn::Transform 'Name' argument")
622
- transform_parameters: dict = args.get("Parameters")
623
- if not isinstance(transform_parameters, dict):
624
- raise RuntimeError("Invalid or missing Fn::Transform 'Parameters' argument")
625
-
626
- if transform_name in transformers:
627
- # TODO: port and refactor this 'transformers' logic to this package.
628
- builtin_transformer_class = transformers[transform_name]
629
- builtin_transformer: Transformer = builtin_transformer_class()
630
- transform_output: Any = builtin_transformer.transform(
631
- account_id=account_id, region_name=region_name, parameters=transform_parameters
632
- )
633
- return transform_output
634
-
635
- macros_store = get_cloudformation_store(
636
- account_id=account_id, region_name=region_name
637
- ).macros
638
- if transform_name in macros_store:
639
- # TODO: this formatting of stack parameters is odd but required to integrate with v1 execute_macro util.
640
- # consider porting this utils and passing the plain list of parameters instead.
641
- stack_parameters = {
642
- parameter["ParameterKey"]: parameter
643
- for parameter in self._change_set.stack.parameters
644
- }
645
- transform_output: Any = execute_macro(
646
- account_id=account_id,
647
- region_name=region_name,
648
- parsed_template=dict(), # TODO: review the requirements for this argument.
649
- macro=args, # TODO: review support for non dict bindings (v1).
650
- stack_parameters=stack_parameters,
651
- transformation_parameters=transform_parameters,
652
- is_intrinsic=True,
653
- )
654
- return transform_output
655
-
656
- raise RuntimeError(
657
- f"Unsupported transform function '{transform_name}' in '{self._change_set.stack.stack_name}'"
658
- )
659
-
660
- def visit_node_intrinsic_function_fn_transform(
661
- self, node_intrinsic_function: NodeIntrinsicFunction
662
- ) -> PreprocEntityDelta:
663
- arguments_delta = self.visit(node_intrinsic_function.arguments)
664
- delta = self._cached_apply(
665
- scope=node_intrinsic_function.scope,
666
- arguments_delta=arguments_delta,
667
- resolver=self._compute_fn_transform,
668
- )
669
- return delta
670
-
671
748
  def visit_node_intrinsic_function_fn_sub(
672
749
  self, node_intrinsic_function: NodeIntrinsicFunction
673
750
  ) -> PreprocEntityDelta:
@@ -677,7 +754,7 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
677
754
  sub_parameters: dict
678
755
  if isinstance(args, str):
679
756
  string_template = args
680
- sub_parameters = dict()
757
+ sub_parameters = {}
681
758
  elif (
682
759
  isinstance(args, list)
683
760
  and len(args) == 2
@@ -784,7 +861,7 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
784
861
  if values == "":
785
862
  return ""
786
863
  raise RuntimeError(f"Invalid arguments list definition for Fn::Join: '{args}'")
787
- str_values: list[str] = list()
864
+ str_values: list[str] = []
788
865
  for value in values:
789
866
  if value is None:
790
867
  continue
@@ -806,13 +883,27 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
806
883
  ):
807
884
  # TODO: add further support for schema validation
808
885
  def _compute_fn_select(args: list[Any]) -> Any:
809
- values: list[Any] = args[1]
886
+ values = args[1]
887
+ # defer evaluation if the selection list contains unresolved elements (e.g., unresolved intrinsics)
888
+ if isinstance(values, list) and not all(isinstance(value, str) for value in values):
889
+ raise RuntimeError("Fn::Select list contains unresolved elements")
890
+
810
891
  if not isinstance(values, list) or not values:
811
- raise RuntimeError(f"Invalid arguments list value for Fn::Select: '{values}'")
892
+ raise ValidationError(
893
+ "Template error: Fn::Select requires a list argument with two elements: an integer index and a list"
894
+ )
895
+ try:
896
+ index: int = int(args[0])
897
+ except ValueError as e:
898
+ raise ValidationError(
899
+ "Template error: Fn::Select requires a list argument with two elements: an integer index and a list"
900
+ ) from e
901
+
812
902
  values_len = len(values)
813
- index: int = int(args[0])
814
- if not isinstance(index, int) or index < 0 or index > values_len:
815
- raise RuntimeError(f"Invalid or out of range index value for Fn::Select: '{index}'")
903
+ if index < 0 or index >= values_len:
904
+ raise ValidationError(
905
+ "Template error: Fn::Select requires a list argument with two elements: an integer index and a list"
906
+ )
816
907
  selection = values[index]
817
908
  return selection
818
909
 
@@ -839,6 +930,17 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
839
930
  return split_string
840
931
 
841
932
  arguments_delta = self.visit(node_intrinsic_function.arguments)
933
+
934
+ if not (
935
+ is_nothing(arguments_delta.after)
936
+ or isinstance(arguments_delta.after, list)
937
+ and len(arguments_delta.after) == 2
938
+ ):
939
+ raise ValidationError(
940
+ "Template error: every Fn::Split object requires two parameters, "
941
+ "(1) a string delimiter and (2) a string to be split or a function that returns a string to be split."
942
+ )
943
+
842
944
  delta = self._cached_apply(
843
945
  scope=node_intrinsic_function.scope,
844
946
  arguments_delta=arguments_delta,
@@ -925,8 +1027,8 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
925
1027
  def visit_node_parameters(
926
1028
  self, node_parameters: NodeParameters
927
1029
  ) -> PreprocEntityDelta[dict[str, Any], dict[str, Any]]:
928
- before_parameters = dict()
929
- after_parameters = dict()
1030
+ before_parameters = {}
1031
+ after_parameters = {}
930
1032
  for parameter in node_parameters.parameters:
931
1033
  parameter_delta = self.visit(parameter)
932
1034
  parameter_before = parameter_delta.before
@@ -938,6 +1040,10 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
938
1040
  return PreprocEntityDelta(before=before_parameters, after=after_parameters)
939
1041
 
940
1042
  def visit_node_parameter(self, node_parameter: NodeParameter) -> PreprocEntityDelta:
1043
+ if not VALID_LOGICAL_RESOURCE_ID_RE.match(node_parameter.name):
1044
+ raise ValidationError(
1045
+ f"Template format error: Parameter name {node_parameter.name} is non alphanumeric."
1046
+ )
941
1047
  dynamic_value = node_parameter.dynamic_value
942
1048
  dynamic_delta = self.visit(dynamic_value)
943
1049
 
@@ -951,8 +1057,11 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
951
1057
 
952
1058
  def _resolve_parameter_type(value: str, type_: str) -> Any:
953
1059
  match type_:
954
- case "List<String>":
1060
+ case "List<String>" | "CommaDelimitedList":
955
1061
  return [item.strip() for item in value.split(",")]
1062
+ case "Number":
1063
+ # TODO: validate the parameter type at template parse time (or whatever is in parity with AWS) so we know this cannot fail
1064
+ return to_number(value)
956
1065
  return value
957
1066
 
958
1067
  if not is_nothing(after):
@@ -969,11 +1078,17 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
969
1078
  return delta
970
1079
 
971
1080
  def _resource_physical_resource_id_from(
972
- self, logical_resource_id: str, resolved_resources: dict
973
- ) -> str:
1081
+ self, logical_resource_id: str, resolved_resources: dict[str, ResolvedResource]
1082
+ ) -> str | None:
974
1083
  # TODO: typing around resolved resources is needed and should be reflected here.
975
- resolved_resource = resolved_resources.get(logical_resource_id, dict())
976
- physical_resource_id: Optional[str] = resolved_resource.get("PhysicalResourceId")
1084
+ resolved_resource = resolved_resources.get(logical_resource_id, {})
1085
+ if resolved_resource.get("ResourceStatus") not in {
1086
+ ResourceStatus.CREATE_COMPLETE,
1087
+ ResourceStatus.UPDATE_COMPLETE,
1088
+ }:
1089
+ return None
1090
+
1091
+ physical_resource_id = resolved_resource.get("PhysicalResourceId")
977
1092
  if not isinstance(physical_resource_id, str):
978
1093
  raise RuntimeError(f"No PhysicalResourceId found for resource '{logical_resource_id}'")
979
1094
  return physical_resource_id
@@ -992,6 +1107,9 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
992
1107
  self, node_intrinsic_function: NodeIntrinsicFunction
993
1108
  ) -> PreprocEntityDelta:
994
1109
  def _compute_fn_ref(logical_id: str) -> PreprocEntityDelta:
1110
+ if logical_id == "AWS::NoValue":
1111
+ return Nothing
1112
+
995
1113
  reference_delta: PreprocEntityDelta = self._resolve_reference(logical_id=logical_id)
996
1114
  if isinstance(before := reference_delta.before, PreprocResource):
997
1115
  reference_delta.before = before.physical_resource_id
@@ -1028,8 +1146,8 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
1028
1146
 
1029
1147
  def visit_node_array(self, node_array: NodeArray) -> PreprocEntityDelta:
1030
1148
  node_change_type = node_array.change_type
1031
- before = list() if node_change_type != ChangeType.CREATED else Nothing
1032
- after = list() if node_change_type != ChangeType.REMOVED else Nothing
1149
+ before = [] if node_change_type != ChangeType.CREATED else Nothing
1150
+ after = [] if node_change_type != ChangeType.REMOVED else Nothing
1033
1151
  for change_set_entity in node_array.array:
1034
1152
  delta: PreprocEntityDelta = self.visit(change_set_entity=change_set_entity)
1035
1153
  delta_before = delta.before
@@ -1040,15 +1158,12 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
1040
1158
  after.append(delta_after)
1041
1159
  return PreprocEntityDelta(before=before, after=after)
1042
1160
 
1043
- def visit_node_property(self, node_property: NodeProperty) -> PreprocEntityDelta:
1044
- return self.visit(node_property.value)
1045
-
1046
1161
  def visit_node_properties(
1047
1162
  self, node_properties: NodeProperties
1048
1163
  ) -> PreprocEntityDelta[PreprocProperties, PreprocProperties]:
1049
1164
  node_change_type = node_properties.change_type
1050
- before_bindings = dict() if node_change_type != ChangeType.CREATED else Nothing
1051
- after_bindings = dict() if node_change_type != ChangeType.REMOVED else Nothing
1165
+ before_bindings = {} if node_change_type != ChangeType.CREATED else Nothing
1166
+ after_bindings = {} if node_change_type != ChangeType.REMOVED else Nothing
1052
1167
  for node_property in node_properties.properties:
1053
1168
  property_name = node_property.name
1054
1169
  delta = self.visit(node_property)
@@ -1088,9 +1203,27 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
1088
1203
  after = after_delta.after
1089
1204
  return PreprocEntityDelta(before=before, after=after)
1090
1205
 
1206
+ def visit_node_resources(self, node_resources: NodeResources):
1207
+ """
1208
+ Skip resources where they conditionally evaluate to False
1209
+ """
1210
+ for node_resource in node_resources.resources:
1211
+ if not is_nothing(node_resource.condition_reference):
1212
+ condition_delta = self._resolve_resource_condition_reference(
1213
+ node_resource.condition_reference
1214
+ )
1215
+ condition_after = condition_delta.after
1216
+ if condition_after is False:
1217
+ continue
1218
+ self.visit(node_resource)
1219
+
1091
1220
  def visit_node_resource(
1092
1221
  self, node_resource: NodeResource
1093
1222
  ) -> PreprocEntityDelta[PreprocResource, PreprocResource]:
1223
+ if not VALID_LOGICAL_RESOURCE_ID_RE.match(node_resource.name):
1224
+ raise ValidationError(
1225
+ f"Template format error: Resource name {node_resource.name} is non alphanumeric."
1226
+ )
1094
1227
  change_type = node_resource.change_type
1095
1228
  condition_before = Nothing
1096
1229
  condition_after = Nothing
@@ -1127,6 +1260,7 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
1127
1260
  resource_type=type_delta.before,
1128
1261
  properties=properties_delta.before,
1129
1262
  depends_on=depends_on_before,
1263
+ requires_replacement=False,
1130
1264
  )
1131
1265
  if change_type != ChangeType.REMOVED and is_nothing(condition_after) or condition_after:
1132
1266
  logical_resource_id = node_resource.name
@@ -1143,6 +1277,7 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
1143
1277
  resource_type=type_delta.after,
1144
1278
  properties=properties_delta.after,
1145
1279
  depends_on=depends_on_after,
1280
+ requires_replacement=node_resource.requires_replacement,
1146
1281
  )
1147
1282
  return PreprocEntityDelta(before=before, after=after)
1148
1283
 
@@ -1189,9 +1324,17 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
1189
1324
  def visit_node_outputs(
1190
1325
  self, node_outputs: NodeOutputs
1191
1326
  ) -> PreprocEntityDelta[list[PreprocOutput], list[PreprocOutput]]:
1192
- before: list[PreprocOutput] = list()
1193
- after: list[PreprocOutput] = list()
1327
+ before: list[PreprocOutput] = []
1328
+ after: list[PreprocOutput] = []
1194
1329
  for node_output in node_outputs.outputs:
1330
+ if not is_nothing(node_output.condition_reference):
1331
+ condition_delta = self._resolve_resource_condition_reference(
1332
+ node_output.condition_reference
1333
+ )
1334
+ condition_after = condition_delta.after
1335
+ if condition_after is False:
1336
+ continue
1337
+
1195
1338
  output_delta: PreprocEntityDelta[PreprocOutput, PreprocOutput] = self.visit(node_output)
1196
1339
  output_before = output_delta.before
1197
1340
  output_after = output_delta.after
@@ -1200,3 +1343,29 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
1200
1343
  if not is_nothing(output_after):
1201
1344
  after.append(output_after)
1202
1345
  return PreprocEntityDelta(before=before, after=after)
1346
+
1347
+ def visit_node_intrinsic_function_fn_import_value(
1348
+ self, node_intrinsic_function: NodeIntrinsicFunction
1349
+ ) -> PreprocEntityDelta:
1350
+ def _compute_fn_import_value(string) -> str:
1351
+ if not isinstance(string, str):
1352
+ raise RuntimeError(f"Invalid parameter for import: '{string}'")
1353
+
1354
+ exports = exports_map(
1355
+ account_id=self._change_set.account_id, region_name=self._change_set.region_name
1356
+ )
1357
+
1358
+ return exports.get(string, {}).get("Value") or Nothing
1359
+
1360
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
1361
+ delta = self._cached_apply(
1362
+ scope=node_intrinsic_function.scope,
1363
+ arguments_delta=arguments_delta,
1364
+ resolver=_compute_fn_import_value,
1365
+ )
1366
+ return delta
1367
+
1368
+ def visit_node_intrinsic_function_fn_transform(
1369
+ self, node_intrinsic_function: NodeIntrinsicFunction
1370
+ ):
1371
+ raise RuntimeError("Fn::Transform should have been handled by the Transformer")