localstack-core 4.5.1.dev62__py3-none-any.whl → 4.5.1.dev63__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 (19) hide show
  1. localstack/services/cloudformation/engine/v2/change_set_model.py +22 -6
  2. localstack/services/cloudformation/engine/v2/change_set_model_describer.py +24 -4
  3. localstack/services/cloudformation/engine/v2/change_set_model_executor.py +2 -1
  4. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +223 -210
  5. localstack/services/cloudformation/engine/v2/change_set_model_transform.py +33 -18
  6. localstack/services/cloudformation/v2/entities.py +3 -3
  7. localstack/services/cloudformation/v2/provider.py +39 -3
  8. localstack/version.py +2 -2
  9. {localstack_core-4.5.1.dev62.dist-info → localstack_core-4.5.1.dev63.dist-info}/METADATA +1 -1
  10. {localstack_core-4.5.1.dev62.dist-info → localstack_core-4.5.1.dev63.dist-info}/RECORD +18 -18
  11. localstack_core-4.5.1.dev63.dist-info/plux.json +1 -0
  12. localstack_core-4.5.1.dev62.dist-info/plux.json +0 -1
  13. {localstack_core-4.5.1.dev62.data → localstack_core-4.5.1.dev63.data}/scripts/localstack +0 -0
  14. {localstack_core-4.5.1.dev62.data → localstack_core-4.5.1.dev63.data}/scripts/localstack-supervisor +0 -0
  15. {localstack_core-4.5.1.dev62.data → localstack_core-4.5.1.dev63.data}/scripts/localstack.bat +0 -0
  16. {localstack_core-4.5.1.dev62.dist-info → localstack_core-4.5.1.dev63.dist-info}/WHEEL +0 -0
  17. {localstack_core-4.5.1.dev62.dist-info → localstack_core-4.5.1.dev63.dist-info}/entry_points.txt +0 -0
  18. {localstack_core-4.5.1.dev62.dist-info → localstack_core-4.5.1.dev63.dist-info}/licenses/LICENSE.txt +0 -0
  19. {localstack_core-4.5.1.dev62.dist-info → localstack_core-4.5.1.dev63.dist-info}/top_level.txt +0 -0
@@ -147,6 +147,22 @@ class ChangeSetNode(ChangeSetEntity, abc.ABC): ...
147
147
  class ChangeSetTerminal(ChangeSetEntity, abc.ABC): ...
148
148
 
149
149
 
150
+ class UpdateModel:
151
+ # TODO: may be expanded to keep track of other runtime values such as resolved_parameters.
152
+
153
+ node_template: Final[NodeTemplate]
154
+ before_runtime_cache: Final[dict]
155
+ after_runtime_cache: Final[dict]
156
+
157
+ def __init__(
158
+ self,
159
+ node_template: NodeTemplate,
160
+ ):
161
+ self.node_template = node_template
162
+ self.before_runtime_cache = dict()
163
+ self.after_runtime_cache = dict()
164
+
165
+
150
166
  class NodeTemplate(ChangeSetNode):
151
167
  transform: Final[NodeTransform]
152
168
  mappings: Final[NodeMappings]
@@ -515,9 +531,8 @@ class ChangeSetModel:
515
531
  )
516
532
  # TODO: need to do template preprocessing e.g. parameter resolution, conditions etc.
517
533
 
518
- def get_update_model(self) -> NodeTemplate:
519
- # TODO: rethink naming of this for outer utils
520
- return self._node_template
534
+ def get_update_model(self) -> UpdateModel:
535
+ return UpdateModel(node_template=self._node_template)
521
536
 
522
537
  def _visit_terminal_value(
523
538
  self, scope: Scope, before_value: Maybe[Any], after_value: Maybe[Any]
@@ -548,8 +563,9 @@ class ChangeSetModel:
548
563
  node_intrinsic_function = self._visited_scopes.get(scope)
549
564
  if isinstance(node_intrinsic_function, NodeIntrinsicFunction):
550
565
  return node_intrinsic_function
566
+ arguments_scope = scope.open_scope("args")
551
567
  arguments = self._visit_value(
552
- scope=scope, before_value=before_arguments, after_value=after_arguments
568
+ scope=arguments_scope, before_value=before_arguments, after_value=after_arguments
553
569
  )
554
570
  if is_created(before=before_arguments, after=after_arguments):
555
571
  change_type = ChangeType.CREATED
@@ -777,7 +793,7 @@ class ChangeSetModel:
777
793
  self._safe_access_in(scope, dominant_type_name, before_value, after_value)
778
794
  )
779
795
  value = self._visit_intrinsic_function(
780
- scope=scope,
796
+ scope=intrinsic_function_scope,
781
797
  intrinsic_function=dominant_type_name,
782
798
  before_arguments=before_arguments,
783
799
  after_arguments=after_arguments,
@@ -937,7 +953,7 @@ class ChangeSetModel:
937
953
  scope, mapping_name, before_mappings, after_mappings
938
954
  )
939
955
  mapping = self._visit_mapping(
940
- scope=scope,
956
+ scope=scope_mapping,
941
957
  name=mapping_name,
942
958
  before_mapping=before_mapping,
943
959
  after_mapping=after_mapping,
@@ -8,6 +8,7 @@ from localstack.services.cloudformation.engine.v2.change_set_model import (
8
8
  NodeIntrinsicFunction,
9
9
  NodeProperty,
10
10
  NodeResource,
11
+ NodeResources,
11
12
  PropertiesKey,
12
13
  is_nothing,
13
14
  )
@@ -40,6 +41,20 @@ class ChangeSetModelDescriber(ChangeSetModelPreproc):
40
41
  self.process()
41
42
  return self._changes
42
43
 
44
+ def _setup_runtime_cache(self) -> None:
45
+ # The describer can output {{changeSet:KNOWN_AFTER_APPLY}} values as not every field
46
+ # is computable at describe time. Until a filtering logic or executor override logic
47
+ # is available, the describer cannot benefit of previous evaluations to compute
48
+ # change set resource changes.
49
+ pass
50
+
51
+ def _save_runtime_cache(self) -> None:
52
+ # The describer can output {{changeSet:KNOWN_AFTER_APPLY}} values as not every field
53
+ # is computable at describe time. Until a filtering logic or executor override logic
54
+ # is available, there are no benefits in having the describer saving its runtime cache
55
+ # for future changes chains.
56
+ pass
57
+
43
58
  def _resolve_attribute(self, arguments: str | list[str], select_before: bool) -> str:
44
59
  if select_before:
45
60
  return super()._resolve_attribute(arguments=arguments, select_before=select_before)
@@ -57,7 +72,8 @@ class ChangeSetModelDescriber(ChangeSetModelPreproc):
57
72
  attribute_name = arguments_list[1]
58
73
 
59
74
  node_resource = self._get_node_resource_for(
60
- resource_name=logical_name_of_resource, node_template=self._node_template
75
+ resource_name=logical_name_of_resource,
76
+ node_template=self._change_set.update_model.node_template,
61
77
  )
62
78
  node_property: Optional[NodeProperty] = self._get_node_property_for(
63
79
  property_name=attribute_name, node_resource=node_resource
@@ -182,6 +198,13 @@ class ChangeSetModelDescriber(ChangeSetModelPreproc):
182
198
  after_properties=after.properties,
183
199
  )
184
200
 
201
+ def visit_node_resources(self, node_resources: NodeResources) -> None:
202
+ for node_resource in node_resources.resources:
203
+ delta_resource = self.visit(node_resource)
204
+ self._describe_resource_change(
205
+ name=node_resource.name, before=delta_resource.before, after=delta_resource.after
206
+ )
207
+
185
208
  def visit_node_resource(
186
209
  self, node_resource: NodeResource
187
210
  ) -> PreprocEntityDelta[PreprocResource, PreprocResource]:
@@ -189,7 +212,4 @@ class ChangeSetModelDescriber(ChangeSetModelPreproc):
189
212
  after_resource = delta.after
190
213
  if not is_nothing(after_resource) and after_resource.physical_resource_id is None:
191
214
  after_resource.physical_resource_id = CHANGESET_KNOWN_AFTER_APPLY
192
- self._describe_resource_change(
193
- name=node_resource.name, before=delta.before, after=delta.after
194
- )
195
215
  return delta
@@ -159,7 +159,8 @@ class ChangeSetModelExecutor(ChangeSetModelPreproc):
159
159
  depends_on_resource_logical_ids.update(array_identifiers_delta.after)
160
160
  for depends_on_resource_logical_id in depends_on_resource_logical_ids:
161
161
  node_resource = self._get_node_resource_for(
162
- resource_name=depends_on_resource_logical_id, node_template=self._node_template
162
+ resource_name=depends_on_resource_logical_id,
163
+ node_template=self._change_set.update_model.node_template,
163
164
  )
164
165
  self.visit(node_resource)
165
166
 
@@ -1,8 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import base64
4
+ import copy
4
5
  import re
5
- from typing import Any, Final, Generic, Optional, TypeVar
6
+ from typing import Any, Callable, Final, Generic, Optional, TypeVar
6
7
 
7
8
  from botocore.exceptions import ClientError
8
9
 
@@ -33,6 +34,7 @@ from localstack.services.cloudformation.engine.v2.change_set_model import (
33
34
  NodeResource,
34
35
  NodeTemplate,
35
36
  Nothing,
37
+ NothingType,
36
38
  Scope,
37
39
  TerminalValue,
38
40
  TerminalValueCreated,
@@ -165,19 +167,44 @@ class PreprocOutput:
165
167
 
166
168
  class ChangeSetModelPreproc(ChangeSetModelVisitor):
167
169
  _change_set: Final[ChangeSet]
168
- _node_template: Final[NodeTemplate]
169
170
  _before_resolved_resources: Final[dict]
170
- _processed: dict[Scope, Any]
171
+ _before_cache: Final[dict[Scope, Any]]
172
+ _after_cache: Final[dict[Scope, Any]]
171
173
 
172
174
  def __init__(self, change_set: ChangeSet):
173
175
  self._change_set = change_set
174
- self._node_template = change_set.update_model
175
176
  self._before_resolved_resources = change_set.stack.resolved_resources
176
- self._processed = dict()
177
+ self._before_cache = dict()
178
+ self._after_cache = dict()
179
+
180
+ def _setup_runtime_cache(self) -> None:
181
+ runtime_cache_key = self.__class__.__name__
182
+
183
+ self._before_cache.clear()
184
+ self._after_cache.clear()
185
+
186
+ before_runtime_cache = self._change_set.update_model.before_runtime_cache
187
+ if cache := before_runtime_cache.get(runtime_cache_key):
188
+ self._before_cache.update(cache)
189
+
190
+ after_runtime_cache = self._change_set.update_model.after_runtime_cache
191
+ if cache := after_runtime_cache.get(runtime_cache_key):
192
+ self._after_cache.update(cache)
193
+
194
+ def _save_runtime_cache(self) -> None:
195
+ runtime_cache_key = self.__class__.__name__
196
+
197
+ before_runtime_cache = self._change_set.update_model.before_runtime_cache
198
+ before_runtime_cache[runtime_cache_key] = copy.deepcopy(self._before_cache)
199
+
200
+ after_runtime_cache = self._change_set.update_model.after_runtime_cache
201
+ after_runtime_cache[runtime_cache_key] = copy.deepcopy(self._after_cache)
177
202
 
178
203
  def process(self) -> None:
179
- self._processed.clear()
180
- self.visit(self._node_template)
204
+ self._setup_runtime_cache()
205
+ node_template = self._change_set.update_model.node_template
206
+ self.visit(node_template)
207
+ self._save_runtime_cache()
181
208
 
182
209
  def _get_node_resource_for(
183
210
  self, resource_name: str, node_template: NodeTemplate
@@ -209,7 +236,8 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
209
236
  # be accessible through delta objects, to ensure computation is always complete at
210
237
  # every level.
211
238
  _ = self._get_node_resource_for(
212
- resource_name=resource_logical_id, node_template=self._node_template
239
+ resource_name=resource_logical_id,
240
+ node_template=self._change_set.update_model.node_template,
213
241
  )
214
242
  resolved_resource = resolved_resources.get(resource_logical_id)
215
243
  if resolved_resource is None:
@@ -241,7 +269,7 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
241
269
  )
242
270
 
243
271
  def _get_node_mapping(self, map_name: str) -> NodeMapping:
244
- mappings: list[NodeMapping] = self._node_template.mappings.mappings
272
+ mappings: list[NodeMapping] = self._change_set.update_model.node_template.mappings.mappings
245
273
  # TODO: another scenarios suggesting property lookups might be preferable.
246
274
  for mapping in mappings:
247
275
  if mapping.name == map_name:
@@ -250,7 +278,9 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
250
278
  raise RuntimeError(f"Undefined '{map_name}' mapping")
251
279
 
252
280
  def _get_node_parameter_if_exists(self, parameter_name: str) -> Maybe[NodeParameter]:
253
- parameters: list[NodeParameter] = self._node_template.parameters.parameters
281
+ parameters: list[NodeParameter] = (
282
+ self._change_set.update_model.node_template.parameters.parameters
283
+ )
254
284
  # TODO: another scenarios suggesting property lookups might be preferable.
255
285
  for parameter in parameters:
256
286
  if parameter.name == parameter_name:
@@ -259,7 +289,9 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
259
289
  return Nothing
260
290
 
261
291
  def _get_node_condition_if_exists(self, condition_name: str) -> Maybe[NodeCondition]:
262
- conditions: list[NodeCondition] = self._node_template.conditions.conditions
292
+ conditions: list[NodeCondition] = (
293
+ self._change_set.update_model.node_template.conditions.conditions
294
+ )
263
295
  # TODO: another scenarios suggesting property lookups might be preferable.
264
296
  for condition in conditions:
265
297
  if condition.name == condition_name:
@@ -307,7 +339,7 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
307
339
  return parameter_delta
308
340
 
309
341
  node_resource = self._get_node_resource_for(
310
- resource_name=logical_id, node_template=self._node_template
342
+ resource_name=logical_id, node_template=self._change_set.update_model.node_template
311
343
  )
312
344
  resource_delta = self.visit(node_resource)
313
345
  before = resource_delta.before
@@ -327,14 +359,65 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
327
359
  return mapping_value_delta
328
360
 
329
361
  def visit(self, change_set_entity: ChangeSetEntity) -> PreprocEntityDelta:
330
- scope = change_set_entity.scope
331
- if scope in self._processed:
332
- delta = self._processed[scope]
333
- return delta
362
+ entity_scope = change_set_entity.scope
363
+ if entity_scope in self._before_cache and entity_scope in self._after_cache:
364
+ before = self._before_cache[entity_scope]
365
+ after = self._after_cache[entity_scope]
366
+ return PreprocEntityDelta(before=before, after=after)
334
367
  delta = super().visit(change_set_entity=change_set_entity)
335
- self._processed[scope] = delta
368
+ if isinstance(delta, PreprocEntityDelta):
369
+ self._before_cache[entity_scope] = delta.before
370
+ self._after_cache[entity_scope] = delta.after
336
371
  return delta
337
372
 
373
+ def _cached_apply(
374
+ self, scope: Scope, arguments_delta: PreprocEntityDelta, resolver: Callable[[Any], Any]
375
+ ) -> PreprocEntityDelta:
376
+ """
377
+ Applies the resolver function to the given input delta if and only if the required
378
+ values are not already present in the runtime caches. This function handles both
379
+ the 'before' and 'after' components of the delta independently.
380
+
381
+ The resolver function receives either the 'before' or 'after' value from the input
382
+ delta and returns a resolved value. If the result returned by the resolver is
383
+ itself a PreprocEntityDelta, the function automatically extracts the appropriate
384
+ component from it: the 'before' value if the input was 'before', and the 'after'
385
+ value if the input was 'after'.
386
+
387
+ This function only reads from the cache and does not update it. It is the caller's
388
+ responsibility to handle caching, either manually or via the upstream visit method
389
+ of this class.
390
+
391
+ Args:
392
+ scope (Scope): The current scope used as a key for cache lookup.
393
+ arguments_delta (PreprocEntityDelta): The delta containing 'before' and 'after' values to resolve.
394
+ resolver (Callable[[Any], Any]): Function to apply on uncached 'before' or 'after' argument values.
395
+
396
+ Returns:
397
+ PreprocEntityDelta: A new delta with resolved 'before' and 'after' values.
398
+ """
399
+
400
+ # TODO: Update all visit_* methods in this class and its subclasses to use this function.
401
+ # This ensures maximal reuse of precomputed 'before' (and 'after') values from
402
+ # prior runtimes on the change sets template, thus avoiding unnecessary recomputation.
403
+
404
+ arguments_before = arguments_delta.before
405
+ arguments_after = arguments_delta.after
406
+
407
+ before = self._before_cache.get(scope, Nothing)
408
+ if is_nothing(before) and not is_nothing(arguments_before):
409
+ before = resolver(arguments_before)
410
+ if isinstance(before, PreprocEntityDelta):
411
+ before = before.before
412
+
413
+ after = self._after_cache.get(scope, Nothing)
414
+ if is_nothing(after) and not is_nothing(arguments_after):
415
+ after = resolver(arguments_after)
416
+ if isinstance(after, PreprocEntityDelta):
417
+ after = after.after
418
+
419
+ return PreprocEntityDelta(before=before, after=after)
420
+
338
421
  def visit_terminal_value_modified(
339
422
  self, terminal_value_modified: TerminalValueModified
340
423
  ) -> PreprocEntityDelta:
@@ -391,7 +474,8 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
391
474
  attribute_name = arguments_list[1]
392
475
 
393
476
  node_resource = self._get_node_resource_for(
394
- resource_name=logical_name_of_resource, node_template=self._node_template
477
+ resource_name=logical_name_of_resource,
478
+ node_template=self._change_set.update_model.node_template,
395
479
  )
396
480
  node_property: Optional[NodeProperty] = self._get_node_property_for(
397
481
  property_name=attribute_name, node_resource=node_resource
@@ -423,12 +507,12 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
423
507
  before_arguments: Maybe[str | list[str]] = arguments_delta.before
424
508
  after_arguments: Maybe[str | list[str]] = arguments_delta.after
425
509
 
426
- before = Nothing
427
- if not is_nothing(before_arguments):
510
+ before = self._before_cache.get(node_intrinsic_function.scope, Nothing)
511
+ if is_nothing(before) and not is_nothing(before_arguments):
428
512
  before = self._resolve_attribute(arguments=before_arguments, select_before=True)
429
513
 
430
- after = Nothing
431
- if not is_nothing(after_arguments):
514
+ after = self._after_cache.get(node_intrinsic_function.scope, Nothing)
515
+ if is_nothing(after) and not is_nothing(after_arguments):
432
516
  after = self._resolve_attribute(arguments=after_arguments, select_before=False)
433
517
 
434
518
  return PreprocEntityDelta(before=before, after=after)
@@ -436,24 +520,21 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
436
520
  def visit_node_intrinsic_function_fn_equals(
437
521
  self, node_intrinsic_function: NodeIntrinsicFunction
438
522
  ) -> PreprocEntityDelta:
523
+ # TODO: add argument shape validation.
524
+ def _compute_fn_equals(args: list[Any]) -> bool:
525
+ return args[0] == args[1]
526
+
439
527
  arguments_delta = self.visit(node_intrinsic_function.arguments)
440
- before_values = arguments_delta.before
441
- after_values = arguments_delta.after
442
- before = Nothing
443
- if before_values:
444
- before = before_values[0] == before_values[1]
445
- after = Nothing
446
- if after_values:
447
- after = after_values[0] == after_values[1]
448
- return PreprocEntityDelta(before=before, after=after)
528
+ delta = self._cached_apply(
529
+ scope=node_intrinsic_function.scope,
530
+ arguments_delta=arguments_delta,
531
+ resolver=_compute_fn_equals,
532
+ )
533
+ return delta
449
534
 
450
535
  def visit_node_intrinsic_function_fn_if(
451
536
  self, node_intrinsic_function: NodeIntrinsicFunction
452
537
  ) -> PreprocEntityDelta:
453
- arguments_delta = self.visit(node_intrinsic_function.arguments)
454
- arguments_before = arguments_delta.before
455
- arguments_after = arguments_delta.after
456
-
457
538
  def _compute_delta_for_if_statement(args: list[Any]) -> PreprocEntityDelta:
458
539
  condition_name = args[0]
459
540
  boolean_expression_delta = self._resolve_condition(logical_id=condition_name)
@@ -462,74 +543,57 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
462
543
  after=args[1] if boolean_expression_delta.after else args[2],
463
544
  )
464
545
 
465
- # TODO: add support for this being created or removed.
466
- before = Nothing
467
- if not is_nothing(arguments_before):
468
- before_outcome_delta = _compute_delta_for_if_statement(arguments_before)
469
- before = before_outcome_delta.before
470
- after = Nothing
471
- if not is_nothing(arguments_after):
472
- after_outcome_delta = _compute_delta_for_if_statement(arguments_after)
473
- after = after_outcome_delta.after
474
- return PreprocEntityDelta(before=before, after=after)
546
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
547
+ delta = self._cached_apply(
548
+ scope=node_intrinsic_function.scope,
549
+ arguments_delta=arguments_delta,
550
+ resolver=_compute_delta_for_if_statement,
551
+ )
552
+ return delta
475
553
 
476
554
  def visit_node_intrinsic_function_fn_and(
477
555
  self, node_intrinsic_function: NodeIntrinsicFunction
478
556
  ) -> PreprocEntityDelta:
479
- arguments_delta = self.visit(node_intrinsic_function.arguments)
480
- arguments_before = arguments_delta.before
481
- arguments_after = arguments_delta.after
482
-
483
- def _compute_fn_and(args: list[bool]):
557
+ def _compute_fn_and(args: list[bool]) -> bool:
484
558
  result = all(args)
485
559
  return result
486
560
 
487
- before = Nothing
488
- if not is_nothing(arguments_before):
489
- before = _compute_fn_and(arguments_before)
490
-
491
- after = Nothing
492
- if not is_nothing(arguments_after):
493
- after = _compute_fn_and(arguments_after)
494
-
495
- return PreprocEntityDelta(before=before, after=after)
561
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
562
+ delta = self._cached_apply(
563
+ scope=node_intrinsic_function.scope,
564
+ arguments_delta=arguments_delta,
565
+ resolver=_compute_fn_and,
566
+ )
567
+ return delta
496
568
 
497
569
  def visit_node_intrinsic_function_fn_or(
498
570
  self, node_intrinsic_function: NodeIntrinsicFunction
499
571
  ) -> PreprocEntityDelta:
500
- arguments_delta = self.visit(node_intrinsic_function.arguments)
501
- arguments_before = arguments_delta.before
502
- arguments_after = arguments_delta.after
503
-
504
- def _compute_fn_and(args: list[bool]):
572
+ def _compute_fn_or(args: list[bool]):
505
573
  result = any(args)
506
574
  return result
507
575
 
508
- before = Nothing
509
- if not is_nothing(arguments_before):
510
- before = _compute_fn_and(arguments_before)
511
-
512
- after = Nothing
513
- if not is_nothing(arguments_after):
514
- after = _compute_fn_and(arguments_after)
515
- return PreprocEntityDelta(before=before, after=after)
576
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
577
+ delta = self._cached_apply(
578
+ scope=node_intrinsic_function.scope,
579
+ arguments_delta=arguments_delta,
580
+ resolver=_compute_fn_or,
581
+ )
582
+ return delta
516
583
 
517
584
  def visit_node_intrinsic_function_fn_not(
518
585
  self, node_intrinsic_function: NodeIntrinsicFunction
519
586
  ) -> PreprocEntityDelta:
587
+ def _compute_fn_not(arg: bool) -> bool:
588
+ return not arg
589
+
520
590
  arguments_delta = self.visit(node_intrinsic_function.arguments)
521
- before_condition = arguments_delta.before
522
- after_condition = arguments_delta.after
523
- before = Nothing
524
- if not is_nothing(before_condition):
525
- before_condition_outcome = before_condition[0]
526
- before = not before_condition_outcome
527
- after = Nothing
528
- if not is_nothing(after_condition):
529
- after_condition_outcome = after_condition[0]
530
- after = not after_condition_outcome
531
- # Implicit change type computation.
532
- return PreprocEntityDelta(before=before, after=after)
591
+ delta = self._cached_apply(
592
+ scope=node_intrinsic_function.scope,
593
+ arguments_delta=arguments_delta,
594
+ resolver=_compute_fn_not,
595
+ )
596
+ return delta
533
597
 
534
598
  def _compute_fn_transform(self, args: dict[str, Any]) -> Any:
535
599
  # TODO: add typing to arguments before this level.
@@ -583,33 +647,16 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
583
647
  self, node_intrinsic_function: NodeIntrinsicFunction
584
648
  ) -> PreprocEntityDelta:
585
649
  arguments_delta = self.visit(node_intrinsic_function.arguments)
586
- arguments_before = arguments_delta.before
587
- arguments_after = arguments_delta.after
588
-
589
- # TODO: review the use of cache in self.precessed from the 'before' run to
590
- # ensure changes to the lambda (such as after UpdateFunctionCode) do not
591
- # generalise tot he before value at this depth (thus making it seems as
592
- # though for this transformation before==after). Another options may be to
593
- # have specialised caching for transformations.
594
-
595
- # TODO: add tests to review the behaviour of CFN with changes to transformation
596
- # function code and no changes to the template.
597
-
598
- before = Nothing
599
- if not is_nothing(arguments_before):
600
- before = self._compute_fn_transform(args=arguments_before)
601
- after = Nothing
602
- if not is_nothing(arguments_after):
603
- after = self._compute_fn_transform(args=arguments_after)
604
- return PreprocEntityDelta(before=before, after=after)
650
+ delta = self._cached_apply(
651
+ scope=node_intrinsic_function.scope,
652
+ arguments_delta=arguments_delta,
653
+ resolver=self._compute_fn_transform,
654
+ )
655
+ return delta
605
656
 
606
657
  def visit_node_intrinsic_function_fn_sub(
607
658
  self, node_intrinsic_function: NodeIntrinsicFunction
608
659
  ) -> PreprocEntityDelta:
609
- arguments_delta = self.visit(node_intrinsic_function.arguments)
610
- arguments_before = arguments_delta.before
611
- arguments_after = arguments_delta.after
612
-
613
660
  def _compute_sub(args: str | list[Any], select_before: bool) -> str:
614
661
  # TODO: add further schema validation.
615
662
  string_template: str
@@ -695,24 +742,25 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
695
742
  result = sub_string
696
743
  return result
697
744
 
698
- before = Nothing
699
- if not is_nothing(arguments_before):
745
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
746
+ arguments_before = arguments_delta.before
747
+ arguments_after = arguments_delta.after
748
+ before = self._before_cache.get(node_intrinsic_function.scope, Nothing)
749
+ if is_nothing(before) and not is_nothing(arguments_before):
700
750
  before = _compute_sub(args=arguments_before, select_before=True)
701
- after = Nothing
702
- if not is_nothing(arguments_after):
751
+ after = self._after_cache.get(node_intrinsic_function.scope, Nothing)
752
+ if is_nothing(after) and not is_nothing(arguments_after):
703
753
  after = _compute_sub(args=arguments_after, select_before=False)
704
754
  return PreprocEntityDelta(before=before, after=after)
705
755
 
706
756
  def visit_node_intrinsic_function_fn_join(
707
757
  self, node_intrinsic_function: NodeIntrinsicFunction
708
758
  ) -> PreprocEntityDelta:
709
- arguments_delta = self.visit(node_intrinsic_function.arguments)
710
- arguments_before = arguments_delta.before
711
- arguments_after = arguments_delta.after
712
-
713
- def _compute_join(args: list[Any]) -> str:
714
- # TODO: add support for schema validation.
715
- # TODO: add tests for joining non string values.
759
+ # TODO: add support for schema validation.
760
+ # TODO: add tests for joining non string values.
761
+ def _compute_fn_join(args: list[Any]) -> str | NothingType:
762
+ if not (isinstance(args, list) and len(args) == 2):
763
+ return Nothing
716
764
  delimiter: str = str(args[0])
717
765
  values: list[Any] = args[1]
718
766
  if not isinstance(values, list):
@@ -731,22 +779,18 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
731
779
  join_result = delimiter.join(str_values)
732
780
  return join_result
733
781
 
734
- before = Nothing
735
- if isinstance(arguments_before, list) and len(arguments_before) == 2:
736
- before = _compute_join(arguments_before)
737
- after = Nothing
738
- if isinstance(arguments_after, list) and len(arguments_after) == 2:
739
- after = _compute_join(arguments_after)
740
- return PreprocEntityDelta(before=before, after=after)
782
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
783
+ delta = self._cached_apply(
784
+ scope=node_intrinsic_function.scope,
785
+ arguments_delta=arguments_delta,
786
+ resolver=_compute_fn_join,
787
+ )
788
+ return delta
741
789
 
742
790
  def visit_node_intrinsic_function_fn_select(
743
791
  self, node_intrinsic_function: NodeIntrinsicFunction
744
792
  ):
745
793
  # TODO: add further support for schema validation
746
- arguments_delta = self.visit(node_intrinsic_function.arguments)
747
- arguments_before = arguments_delta.before
748
- arguments_after = arguments_delta.after
749
-
750
794
  def _compute_fn_select(args: list[Any]) -> Any:
751
795
  values: list[Any] = args[1]
752
796
  if not isinstance(values, list) or not values:
@@ -758,24 +802,18 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
758
802
  selection = values[index]
759
803
  return selection
760
804
 
761
- before = Nothing
762
- if not is_nothing(arguments_before):
763
- before = _compute_fn_select(arguments_before)
764
-
765
- after = Nothing
766
- if not is_nothing(arguments_after):
767
- after = _compute_fn_select(arguments_after)
768
-
769
- return PreprocEntityDelta(before=before, after=after)
805
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
806
+ delta = self._cached_apply(
807
+ scope=node_intrinsic_function.scope,
808
+ arguments_delta=arguments_delta,
809
+ resolver=_compute_fn_select,
810
+ )
811
+ return delta
770
812
 
771
813
  def visit_node_intrinsic_function_fn_split(
772
814
  self, node_intrinsic_function: NodeIntrinsicFunction
773
815
  ):
774
816
  # TODO: add further support for schema validation
775
- arguments_delta = self.visit(node_intrinsic_function.arguments)
776
- arguments_before = arguments_delta.before
777
- arguments_after = arguments_delta.after
778
-
779
817
  def _compute_fn_split(args: list[Any]) -> Any:
780
818
  delimiter = args[0]
781
819
  if not isinstance(delimiter, str) or not delimiter:
@@ -786,23 +824,18 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
786
824
  split_string = source_string.split(delimiter)
787
825
  return split_string
788
826
 
789
- before = Nothing
790
- if not is_nothing(arguments_before):
791
- before = _compute_fn_split(arguments_before)
792
-
793
- after = Nothing
794
- if not is_nothing(arguments_after):
795
- after = _compute_fn_split(arguments_after)
796
-
797
- return PreprocEntityDelta(before=before, after=after)
827
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
828
+ delta = self._cached_apply(
829
+ scope=node_intrinsic_function.scope,
830
+ arguments_delta=arguments_delta,
831
+ resolver=_compute_fn_split,
832
+ )
833
+ return delta
798
834
 
799
835
  def visit_node_intrinsic_function_fn_get_a_zs(
800
836
  self, node_intrinsic_function: NodeIntrinsicFunction
801
837
  ) -> PreprocEntityDelta:
802
838
  # TODO: add further support for schema validation
803
- arguments_delta = self.visit(node_intrinsic_function.arguments)
804
- arguments_before = arguments_delta.before
805
- arguments_after = arguments_delta.after
806
839
 
807
840
  def _compute_fn_get_a_zs(region) -> Any:
808
841
  if not isinstance(region, str):
@@ -827,24 +860,18 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
827
860
  azs = [az["ZoneName"] for az in availability_zones]
828
861
  return azs
829
862
 
830
- before = Nothing
831
- if not is_nothing(arguments_before):
832
- before = _compute_fn_get_a_zs(arguments_before)
833
-
834
- after = Nothing
835
- if not is_nothing(arguments_after):
836
- after = _compute_fn_get_a_zs(arguments_after)
837
-
838
- return PreprocEntityDelta(before=before, after=after)
863
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
864
+ delta = self._cached_apply(
865
+ scope=node_intrinsic_function.scope,
866
+ arguments_delta=arguments_delta,
867
+ resolver=_compute_fn_get_a_zs,
868
+ )
869
+ return delta
839
870
 
840
871
  def visit_node_intrinsic_function_fn_base64(
841
872
  self, node_intrinsic_function: NodeIntrinsicFunction
842
873
  ) -> PreprocEntityDelta:
843
874
  # TODO: add further support for schema validation
844
- arguments_delta = self.visit(node_intrinsic_function.arguments)
845
- arguments_before = arguments_delta.before
846
- arguments_after = arguments_delta.after
847
-
848
875
  def _compute_fn_base_64(string) -> Any:
849
876
  if not isinstance(string, str):
850
877
  raise RuntimeError(f"Invalid valueToEncode for Fn::Base64: '{string}'")
@@ -852,15 +879,13 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
852
879
  base64_string = to_str(base64.b64encode(to_bytes(string)))
853
880
  return base64_string
854
881
 
855
- before = Nothing
856
- if not is_nothing(arguments_before):
857
- before = _compute_fn_base_64(arguments_before)
858
-
859
- after = Nothing
860
- if not is_nothing(arguments_after):
861
- after = _compute_fn_base_64(arguments_after)
862
-
863
- return PreprocEntityDelta(before=before, after=after)
882
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
883
+ delta = self._cached_apply(
884
+ scope=node_intrinsic_function.scope,
885
+ arguments_delta=arguments_delta,
886
+ resolver=_compute_fn_base_64,
887
+ )
888
+ return delta
864
889
 
865
890
  def visit_node_intrinsic_function_fn_find_in_map(
866
891
  self, node_intrinsic_function: NodeIntrinsicFunction
@@ -941,52 +966,40 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
941
966
  def visit_node_intrinsic_function_ref(
942
967
  self, node_intrinsic_function: NodeIntrinsicFunction
943
968
  ) -> PreprocEntityDelta:
944
- arguments_delta = self.visit(node_intrinsic_function.arguments)
945
- before_logical_id = arguments_delta.before
946
- after_logical_id = arguments_delta.after
947
-
948
- # TODO: extend this to support references to other types.
949
- before = Nothing
950
- if not is_nothing(before_logical_id):
951
- before_delta = self._resolve_reference(logical_id=before_logical_id)
952
- before = before_delta.before
953
- if isinstance(before, PreprocResource):
954
- before = before.physical_resource_id
955
-
956
- after = Nothing
957
- if not is_nothing(after_logical_id):
958
- after_delta = self._resolve_reference(logical_id=after_logical_id)
959
- after = after_delta.after
960
- if isinstance(after, PreprocResource):
961
- after = after.physical_resource_id
969
+ def _compute_fn_ref(logical_id: str) -> PreprocEntityDelta:
970
+ reference_delta: PreprocEntityDelta = self._resolve_reference(logical_id=logical_id)
971
+ if isinstance(before := reference_delta.before, PreprocResource):
972
+ reference_delta.before = before.physical_resource_id
973
+ if isinstance(after := reference_delta.after, PreprocResource):
974
+ reference_delta.after = after.physical_resource_id
975
+ return reference_delta
962
976
 
963
- return PreprocEntityDelta(before=before, after=after)
977
+ arguments_delta = self.visit(node_intrinsic_function.arguments)
978
+ delta = self._cached_apply(
979
+ scope=node_intrinsic_function.scope,
980
+ arguments_delta=arguments_delta,
981
+ resolver=_compute_fn_ref,
982
+ )
983
+ return delta
964
984
 
965
985
  def visit_node_intrinsic_function_condition(
966
986
  self, node_intrinsic_function: NodeIntrinsicFunction
967
987
  ) -> PreprocEntityDelta:
968
988
  arguments_delta = self.visit(node_intrinsic_function.arguments)
969
- before_condition_name = arguments_delta.before
970
- after_condition_name = arguments_delta.after
971
989
 
972
990
  def _delta_of_condition(name: str) -> PreprocEntityDelta:
973
991
  node_condition = self._get_node_condition_if_exists(condition_name=name)
974
992
  if is_nothing(node_condition):
975
993
  raise RuntimeError(f"Undefined condition '{name}'")
976
- delta = self.visit(node_condition)
977
- return delta
978
-
979
- before = Nothing
980
- if not is_nothing(before_condition_name):
981
- before_delta = _delta_of_condition(before_condition_name)
982
- before = before_delta.before
983
-
984
- after = Nothing
985
- if not is_nothing(after_condition_name):
986
- after_delta = _delta_of_condition(after_condition_name)
987
- after = after_delta.after
994
+ condition_delta = self.visit(node_condition)
995
+ return condition_delta
988
996
 
989
- return PreprocEntityDelta(before=before, after=after)
997
+ delta = self._cached_apply(
998
+ resolver=_delta_of_condition,
999
+ scope=node_intrinsic_function.scope,
1000
+ arguments_delta=arguments_delta,
1001
+ )
1002
+ return delta
990
1003
 
991
1004
  def visit_node_array(self, node_array: NodeArray) -> PreprocEntityDelta:
992
1005
  node_change_type = node_array.change_type
@@ -18,6 +18,7 @@ from localstack.services.cloudformation.engine.v2.change_set_model import (
18
18
  NodeParameter,
19
19
  NodeTransform,
20
20
  Nothing,
21
+ Scope,
21
22
  is_nothing,
22
23
  )
23
24
  from localstack.services.cloudformation.engine.v2.change_set_model_preproc import (
@@ -33,6 +34,8 @@ SERVERLESS_TRANSFORM = "AWS::Serverless-2016-10-31"
33
34
  EXTENSIONS_TRANSFORM = "AWS::LanguageExtensions"
34
35
  SECRETSMANAGER_TRANSFORM = "AWS::SecretsManager-2020-07-23"
35
36
 
37
+ _SCOPE_TRANSFORM_TEMPLATE_OUTCOME: Final[Scope] = Scope("TRANSFORM_TEMPLATE_OUTCOME")
38
+
36
39
 
37
40
  # TODO: evaluate the use of subtypes to represent and validate types of transforms
38
41
  class GlobalTransform:
@@ -190,35 +193,47 @@ class ChangeSetModelTransform(ChangeSetModelPreproc):
190
193
  return transformed_template
191
194
 
192
195
  def transform(self) -> tuple[dict, dict]:
193
- parameters_delta = self.visit_node_parameters(self._node_template.parameters)
196
+ self._setup_runtime_cache()
197
+
198
+ node_template = self._change_set.update_model.node_template
199
+
200
+ parameters_delta = self.visit_node_parameters(node_template.parameters)
194
201
  parameters_before = parameters_delta.before
195
202
  parameters_after = parameters_delta.after
196
203
 
197
204
  transform_delta: PreprocEntityDelta[list[GlobalTransform], list[GlobalTransform]] = (
198
- self.visit_node_transform(self._node_template.transform)
205
+ self.visit_node_transform(node_template.transform)
199
206
  )
200
207
  transform_before: Maybe[list[GlobalTransform]] = transform_delta.before
201
208
  transform_after: Maybe[list[GlobalTransform]] = transform_delta.after
202
209
 
203
210
  transformed_before_template = self._before_template
204
- if not is_nothing(transform_before) and not is_nothing(self._before_template):
205
- transformed_before_template = self._before_template
206
- for before_global_transform in transform_before:
207
- transformed_before_template = self._apply_global_transform(
208
- global_transform=before_global_transform,
209
- parameters=parameters_before,
210
- template=transformed_before_template,
211
- )
211
+ if transform_before and not is_nothing(self._before_template):
212
+ transformed_before_template = self._before_cache.get(_SCOPE_TRANSFORM_TEMPLATE_OUTCOME)
213
+ if not transformed_before_template:
214
+ transformed_before_template = self._before_template
215
+ for before_global_transform in transform_before:
216
+ transformed_before_template = self._apply_global_transform(
217
+ global_transform=before_global_transform,
218
+ parameters=parameters_before,
219
+ template=transformed_before_template,
220
+ )
221
+ self._before_cache[_SCOPE_TRANSFORM_TEMPLATE_OUTCOME] = transformed_before_template
212
222
 
213
223
  transformed_after_template = self._after_template
214
- if not is_nothing(transform_after) and not is_nothing(self._after_template):
215
- transformed_after_template = self._after_template
216
- for after_global_transform in transform_after:
217
- transformed_after_template = self._apply_global_transform(
218
- global_transform=after_global_transform,
219
- parameters=parameters_after,
220
- template=transformed_after_template,
221
- )
224
+ if transform_after and not is_nothing(self._after_template):
225
+ transformed_after_template = self._after_cache.get(_SCOPE_TRANSFORM_TEMPLATE_OUTCOME)
226
+ if not transformed_after_template:
227
+ transformed_after_template = self._after_template
228
+ for after_global_transform in transform_after:
229
+ transformed_after_template = self._apply_global_transform(
230
+ global_transform=after_global_transform,
231
+ parameters=parameters_after,
232
+ template=transformed_after_template,
233
+ )
234
+ self._after_cache[_SCOPE_TRANSFORM_TEMPLATE_OUTCOME] = transformed_after_template
235
+
236
+ self._save_runtime_cache()
222
237
 
223
238
  return transformed_before_template, transformed_after_template
224
239
 
@@ -24,7 +24,7 @@ from localstack.services.cloudformation.engine.entities import (
24
24
  StackIdentifier,
25
25
  )
26
26
  from localstack.services.cloudformation.engine.v2.change_set_model import (
27
- NodeTemplate,
27
+ UpdateModel,
28
28
  )
29
29
  from localstack.utils.aws import arns
30
30
  from localstack.utils.strings import long_uid, short_uid
@@ -204,7 +204,7 @@ class ChangeSet:
204
204
  change_set_name: str
205
205
  change_set_id: str
206
206
  change_set_type: ChangeSetType
207
- update_model: Optional[NodeTemplate]
207
+ update_model: Optional[UpdateModel]
208
208
  status: ChangeSetStatus
209
209
  execution_status: ExecutionStatus
210
210
  creation_time: datetime
@@ -231,7 +231,7 @@ class ChangeSet:
231
231
  region_name=self.stack.region_name,
232
232
  )
233
233
 
234
- def set_update_model(self, update_model: NodeTemplate) -> None:
234
+ def set_update_model(self, update_model: UpdateModel) -> None:
235
235
  self.update_model = update_model
236
236
 
237
237
  def set_change_set_status(self, status: ChangeSetStatus):
@@ -47,7 +47,7 @@ from localstack.services.cloudformation.engine import template_preparer
47
47
  from localstack.services.cloudformation.engine.v2.change_set_model import (
48
48
  ChangeSetModel,
49
49
  ChangeType,
50
- NodeTemplate,
50
+ UpdateModel,
51
51
  )
52
52
  from localstack.services.cloudformation.engine.v2.change_set_model_describer import (
53
53
  ChangeSetModelDescriber,
@@ -133,6 +133,7 @@ class CloudformationProviderV2(CloudformationProvider):
133
133
  after_template: Optional[dict],
134
134
  before_parameters: Optional[dict],
135
135
  after_parameters: Optional[dict],
136
+ previous_update_model: Optional[UpdateModel],
136
137
  ):
137
138
  # Create and preprocess the update graph for this template update.
138
139
  change_set_model = ChangeSetModel(
@@ -141,7 +142,12 @@ class CloudformationProviderV2(CloudformationProvider):
141
142
  before_parameters=before_parameters,
142
143
  after_parameters=after_parameters,
143
144
  )
144
- raw_update_model: NodeTemplate = change_set_model.get_update_model()
145
+ raw_update_model: UpdateModel = change_set_model.get_update_model()
146
+ # If there exists an update model which operated in the 'before' version of this change set,
147
+ # port the runtime values computed for the before version into this latest update model.
148
+ if previous_update_model:
149
+ raw_update_model.before_runtime_cache.clear()
150
+ raw_update_model.before_runtime_cache.update(previous_update_model.after_runtime_cache)
145
151
  change_set.set_update_model(raw_update_model)
146
152
 
147
153
  # Apply global transforms.
@@ -165,6 +171,12 @@ class CloudformationProviderV2(CloudformationProvider):
165
171
  after_parameters=after_parameters,
166
172
  )
167
173
  update_model = change_set_model.get_update_model()
174
+ # Bring the cache for the previous operations forward in the update graph for this version
175
+ # of the templates. This enables downstream update graph visitors to access runtime
176
+ # information computed whilst evaluating the previous version of this template, and during
177
+ # the transformations.
178
+ update_model.before_runtime_cache.update(raw_update_model.before_runtime_cache)
179
+ update_model.after_runtime_cache.update(raw_update_model.after_runtime_cache)
168
180
  change_set.set_update_model(update_model)
169
181
 
170
182
  @handler("CreateChangeSet", expand=False)
@@ -284,6 +296,15 @@ class CloudformationProviderV2(CloudformationProvider):
284
296
  before_template = stack.template
285
297
  after_template = structured_template
286
298
 
299
+ previous_update_model = None
300
+ try:
301
+ # FIXME: 'change_set_id' for 'stack' objects is dynamically attributed
302
+ if previous_change_set := find_change_set_v2(state, stack.change_set_id):
303
+ previous_update_model = previous_change_set.update_model
304
+ except Exception:
305
+ # No change set available on this stack.
306
+ pass
307
+
287
308
  # create change set for the stack and apply changes
288
309
  change_set = ChangeSet(stack, request, template=after_template)
289
310
  self._setup_change_set_model(
@@ -292,6 +313,7 @@ class CloudformationProviderV2(CloudformationProvider):
292
313
  after_template=after_template,
293
314
  before_parameters=before_parameters,
294
315
  after_parameters=after_parameters,
316
+ previous_update_model=previous_update_model,
295
317
  )
296
318
 
297
319
  change_set.set_change_set_status(ChangeSetStatus.CREATE_COMPLETE)
@@ -488,6 +510,7 @@ class CloudformationProviderV2(CloudformationProvider):
488
510
  after_template=after_template,
489
511
  before_parameters=None,
490
512
  after_parameters=after_parameters,
513
+ previous_update_model=None,
491
514
  )
492
515
 
493
516
  # deployment process
@@ -695,6 +718,10 @@ class CloudformationProviderV2(CloudformationProvider):
695
718
  before_template = stack.template
696
719
  after_template = structured_template
697
720
 
721
+ previous_update_model = None
722
+ if previous_change_set := find_change_set_v2(state, stack.change_set_id):
723
+ previous_update_model = previous_change_set.update_model
724
+
698
725
  change_set = ChangeSet(
699
726
  stack,
700
727
  {"ChangeSetName": f"cs-{stack_name}-create", "ChangeSetType": ChangeSetType.CREATE},
@@ -706,9 +733,13 @@ class CloudformationProviderV2(CloudformationProvider):
706
733
  after_template=after_template,
707
734
  before_parameters=before_parameters,
708
735
  after_parameters=after_parameters,
736
+ previous_update_model=previous_update_model,
709
737
  )
710
738
 
711
- if change_set.update_model.change_type == ChangeType.UNCHANGED:
739
+ # TODO: some changes are only detectable at runtime; consider using
740
+ # the ChangeSetModelDescriber, or a new custom visitors, to
741
+ # pick-up on runtime changes.
742
+ if change_set.update_model.node_template.change_type == ChangeType.UNCHANGED:
712
743
  raise ValidationError("No updates are to be performed.")
713
744
 
714
745
  stack.set_stack_status(StackStatus.UPDATE_IN_PROGRESS)
@@ -757,6 +788,10 @@ class CloudformationProviderV2(CloudformationProvider):
757
788
  stack.deletion_time = datetime.now(tz=timezone.utc)
758
789
  return
759
790
 
791
+ previous_update_model = None
792
+ if previous_change_set := find_change_set_v2(state, stack.change_set_id):
793
+ previous_update_model = previous_change_set.update_model
794
+
760
795
  # create a dummy change set
761
796
  change_set = ChangeSet(stack, {"ChangeSetName": f"delete-stack_{stack.stack_name}"}) # noqa
762
797
  self._setup_change_set_model(
@@ -765,6 +800,7 @@ class CloudformationProviderV2(CloudformationProvider):
765
800
  after_template=None,
766
801
  before_parameters=stack.resolved_parameters,
767
802
  after_parameters=None,
803
+ previous_update_model=previous_update_model,
768
804
  )
769
805
 
770
806
  change_set_executor = ChangeSetModelExecutor(change_set)
localstack/version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '4.5.1.dev62'
21
- __version_tuple__ = version_tuple = (4, 5, 1, 'dev62')
20
+ __version__ = version = '4.5.1.dev63'
21
+ __version_tuple__ = version_tuple = (4, 5, 1, 'dev63')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localstack-core
3
- Version: 4.5.1.dev62
3
+ Version: 4.5.1.dev63
4
4
  Summary: The core library and runtime of LocalStack
5
5
  Author-email: LocalStack Contributors <info@localstack.cloud>
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ localstack/deprecations.py,sha256=mNXTebZ8kSbQjFKz0LbT-g1Kdr0CE8bhEgZfHV3IX0s,15
4
4
  localstack/openapi.yaml,sha256=B803NmpwsxG8PHpHrdZYBrUYjnrRh7B_JX0XuNynuFs,30237
5
5
  localstack/plugins.py,sha256=BIJC9dlo0WbP7lLKkCiGtd_2q5oeqiHZohvoRTcejXM,2457
6
6
  localstack/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- localstack/version.py,sha256=QYOE4FT7nL_3BDW_DCEMrqvbI7DEnRFQHk6LWCl1QgQ,526
7
+ localstack/version.py,sha256=LTxjfcRuowkt-GVcLE40v8qA0zkkDM-GYlAiR90qrJE,526
8
8
  localstack/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  localstack/aws/accounts.py,sha256=102zpGowOxo0S6UGMpfjw14QW7WCLVAGsnFK5xFMLoo,3043
10
10
  localstack/aws/app.py,sha256=n9bJCfJRuMz_gLGAH430c3bIQXgUXeWO5NPfcdL2MV8,5145
@@ -311,11 +311,11 @@ localstack/services/cloudformation/engine/types.py,sha256=YIhmTrO__obIviYvzzCovK
311
311
  localstack/services/cloudformation/engine/validations.py,sha256=brq7s8O8exA5kvnfzR9ulOtQ7i4konrWQs07-0h_ByE,2847
312
312
  localstack/services/cloudformation/engine/yaml_parser.py,sha256=LQpAVq9Syze9jXUGen9Mz8SjosBuodpV5XvsCSn9bDg,2164
313
313
  localstack/services/cloudformation/engine/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
314
- localstack/services/cloudformation/engine/v2/change_set_model.py,sha256=Jt_ersgkciAIWhGde9qm0MllIRA4K3vBZE1V04RJ6XQ,54613
315
- localstack/services/cloudformation/engine/v2/change_set_model_describer.py,sha256=J2OibRDuVXu-rnLxHmxtjqOD4Q489F9An_6-fkTTAm8,8057
316
- localstack/services/cloudformation/engine/v2/change_set_model_executor.py,sha256=kykv7hPUOvzeaUPs1NA1FHQyUyKcrqRcVK6C-R-sb2E,19943
317
- localstack/services/cloudformation/engine/v2/change_set_model_preproc.py,sha256=lwSdkqF05IkafWGXVLuZ37dugBGB7_hNpX4e-xtZShY,49709
318
- localstack/services/cloudformation/engine/v2/change_set_model_transform.py,sha256=TLQmK2WE0NzjSn0-0h0WfOZEwH1ULAJD34eQLEG3F7w,10655
314
+ localstack/services/cloudformation/engine/v2/change_set_model.py,sha256=9JK6YySuJehfP_IJTwrwRfQRaPMmyh3qH3RFJ1GsnOA,55108
315
+ localstack/services/cloudformation/engine/v2/change_set_model_describer.py,sha256=Y1mvD57gBCSQ4VjVTwebDGeaDv9_a8dNCqOEZq5u5Fg,9075
316
+ localstack/services/cloudformation/engine/v2/change_set_model_executor.py,sha256=7uKu7GLARY15s3J5_HCUti4K_KPMz4RqdunRpVn_n-A,19984
317
+ localstack/services/cloudformation/engine/v2/change_set_model_preproc.py,sha256=zdHDjYUJBo53pdgida0TPsyVjELu4MifLpQFvFYtVAE,50713
318
+ localstack/services/cloudformation/engine/v2/change_set_model_transform.py,sha256=P3iJhAJd2w2E4WevqifAgdBs8tPqk5BuSJYxXs5HpOY,11398
319
319
  localstack/services/cloudformation/engine/v2/change_set_model_visitor.py,sha256=JERT55YkPF-UHzG-sk958mpyEq2Gxz4smY8xwDbhIRQ,7666
320
320
  localstack/services/cloudformation/models/__init__.py,sha256=da1PTClDMl-IBkrSvq6JC1lnS-K_BASzCvxVhNxN5Ls,13
321
321
  localstack/services/cloudformation/resource_providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -334,8 +334,8 @@ localstack/services/cloudformation/resource_providers/aws_cloudformation_waitcon
334
334
  localstack/services/cloudformation/scaffolding/__main__.py,sha256=zjedOdqvnfN99WzQ43gxtGZxLDitSnbFGA-zpWbyMQ0,30960
335
335
  localstack/services/cloudformation/scaffolding/propgen.py,sha256=9YsSCkDegcU_Yp8Sfw8eNV26N5ibOlLC6Hg6lxPeBBM,7949
336
336
  localstack/services/cloudformation/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
337
- localstack/services/cloudformation/v2/entities.py,sha256=2GK1Fi1Mi3WwLm1j4F5CjMk4IXotyhwfA2JwTSv6I38,8034
338
- localstack/services/cloudformation/v2/provider.py,sha256=A3ZUaVw_Xj6zB_LEKoFVlQcL1vZRwzCE3pcwn5zDFVw,33103
337
+ localstack/services/cloudformation/v2/entities.py,sha256=34Xb2ZoLusyZB0WkSJfMhCEydyY7GpDlxOFqA86s6o4,8031
338
+ localstack/services/cloudformation/v2/provider.py,sha256=QN9T_fIMi7zptVlR6FJ5RTLP7VtL1_uK-qQnaasO3S0,35226
339
339
  localstack/services/cloudformation/v2/utils.py,sha256=xy4Lcp4X8XGJ0OKfnsE7pnfMcFrtIH0Chw35qwjhZuw,148
340
340
  localstack/services/cloudwatch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
341
341
  localstack/services/cloudwatch/alarm_scheduler.py,sha256=XFllg0gI_WNV7cNxOcgXifzmbNA07OPpuEUuf37keP4,15663
@@ -1286,13 +1286,13 @@ localstack/utils/server/tcp_proxy.py,sha256=rR6d5jR0ozDvIlpHiqW0cfyY9a2fRGdOzyA8
1286
1286
  localstack/utils/xray/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1287
1287
  localstack/utils/xray/trace_header.py,sha256=ahXk9eonq7LpeENwlqUEPj3jDOCiVRixhntQuxNor-Q,6209
1288
1288
  localstack/utils/xray/traceid.py,sha256=SQSsMV2rhbTNK6ceIoozZYuGU7Fg687EXcgqxoDl1Fw,1106
1289
- localstack_core-4.5.1.dev62.data/scripts/localstack,sha256=WyL11vp5CkuP79iIR-L8XT7Cj8nvmxX7XRAgxhbmXNE,529
1290
- localstack_core-4.5.1.dev62.data/scripts/localstack-supervisor,sha256=nm1Il2d6ASyOB6Vo4CRHd90w7TK9FdRl9VPp0NN6hUk,6378
1291
- localstack_core-4.5.1.dev62.data/scripts/localstack.bat,sha256=tlzZTXtveHkMX_s_fa7VDfvdNdS8iVpEz2ER3uk9B_c,29
1292
- localstack_core-4.5.1.dev62.dist-info/licenses/LICENSE.txt,sha256=3PC-9Z69UsNARuQ980gNR_JsLx8uvMjdG6C7cc4LBYs,606
1293
- localstack_core-4.5.1.dev62.dist-info/METADATA,sha256=px0ddl0bIlz3PL9YBogwx3hRCY_zupu-ZIFlpwY7G0o,5539
1294
- localstack_core-4.5.1.dev62.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1295
- localstack_core-4.5.1.dev62.dist-info/entry_points.txt,sha256=-GFtw80qM_1GQIDUcyqXojJvnqvP_8lK1Vc-M9ShaJE,20668
1296
- localstack_core-4.5.1.dev62.dist-info/plux.json,sha256=2vu1SPou3jivuZuj32fzUyyCZeWitMhsP7Hba7i8dZ0,20891
1297
- localstack_core-4.5.1.dev62.dist-info/top_level.txt,sha256=3sqmK2lGac8nCy8nwsbS5SpIY_izmtWtgaTFKHYVHbI,11
1298
- localstack_core-4.5.1.dev62.dist-info/RECORD,,
1289
+ localstack_core-4.5.1.dev63.data/scripts/localstack,sha256=WyL11vp5CkuP79iIR-L8XT7Cj8nvmxX7XRAgxhbmXNE,529
1290
+ localstack_core-4.5.1.dev63.data/scripts/localstack-supervisor,sha256=nm1Il2d6ASyOB6Vo4CRHd90w7TK9FdRl9VPp0NN6hUk,6378
1291
+ localstack_core-4.5.1.dev63.data/scripts/localstack.bat,sha256=tlzZTXtveHkMX_s_fa7VDfvdNdS8iVpEz2ER3uk9B_c,29
1292
+ localstack_core-4.5.1.dev63.dist-info/licenses/LICENSE.txt,sha256=3PC-9Z69UsNARuQ980gNR_JsLx8uvMjdG6C7cc4LBYs,606
1293
+ localstack_core-4.5.1.dev63.dist-info/METADATA,sha256=nd0S0X_zyxnGAkuGycaqLBX0J5AnnvPIEElGAAlzYzU,5539
1294
+ localstack_core-4.5.1.dev63.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1295
+ localstack_core-4.5.1.dev63.dist-info/entry_points.txt,sha256=-GFtw80qM_1GQIDUcyqXojJvnqvP_8lK1Vc-M9ShaJE,20668
1296
+ localstack_core-4.5.1.dev63.dist-info/plux.json,sha256=SrBYCxHG_jbVHlfE9Kl6TsUmFfVQEREHJRBd3jECTqQ,20891
1297
+ localstack_core-4.5.1.dev63.dist-info/top_level.txt,sha256=3sqmK2lGac8nCy8nwsbS5SpIY_izmtWtgaTFKHYVHbI,11
1298
+ localstack_core-4.5.1.dev63.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ {"localstack.cloudformation.resource_providers": ["AWS::IAM::Group=localstack.services.iam.resource_providers.aws_iam_group_plugin:IAMGroupProviderPlugin", "AWS::ApiGateway::Deployment=localstack.services.apigateway.resource_providers.aws_apigateway_deployment_plugin:ApiGatewayDeploymentProviderPlugin", "AWS::Route53::HealthCheck=localstack.services.route53.resource_providers.aws_route53_healthcheck_plugin:Route53HealthCheckProviderPlugin", "AWS::EC2::RouteTable=localstack.services.ec2.resource_providers.aws_ec2_routetable_plugin:EC2RouteTableProviderPlugin", "AWS::IAM::ServerCertificate=localstack.services.iam.resource_providers.aws_iam_servercertificate_plugin:IAMServerCertificateProviderPlugin", "AWS::ApiGateway::RestApi=localstack.services.apigateway.resource_providers.aws_apigateway_restapi_plugin:ApiGatewayRestApiProviderPlugin", "AWS::IAM::AccessKey=localstack.services.iam.resource_providers.aws_iam_accesskey_plugin:IAMAccessKeyProviderPlugin", "AWS::EC2::KeyPair=localstack.services.ec2.resource_providers.aws_ec2_keypair_plugin:EC2KeyPairProviderPlugin", "AWS::EC2::TransitGatewayAttachment=localstack.services.ec2.resource_providers.aws_ec2_transitgatewayattachment_plugin:EC2TransitGatewayAttachmentProviderPlugin", "AWS::Lambda::Permission=localstack.services.lambda_.resource_providers.aws_lambda_permission_plugin:LambdaPermissionProviderPlugin", "AWS::S3::BucketPolicy=localstack.services.s3.resource_providers.aws_s3_bucketpolicy_plugin:S3BucketPolicyProviderPlugin", "AWS::SSM::MaintenanceWindowTask=localstack.services.ssm.resource_providers.aws_ssm_maintenancewindowtask_plugin:SSMMaintenanceWindowTaskProviderPlugin", "AWS::Kinesis::Stream=localstack.services.kinesis.resource_providers.aws_kinesis_stream_plugin:KinesisStreamProviderPlugin", "AWS::Kinesis::StreamConsumer=localstack.services.kinesis.resource_providers.aws_kinesis_streamconsumer_plugin:KinesisStreamConsumerProviderPlugin", "AWS::Lambda::Function=localstack.services.lambda_.resource_providers.aws_lambda_function_plugin:LambdaFunctionProviderPlugin", "AWS::DynamoDB::GlobalTable=localstack.services.dynamodb.resource_providers.aws_dynamodb_globaltable_plugin:DynamoDBGlobalTableProviderPlugin", "AWS::SecretsManager::SecretTargetAttachment=localstack.services.secretsmanager.resource_providers.aws_secretsmanager_secrettargetattachment_plugin:SecretsManagerSecretTargetAttachmentProviderPlugin", "AWS::Lambda::Url=localstack.services.lambda_.resource_providers.aws_lambda_url_plugin:LambdaUrlProviderPlugin", "AWS::SES::EmailIdentity=localstack.services.ses.resource_providers.aws_ses_emailidentity_plugin:SESEmailIdentityProviderPlugin", "AWS::Scheduler::Schedule=localstack.services.scheduler.resource_providers.aws_scheduler_schedule_plugin:SchedulerScheduleProviderPlugin", "AWS::Events::Rule=localstack.services.events.resource_providers.aws_events_rule_plugin:EventsRuleProviderPlugin", "AWS::StepFunctions::Activity=localstack.services.stepfunctions.resource_providers.aws_stepfunctions_activity_plugin:StepFunctionsActivityProviderPlugin", "AWS::EC2::Instance=localstack.services.ec2.resource_providers.aws_ec2_instance_plugin:EC2InstanceProviderPlugin", "AWS::ApiGateway::DomainName=localstack.services.apigateway.resource_providers.aws_apigateway_domainname_plugin:ApiGatewayDomainNameProviderPlugin", "AWS::CloudFormation::WaitConditionHandle=localstack.services.cloudformation.resource_providers.aws_cloudformation_waitconditionhandle_plugin:CloudFormationWaitConditionHandleProviderPlugin", "AWS::ApiGateway::Resource=localstack.services.apigateway.resource_providers.aws_apigateway_resource_plugin:ApiGatewayResourceProviderPlugin", "AWS::CDK::Metadata=localstack.services.cdk.resource_providers.cdk_metadata_plugin:LambdaAliasProviderPlugin", "AWS::EC2::VPCEndpoint=localstack.services.ec2.resource_providers.aws_ec2_vpcendpoint_plugin:EC2VPCEndpointProviderPlugin", "AWS::EC2::NetworkAcl=localstack.services.ec2.resource_providers.aws_ec2_networkacl_plugin:EC2NetworkAclProviderPlugin", "AWS::Lambda::LayerVersionPermission=localstack.services.lambda_.resource_providers.aws_lambda_layerversionpermission_plugin:LambdaLayerVersionPermissionProviderPlugin", "AWS::EC2::Route=localstack.services.ec2.resource_providers.aws_ec2_route_plugin:EC2RouteProviderPlugin", "AWS::Lambda::EventSourceMapping=localstack.services.lambda_.resource_providers.aws_lambda_eventsourcemapping_plugin:LambdaEventSourceMappingProviderPlugin", "AWS::Events::EventBusPolicy=localstack.services.events.resource_providers.aws_events_eventbuspolicy_plugin:EventsEventBusPolicyProviderPlugin", "AWS::Lambda::Version=localstack.services.lambda_.resource_providers.aws_lambda_version_plugin:LambdaVersionProviderPlugin", "AWS::EC2::DHCPOptions=localstack.services.ec2.resource_providers.aws_ec2_dhcpoptions_plugin:EC2DHCPOptionsProviderPlugin", "AWS::Logs::LogStream=localstack.services.logs.resource_providers.aws_logs_logstream_plugin:LogsLogStreamProviderPlugin", "AWS::SecretsManager::ResourcePolicy=localstack.services.secretsmanager.resource_providers.aws_secretsmanager_resourcepolicy_plugin:SecretsManagerResourcePolicyProviderPlugin", "AWS::ECR::Repository=localstack.services.ecr.resource_providers.aws_ecr_repository_plugin:ECRRepositoryProviderPlugin", "AWS::ApiGateway::Method=localstack.services.apigateway.resource_providers.aws_apigateway_method_plugin:ApiGatewayMethodProviderPlugin", "AWS::SNS::Subscription=localstack.services.sns.resource_providers.aws_sns_subscription_plugin:SNSSubscriptionProviderPlugin", "AWS::ApiGateway::UsagePlanKey=localstack.services.apigateway.resource_providers.aws_apigateway_usageplankey_plugin:ApiGatewayUsagePlanKeyProviderPlugin", "AWS::Elasticsearch::Domain=localstack.services.opensearch.resource_providers.aws_elasticsearch_domain_plugin:ElasticsearchDomainProviderPlugin", "AWS::EC2::PrefixList=localstack.services.ec2.resource_providers.aws_ec2_prefixlist_plugin:EC2PrefixListProviderPlugin", "AWS::SQS::QueuePolicy=localstack.services.sqs.resource_providers.aws_sqs_queuepolicy_plugin:SQSQueuePolicyProviderPlugin", "AWS::ApiGateway::ApiKey=localstack.services.apigateway.resource_providers.aws_apigateway_apikey_plugin:ApiGatewayApiKeyProviderPlugin", "AWS::Lambda::Alias=localstack.services.lambda_.resource_providers.lambda_alias_plugin:LambdaAliasProviderPlugin", "AWS::Logs::SubscriptionFilter=localstack.services.logs.resource_providers.aws_logs_subscriptionfilter_plugin:LogsSubscriptionFilterProviderPlugin", "AWS::CertificateManager::Certificate=localstack.services.certificatemanager.resource_providers.aws_certificatemanager_certificate_plugin:CertificateManagerCertificateProviderPlugin", "AWS::EC2::Subnet=localstack.services.ec2.resource_providers.aws_ec2_subnet_plugin:EC2SubnetProviderPlugin", "AWS::IAM::ManagedPolicy=localstack.services.iam.resource_providers.aws_iam_managedpolicy_plugin:IAMManagedPolicyProviderPlugin", "AWS::CloudFormation::Macro=localstack.services.cloudformation.resource_providers.aws_cloudformation_macro_plugin:CloudFormationMacroProviderPlugin", "AWS::ApiGateway::RequestValidator=localstack.services.apigateway.resource_providers.aws_apigateway_requestvalidator_plugin:ApiGatewayRequestValidatorProviderPlugin", "AWS::IAM::Policy=localstack.services.iam.resource_providers.aws_iam_policy_plugin:IAMPolicyProviderPlugin", "AWS::Lambda::CodeSigningConfig=localstack.services.lambda_.resource_providers.aws_lambda_codesigningconfig_plugin:LambdaCodeSigningConfigProviderPlugin", "AWS::ApiGateway::BasePathMapping=localstack.services.apigateway.resource_providers.aws_apigateway_basepathmapping_plugin:ApiGatewayBasePathMappingProviderPlugin", "AWS::CloudFormation::WaitCondition=localstack.services.cloudformation.resource_providers.aws_cloudformation_waitcondition_plugin:CloudFormationWaitConditionProviderPlugin", "AWS::Route53::RecordSet=localstack.services.route53.resource_providers.aws_route53_recordset_plugin:Route53RecordSetProviderPlugin", "AWS::SSM::PatchBaseline=localstack.services.ssm.resource_providers.aws_ssm_patchbaseline_plugin:SSMPatchBaselineProviderPlugin", "AWS::KMS::Alias=localstack.services.kms.resource_providers.aws_kms_alias_plugin:KMSAliasProviderPlugin", "AWS::ApiGateway::Model=localstack.services.apigateway.resource_providers.aws_apigateway_model_plugin:ApiGatewayModelProviderPlugin", "AWS::S3::Bucket=localstack.services.s3.resource_providers.aws_s3_bucket_plugin:S3BucketProviderPlugin", "AWS::SQS::Queue=localstack.services.sqs.resource_providers.aws_sqs_queue_plugin:SQSQueueProviderPlugin", "AWS::IAM::ServiceLinkedRole=localstack.services.iam.resource_providers.aws_iam_servicelinkedrole_plugin:IAMServiceLinkedRoleProviderPlugin", "AWS::ApiGateway::Stage=localstack.services.apigateway.resource_providers.aws_apigateway_stage_plugin:ApiGatewayStageProviderPlugin", "AWS::Events::EventBus=localstack.services.events.resource_providers.aws_events_eventbus_plugin:EventsEventBusProviderPlugin", "AWS::SNS::Topic=localstack.services.sns.resource_providers.aws_sns_topic_plugin:SNSTopicProviderPlugin", "AWS::Redshift::Cluster=localstack.services.redshift.resource_providers.aws_redshift_cluster_plugin:RedshiftClusterProviderPlugin", "AWS::EC2::VPCGatewayAttachment=localstack.services.ec2.resource_providers.aws_ec2_vpcgatewayattachment_plugin:EC2VPCGatewayAttachmentProviderPlugin", "AWS::KMS::Key=localstack.services.kms.resource_providers.aws_kms_key_plugin:KMSKeyProviderPlugin", "AWS::OpenSearchService::Domain=localstack.services.opensearch.resource_providers.aws_opensearchservice_domain_plugin:OpenSearchServiceDomainProviderPlugin", "AWS::Events::Connection=localstack.services.events.resource_providers.aws_events_connection_plugin:EventsConnectionProviderPlugin", "AWS::ApiGateway::GatewayResponse=localstack.services.apigateway.resource_providers.aws_apigateway_gatewayresponse_plugin:ApiGatewayGatewayResponseProviderPlugin", "AWS::EC2::NatGateway=localstack.services.ec2.resource_providers.aws_ec2_natgateway_plugin:EC2NatGatewayProviderPlugin", "AWS::CloudWatch::CompositeAlarm=localstack.services.cloudwatch.resource_providers.aws_cloudwatch_compositealarm_plugin:CloudWatchCompositeAlarmProviderPlugin", "AWS::SecretsManager::RotationSchedule=localstack.services.secretsmanager.resource_providers.aws_secretsmanager_rotationschedule_plugin:SecretsManagerRotationScheduleProviderPlugin", "AWS::Lambda::LayerVersion=localstack.services.lambda_.resource_providers.aws_lambda_layerversion_plugin:LambdaLayerVersionProviderPlugin", "AWS::SSM::MaintenanceWindow=localstack.services.ssm.resource_providers.aws_ssm_maintenancewindow_plugin:SSMMaintenanceWindowProviderPlugin", "AWS::SNS::TopicPolicy=localstack.services.sns.resource_providers.aws_sns_topicpolicy_plugin:SNSTopicPolicyProviderPlugin", "AWS::IAM::Role=localstack.services.iam.resource_providers.aws_iam_role_plugin:IAMRoleProviderPlugin", "AWS::KinesisFirehose::DeliveryStream=localstack.services.kinesisfirehose.resource_providers.aws_kinesisfirehose_deliverystream_plugin:KinesisFirehoseDeliveryStreamProviderPlugin", "AWS::Lambda::EventInvokeConfig=localstack.services.lambda_.resource_providers.aws_lambda_eventinvokeconfig_plugin:LambdaEventInvokeConfigProviderPlugin", "AWS::CloudWatch::Alarm=localstack.services.cloudwatch.resource_providers.aws_cloudwatch_alarm_plugin:CloudWatchAlarmProviderPlugin", "AWS::EC2::TransitGateway=localstack.services.ec2.resource_providers.aws_ec2_transitgateway_plugin:EC2TransitGatewayProviderPlugin", "AWS::ApiGateway::UsagePlan=localstack.services.apigateway.resource_providers.aws_apigateway_usageplan_plugin:ApiGatewayUsagePlanProviderPlugin", "AWS::StepFunctions::StateMachine=localstack.services.stepfunctions.resource_providers.aws_stepfunctions_statemachine_plugin:StepFunctionsStateMachineProviderPlugin", "AWS::ApiGateway::Account=localstack.services.apigateway.resource_providers.aws_apigateway_account_plugin:ApiGatewayAccountProviderPlugin", "AWS::SSM::MaintenanceWindowTarget=localstack.services.ssm.resource_providers.aws_ssm_maintenancewindowtarget_plugin:SSMMaintenanceWindowTargetProviderPlugin", "AWS::EC2::InternetGateway=localstack.services.ec2.resource_providers.aws_ec2_internetgateway_plugin:EC2InternetGatewayProviderPlugin", "AWS::IAM::InstanceProfile=localstack.services.iam.resource_providers.aws_iam_instanceprofile_plugin:IAMInstanceProfileProviderPlugin", "AWS::CloudFormation::Stack=localstack.services.cloudformation.resource_providers.aws_cloudformation_stack_plugin:CloudFormationStackProviderPlugin", "AWS::SecretsManager::Secret=localstack.services.secretsmanager.resource_providers.aws_secretsmanager_secret_plugin:SecretsManagerSecretProviderPlugin", "AWS::SSM::Parameter=localstack.services.ssm.resource_providers.aws_ssm_parameter_plugin:SSMParameterProviderPlugin", "AWS::EC2::VPC=localstack.services.ec2.resource_providers.aws_ec2_vpc_plugin:EC2VPCProviderPlugin", "AWS::Logs::LogGroup=localstack.services.logs.resource_providers.aws_logs_loggroup_plugin:LogsLogGroupProviderPlugin", "AWS::Scheduler::ScheduleGroup=localstack.services.scheduler.resource_providers.aws_scheduler_schedulegroup_plugin:SchedulerScheduleGroupProviderPlugin", "AWS::ResourceGroups::Group=localstack.services.resource_groups.resource_providers.aws_resourcegroups_group_plugin:ResourceGroupsGroupProviderPlugin", "AWS::Events::ApiDestination=localstack.services.events.resource_providers.aws_events_apidestination_plugin:EventsApiDestinationProviderPlugin", "AWS::DynamoDB::Table=localstack.services.dynamodb.resource_providers.aws_dynamodb_table_plugin:DynamoDBTableProviderPlugin", "AWS::EC2::SecurityGroup=localstack.services.ec2.resource_providers.aws_ec2_securitygroup_plugin:EC2SecurityGroupProviderPlugin", "AWS::IAM::User=localstack.services.iam.resource_providers.aws_iam_user_plugin:IAMUserProviderPlugin", "AWS::EC2::SubnetRouteTableAssociation=localstack.services.ec2.resource_providers.aws_ec2_subnetroutetableassociation_plugin:EC2SubnetRouteTableAssociationProviderPlugin"], "localstack.packages": ["elasticsearch/community=localstack.services.es.plugins:elasticsearch_package", "vosk/community=localstack.services.transcribe.plugins:vosk_package", "dynamodb-local/community=localstack.services.dynamodb.plugins:dynamodb_local_package", "ffmpeg/community=localstack.packages.plugins:ffmpeg_package", "java/community=localstack.packages.plugins:java_package", "terraform/community=localstack.packages.plugins:terraform_package", "lambda-java-libs/community=localstack.services.lambda_.plugins:lambda_java_libs", "lambda-runtime/community=localstack.services.lambda_.plugins:lambda_runtime_package", "opensearch/community=localstack.services.opensearch.plugins:opensearch_package", "kinesis-mock/community=localstack.services.kinesis.plugins:kinesismock_package", "jpype-jsonata/community=localstack.services.stepfunctions.plugins:jpype_jsonata_package"], "localstack.hooks.on_infra_start": ["setup_dns_configuration_on_host=localstack.dns.plugins:setup_dns_configuration_on_host", "start_dns_server=localstack.dns.plugins:start_dns_server", "delete_cached_certificate=localstack.plugins:delete_cached_certificate", "deprecation_warnings=localstack.plugins:deprecation_warnings", "_run_init_scripts_on_start=localstack.runtime.init:_run_init_scripts_on_start", "_publish_config_as_analytics_event=localstack.runtime.analytics:_publish_config_as_analytics_event", "_publish_container_info=localstack.runtime.analytics:_publish_container_info", "eager_load_services=localstack.services.plugins:eager_load_services", "apply_aws_runtime_patches=localstack.aws.patches:apply_aws_runtime_patches", "register_custom_endpoints=localstack.services.lambda_.plugins:register_custom_endpoints", "validate_configuration=localstack.services.lambda_.plugins:validate_configuration", "apply_runtime_patches=localstack.runtime.patches:apply_runtime_patches", "_patch_botocore_endpoint_in_memory=localstack.aws.client:_patch_botocore_endpoint_in_memory", "_patch_botocore_json_parser=localstack.aws.client:_patch_botocore_json_parser", "_patch_cbor2=localstack.aws.client:_patch_cbor2", "init_response_mutation_handler=localstack.aws.handlers.response:init_response_mutation_handler", "register_cloudformation_deploy_ui=localstack.services.cloudformation.plugins:register_cloudformation_deploy_ui", "register_swagger_endpoints=localstack.http.resources.swagger.plugins:register_swagger_endpoints", "conditionally_enable_debugger=localstack.dev.debugger.plugins:conditionally_enable_debugger"], "localstack.hooks.on_infra_shutdown": ["stop_server=localstack.dns.plugins:stop_server", "_run_init_scripts_on_shutdown=localstack.runtime.init:_run_init_scripts_on_shutdown", "publish_metrics=localstack.utils.analytics.metrics.publisher:publish_metrics", "remove_custom_endpoints=localstack.services.lambda_.plugins:remove_custom_endpoints", "run_on_after_service_shutdown_handlers=localstack.runtime.shutdown:run_on_after_service_shutdown_handlers", "run_shutdown_handlers=localstack.runtime.shutdown:run_shutdown_handlers", "shutdown_services=localstack.runtime.shutdown:shutdown_services"], "localstack.openapi.spec": ["localstack=localstack.plugins:CoreOASPlugin"], "localstack.init.runner": ["py=localstack.runtime.init:PythonScriptRunner", "sh=localstack.runtime.init:ShellScriptRunner"], "localstack.hooks.on_infra_ready": ["_run_init_scripts_on_ready=localstack.runtime.init:_run_init_scripts_on_ready"], "localstack.aws.provider": ["acm:default=localstack.services.providers:acm", "apigateway:default=localstack.services.providers:apigateway", "apigateway:legacy=localstack.services.providers:apigateway_legacy", "apigateway:next_gen=localstack.services.providers:apigateway_next_gen", "config:default=localstack.services.providers:awsconfig", "cloudformation:default=localstack.services.providers:cloudformation", "cloudformation:engine-v2=localstack.services.providers:cloudformation_v2", "cloudwatch:default=localstack.services.providers:cloudwatch", "cloudwatch:v1=localstack.services.providers:cloudwatch_v1", "cloudwatch:v2=localstack.services.providers:cloudwatch_v2", "dynamodb:default=localstack.services.providers:dynamodb", "dynamodb:v2=localstack.services.providers:dynamodb_v2", "dynamodbstreams:default=localstack.services.providers:dynamodbstreams", "dynamodbstreams:v2=localstack.services.providers:dynamodbstreams_v2", "ec2:default=localstack.services.providers:ec2", "es:default=localstack.services.providers:es", "events:default=localstack.services.providers:events", "events:legacy=localstack.services.providers:events_legacy", "events:v1=localstack.services.providers:events_v1", "events:v2=localstack.services.providers:events_v2", "firehose:default=localstack.services.providers:firehose", "iam:default=localstack.services.providers:iam", "kinesis:default=localstack.services.providers:kinesis", "kms:default=localstack.services.providers:kms", "lambda:default=localstack.services.providers:lambda_", "lambda:asf=localstack.services.providers:lambda_asf", "lambda:v2=localstack.services.providers:lambda_v2", "logs:default=localstack.services.providers:logs", "opensearch:default=localstack.services.providers:opensearch", "redshift:default=localstack.services.providers:redshift", "resource-groups:default=localstack.services.providers:resource_groups", "resourcegroupstaggingapi:default=localstack.services.providers:resourcegroupstaggingapi", "route53:default=localstack.services.providers:route53", "route53resolver:default=localstack.services.providers:route53resolver", "s3:default=localstack.services.providers:s3", "s3control:default=localstack.services.providers:s3control", "scheduler:default=localstack.services.providers:scheduler", "secretsmanager:default=localstack.services.providers:secretsmanager", "ses:default=localstack.services.providers:ses", "sns:default=localstack.services.providers:sns", "sqs:default=localstack.services.providers:sqs", "ssm:default=localstack.services.providers:ssm", "stepfunctions:default=localstack.services.providers:stepfunctions", "stepfunctions:v2=localstack.services.providers:stepfunctions_v2", "sts:default=localstack.services.providers:sts", "support:default=localstack.services.providers:support", "swf:default=localstack.services.providers:swf", "transcribe:default=localstack.services.providers:transcribe"], "localstack.runtime.server": ["hypercorn=localstack.runtime.server.plugins:HypercornRuntimeServerPlugin", "twisted=localstack.runtime.server.plugins:TwistedRuntimeServerPlugin"], "localstack.lambda.runtime_executor": ["docker=localstack.services.lambda_.invocation.plugins:DockerRuntimeExecutorPlugin"], "localstack.runtime.components": ["aws=localstack.aws.components:AwsComponents"], "localstack.hooks.configure_localstack_container": ["_mount_machine_file=localstack.utils.analytics.metadata:_mount_machine_file"], "localstack.hooks.prepare_host": ["prepare_host_machine_id=localstack.utils.analytics.metadata:prepare_host_machine_id"]}
@@ -1 +0,0 @@
1
- {"localstack.cloudformation.resource_providers": ["AWS::EC2::VPCGatewayAttachment=localstack.services.ec2.resource_providers.aws_ec2_vpcgatewayattachment_plugin:EC2VPCGatewayAttachmentProviderPlugin", "AWS::EC2::NetworkAcl=localstack.services.ec2.resource_providers.aws_ec2_networkacl_plugin:EC2NetworkAclProviderPlugin", "AWS::SQS::Queue=localstack.services.sqs.resource_providers.aws_sqs_queue_plugin:SQSQueueProviderPlugin", "AWS::CloudWatch::CompositeAlarm=localstack.services.cloudwatch.resource_providers.aws_cloudwatch_compositealarm_plugin:CloudWatchCompositeAlarmProviderPlugin", "AWS::Lambda::Permission=localstack.services.lambda_.resource_providers.aws_lambda_permission_plugin:LambdaPermissionProviderPlugin", "AWS::ECR::Repository=localstack.services.ecr.resource_providers.aws_ecr_repository_plugin:ECRRepositoryProviderPlugin", "AWS::Elasticsearch::Domain=localstack.services.opensearch.resource_providers.aws_elasticsearch_domain_plugin:ElasticsearchDomainProviderPlugin", "AWS::SSM::MaintenanceWindowTarget=localstack.services.ssm.resource_providers.aws_ssm_maintenancewindowtarget_plugin:SSMMaintenanceWindowTargetProviderPlugin", "AWS::IAM::InstanceProfile=localstack.services.iam.resource_providers.aws_iam_instanceprofile_plugin:IAMInstanceProfileProviderPlugin", "AWS::ApiGateway::ApiKey=localstack.services.apigateway.resource_providers.aws_apigateway_apikey_plugin:ApiGatewayApiKeyProviderPlugin", "AWS::DynamoDB::GlobalTable=localstack.services.dynamodb.resource_providers.aws_dynamodb_globaltable_plugin:DynamoDBGlobalTableProviderPlugin", "AWS::IAM::Role=localstack.services.iam.resource_providers.aws_iam_role_plugin:IAMRoleProviderPlugin", "AWS::Kinesis::Stream=localstack.services.kinesis.resource_providers.aws_kinesis_stream_plugin:KinesisStreamProviderPlugin", "AWS::SecretsManager::Secret=localstack.services.secretsmanager.resource_providers.aws_secretsmanager_secret_plugin:SecretsManagerSecretProviderPlugin", "AWS::StepFunctions::StateMachine=localstack.services.stepfunctions.resource_providers.aws_stepfunctions_statemachine_plugin:StepFunctionsStateMachineProviderPlugin", "AWS::Lambda::LayerVersion=localstack.services.lambda_.resource_providers.aws_lambda_layerversion_plugin:LambdaLayerVersionProviderPlugin", "AWS::OpenSearchService::Domain=localstack.services.opensearch.resource_providers.aws_opensearchservice_domain_plugin:OpenSearchServiceDomainProviderPlugin", "AWS::ApiGateway::UsagePlan=localstack.services.apigateway.resource_providers.aws_apigateway_usageplan_plugin:ApiGatewayUsagePlanProviderPlugin", "AWS::SNS::TopicPolicy=localstack.services.sns.resource_providers.aws_sns_topicpolicy_plugin:SNSTopicPolicyProviderPlugin", "AWS::ApiGateway::DomainName=localstack.services.apigateway.resource_providers.aws_apigateway_domainname_plugin:ApiGatewayDomainNameProviderPlugin", "AWS::ApiGateway::RestApi=localstack.services.apigateway.resource_providers.aws_apigateway_restapi_plugin:ApiGatewayRestApiProviderPlugin", "AWS::Redshift::Cluster=localstack.services.redshift.resource_providers.aws_redshift_cluster_plugin:RedshiftClusterProviderPlugin", "AWS::Lambda::LayerVersionPermission=localstack.services.lambda_.resource_providers.aws_lambda_layerversionpermission_plugin:LambdaLayerVersionPermissionProviderPlugin", "AWS::ApiGateway::RequestValidator=localstack.services.apigateway.resource_providers.aws_apigateway_requestvalidator_plugin:ApiGatewayRequestValidatorProviderPlugin", "AWS::EC2::Route=localstack.services.ec2.resource_providers.aws_ec2_route_plugin:EC2RouteProviderPlugin", "AWS::KinesisFirehose::DeliveryStream=localstack.services.kinesisfirehose.resource_providers.aws_kinesisfirehose_deliverystream_plugin:KinesisFirehoseDeliveryStreamProviderPlugin", "AWS::Scheduler::Schedule=localstack.services.scheduler.resource_providers.aws_scheduler_schedule_plugin:SchedulerScheduleProviderPlugin", "AWS::ResourceGroups::Group=localstack.services.resource_groups.resource_providers.aws_resourcegroups_group_plugin:ResourceGroupsGroupProviderPlugin", "AWS::EC2::SubnetRouteTableAssociation=localstack.services.ec2.resource_providers.aws_ec2_subnetroutetableassociation_plugin:EC2SubnetRouteTableAssociationProviderPlugin", "AWS::IAM::ManagedPolicy=localstack.services.iam.resource_providers.aws_iam_managedpolicy_plugin:IAMManagedPolicyProviderPlugin", "AWS::IAM::AccessKey=localstack.services.iam.resource_providers.aws_iam_accesskey_plugin:IAMAccessKeyProviderPlugin", "AWS::ApiGateway::Account=localstack.services.apigateway.resource_providers.aws_apigateway_account_plugin:ApiGatewayAccountProviderPlugin", "AWS::ApiGateway::Model=localstack.services.apigateway.resource_providers.aws_apigateway_model_plugin:ApiGatewayModelProviderPlugin", "AWS::EC2::SecurityGroup=localstack.services.ec2.resource_providers.aws_ec2_securitygroup_plugin:EC2SecurityGroupProviderPlugin", "AWS::CDK::Metadata=localstack.services.cdk.resource_providers.cdk_metadata_plugin:LambdaAliasProviderPlugin", "AWS::SQS::QueuePolicy=localstack.services.sqs.resource_providers.aws_sqs_queuepolicy_plugin:SQSQueuePolicyProviderPlugin", "AWS::EC2::KeyPair=localstack.services.ec2.resource_providers.aws_ec2_keypair_plugin:EC2KeyPairProviderPlugin", "AWS::IAM::ServerCertificate=localstack.services.iam.resource_providers.aws_iam_servercertificate_plugin:IAMServerCertificateProviderPlugin", "AWS::Lambda::Function=localstack.services.lambda_.resource_providers.aws_lambda_function_plugin:LambdaFunctionProviderPlugin", "AWS::SES::EmailIdentity=localstack.services.ses.resource_providers.aws_ses_emailidentity_plugin:SESEmailIdentityProviderPlugin", "AWS::Events::ApiDestination=localstack.services.events.resource_providers.aws_events_apidestination_plugin:EventsApiDestinationProviderPlugin", "AWS::Route53::HealthCheck=localstack.services.route53.resource_providers.aws_route53_healthcheck_plugin:Route53HealthCheckProviderPlugin", "AWS::Route53::RecordSet=localstack.services.route53.resource_providers.aws_route53_recordset_plugin:Route53RecordSetProviderPlugin", "AWS::SecretsManager::SecretTargetAttachment=localstack.services.secretsmanager.resource_providers.aws_secretsmanager_secrettargetattachment_plugin:SecretsManagerSecretTargetAttachmentProviderPlugin", "AWS::Lambda::CodeSigningConfig=localstack.services.lambda_.resource_providers.aws_lambda_codesigningconfig_plugin:LambdaCodeSigningConfigProviderPlugin", "AWS::ApiGateway::GatewayResponse=localstack.services.apigateway.resource_providers.aws_apigateway_gatewayresponse_plugin:ApiGatewayGatewayResponseProviderPlugin", "AWS::IAM::ServiceLinkedRole=localstack.services.iam.resource_providers.aws_iam_servicelinkedrole_plugin:IAMServiceLinkedRoleProviderPlugin", "AWS::IAM::Policy=localstack.services.iam.resource_providers.aws_iam_policy_plugin:IAMPolicyProviderPlugin", "AWS::CertificateManager::Certificate=localstack.services.certificatemanager.resource_providers.aws_certificatemanager_certificate_plugin:CertificateManagerCertificateProviderPlugin", "AWS::ApiGateway::Deployment=localstack.services.apigateway.resource_providers.aws_apigateway_deployment_plugin:ApiGatewayDeploymentProviderPlugin", "AWS::IAM::Group=localstack.services.iam.resource_providers.aws_iam_group_plugin:IAMGroupProviderPlugin", "AWS::EC2::VPC=localstack.services.ec2.resource_providers.aws_ec2_vpc_plugin:EC2VPCProviderPlugin", "AWS::EC2::Subnet=localstack.services.ec2.resource_providers.aws_ec2_subnet_plugin:EC2SubnetProviderPlugin", "AWS::SSM::PatchBaseline=localstack.services.ssm.resource_providers.aws_ssm_patchbaseline_plugin:SSMPatchBaselineProviderPlugin", "AWS::Lambda::EventInvokeConfig=localstack.services.lambda_.resource_providers.aws_lambda_eventinvokeconfig_plugin:LambdaEventInvokeConfigProviderPlugin", "AWS::CloudFormation::WaitConditionHandle=localstack.services.cloudformation.resource_providers.aws_cloudformation_waitconditionhandle_plugin:CloudFormationWaitConditionHandleProviderPlugin", "AWS::IAM::User=localstack.services.iam.resource_providers.aws_iam_user_plugin:IAMUserProviderPlugin", "AWS::ApiGateway::Stage=localstack.services.apigateway.resource_providers.aws_apigateway_stage_plugin:ApiGatewayStageProviderPlugin", "AWS::Kinesis::StreamConsumer=localstack.services.kinesis.resource_providers.aws_kinesis_streamconsumer_plugin:KinesisStreamConsumerProviderPlugin", "AWS::EC2::TransitGatewayAttachment=localstack.services.ec2.resource_providers.aws_ec2_transitgatewayattachment_plugin:EC2TransitGatewayAttachmentProviderPlugin", "AWS::Lambda::Url=localstack.services.lambda_.resource_providers.aws_lambda_url_plugin:LambdaUrlProviderPlugin", "AWS::DynamoDB::Table=localstack.services.dynamodb.resource_providers.aws_dynamodb_table_plugin:DynamoDBTableProviderPlugin", "AWS::KMS::Key=localstack.services.kms.resource_providers.aws_kms_key_plugin:KMSKeyProviderPlugin", "AWS::ApiGateway::Resource=localstack.services.apigateway.resource_providers.aws_apigateway_resource_plugin:ApiGatewayResourceProviderPlugin", "AWS::EC2::VPCEndpoint=localstack.services.ec2.resource_providers.aws_ec2_vpcendpoint_plugin:EC2VPCEndpointProviderPlugin", "AWS::EC2::NatGateway=localstack.services.ec2.resource_providers.aws_ec2_natgateway_plugin:EC2NatGatewayProviderPlugin", "AWS::Events::EventBusPolicy=localstack.services.events.resource_providers.aws_events_eventbuspolicy_plugin:EventsEventBusPolicyProviderPlugin", "AWS::EC2::TransitGateway=localstack.services.ec2.resource_providers.aws_ec2_transitgateway_plugin:EC2TransitGatewayProviderPlugin", "AWS::SecretsManager::RotationSchedule=localstack.services.secretsmanager.resource_providers.aws_secretsmanager_rotationschedule_plugin:SecretsManagerRotationScheduleProviderPlugin", "AWS::CloudWatch::Alarm=localstack.services.cloudwatch.resource_providers.aws_cloudwatch_alarm_plugin:CloudWatchAlarmProviderPlugin", "AWS::SSM::MaintenanceWindowTask=localstack.services.ssm.resource_providers.aws_ssm_maintenancewindowtask_plugin:SSMMaintenanceWindowTaskProviderPlugin", "AWS::Events::Connection=localstack.services.events.resource_providers.aws_events_connection_plugin:EventsConnectionProviderPlugin", "AWS::EC2::DHCPOptions=localstack.services.ec2.resource_providers.aws_ec2_dhcpoptions_plugin:EC2DHCPOptionsProviderPlugin", "AWS::CloudFormation::Stack=localstack.services.cloudformation.resource_providers.aws_cloudformation_stack_plugin:CloudFormationStackProviderPlugin", "AWS::EC2::PrefixList=localstack.services.ec2.resource_providers.aws_ec2_prefixlist_plugin:EC2PrefixListProviderPlugin", "AWS::SNS::Subscription=localstack.services.sns.resource_providers.aws_sns_subscription_plugin:SNSSubscriptionProviderPlugin", "AWS::KMS::Alias=localstack.services.kms.resource_providers.aws_kms_alias_plugin:KMSAliasProviderPlugin", "AWS::Lambda::Alias=localstack.services.lambda_.resource_providers.lambda_alias_plugin:LambdaAliasProviderPlugin", "AWS::Logs::LogStream=localstack.services.logs.resource_providers.aws_logs_logstream_plugin:LogsLogStreamProviderPlugin", "AWS::StepFunctions::Activity=localstack.services.stepfunctions.resource_providers.aws_stepfunctions_activity_plugin:StepFunctionsActivityProviderPlugin", "AWS::EC2::RouteTable=localstack.services.ec2.resource_providers.aws_ec2_routetable_plugin:EC2RouteTableProviderPlugin", "AWS::Lambda::Version=localstack.services.lambda_.resource_providers.aws_lambda_version_plugin:LambdaVersionProviderPlugin", "AWS::Logs::SubscriptionFilter=localstack.services.logs.resource_providers.aws_logs_subscriptionfilter_plugin:LogsSubscriptionFilterProviderPlugin", "AWS::EC2::InternetGateway=localstack.services.ec2.resource_providers.aws_ec2_internetgateway_plugin:EC2InternetGatewayProviderPlugin", "AWS::ApiGateway::Method=localstack.services.apigateway.resource_providers.aws_apigateway_method_plugin:ApiGatewayMethodProviderPlugin", "AWS::Events::EventBus=localstack.services.events.resource_providers.aws_events_eventbus_plugin:EventsEventBusProviderPlugin", "AWS::CloudFormation::WaitCondition=localstack.services.cloudformation.resource_providers.aws_cloudformation_waitcondition_plugin:CloudFormationWaitConditionProviderPlugin", "AWS::S3::Bucket=localstack.services.s3.resource_providers.aws_s3_bucket_plugin:S3BucketProviderPlugin", "AWS::SecretsManager::ResourcePolicy=localstack.services.secretsmanager.resource_providers.aws_secretsmanager_resourcepolicy_plugin:SecretsManagerResourcePolicyProviderPlugin", "AWS::Logs::LogGroup=localstack.services.logs.resource_providers.aws_logs_loggroup_plugin:LogsLogGroupProviderPlugin", "AWS::Lambda::EventSourceMapping=localstack.services.lambda_.resource_providers.aws_lambda_eventsourcemapping_plugin:LambdaEventSourceMappingProviderPlugin", "AWS::SNS::Topic=localstack.services.sns.resource_providers.aws_sns_topic_plugin:SNSTopicProviderPlugin", "AWS::Scheduler::ScheduleGroup=localstack.services.scheduler.resource_providers.aws_scheduler_schedulegroup_plugin:SchedulerScheduleGroupProviderPlugin", "AWS::Events::Rule=localstack.services.events.resource_providers.aws_events_rule_plugin:EventsRuleProviderPlugin", "AWS::SSM::MaintenanceWindow=localstack.services.ssm.resource_providers.aws_ssm_maintenancewindow_plugin:SSMMaintenanceWindowProviderPlugin", "AWS::ApiGateway::UsagePlanKey=localstack.services.apigateway.resource_providers.aws_apigateway_usageplankey_plugin:ApiGatewayUsagePlanKeyProviderPlugin", "AWS::ApiGateway::BasePathMapping=localstack.services.apigateway.resource_providers.aws_apigateway_basepathmapping_plugin:ApiGatewayBasePathMappingProviderPlugin", "AWS::EC2::Instance=localstack.services.ec2.resource_providers.aws_ec2_instance_plugin:EC2InstanceProviderPlugin", "AWS::S3::BucketPolicy=localstack.services.s3.resource_providers.aws_s3_bucketpolicy_plugin:S3BucketPolicyProviderPlugin", "AWS::CloudFormation::Macro=localstack.services.cloudformation.resource_providers.aws_cloudformation_macro_plugin:CloudFormationMacroProviderPlugin", "AWS::SSM::Parameter=localstack.services.ssm.resource_providers.aws_ssm_parameter_plugin:SSMParameterProviderPlugin"], "localstack.runtime.server": ["hypercorn=localstack.runtime.server.plugins:HypercornRuntimeServerPlugin", "twisted=localstack.runtime.server.plugins:TwistedRuntimeServerPlugin"], "localstack.lambda.runtime_executor": ["docker=localstack.services.lambda_.invocation.plugins:DockerRuntimeExecutorPlugin"], "localstack.hooks.on_infra_start": ["register_cloudformation_deploy_ui=localstack.services.cloudformation.plugins:register_cloudformation_deploy_ui", "eager_load_services=localstack.services.plugins:eager_load_services", "setup_dns_configuration_on_host=localstack.dns.plugins:setup_dns_configuration_on_host", "start_dns_server=localstack.dns.plugins:start_dns_server", "register_custom_endpoints=localstack.services.lambda_.plugins:register_custom_endpoints", "validate_configuration=localstack.services.lambda_.plugins:validate_configuration", "_run_init_scripts_on_start=localstack.runtime.init:_run_init_scripts_on_start", "apply_aws_runtime_patches=localstack.aws.patches:apply_aws_runtime_patches", "_publish_config_as_analytics_event=localstack.runtime.analytics:_publish_config_as_analytics_event", "_publish_container_info=localstack.runtime.analytics:_publish_container_info", "apply_runtime_patches=localstack.runtime.patches:apply_runtime_patches", "register_swagger_endpoints=localstack.http.resources.swagger.plugins:register_swagger_endpoints", "init_response_mutation_handler=localstack.aws.handlers.response:init_response_mutation_handler", "_patch_botocore_endpoint_in_memory=localstack.aws.client:_patch_botocore_endpoint_in_memory", "_patch_botocore_json_parser=localstack.aws.client:_patch_botocore_json_parser", "_patch_cbor2=localstack.aws.client:_patch_cbor2", "delete_cached_certificate=localstack.plugins:delete_cached_certificate", "deprecation_warnings=localstack.plugins:deprecation_warnings", "conditionally_enable_debugger=localstack.dev.debugger.plugins:conditionally_enable_debugger"], "localstack.hooks.on_infra_shutdown": ["stop_server=localstack.dns.plugins:stop_server", "remove_custom_endpoints=localstack.services.lambda_.plugins:remove_custom_endpoints", "_run_init_scripts_on_shutdown=localstack.runtime.init:_run_init_scripts_on_shutdown", "publish_metrics=localstack.utils.analytics.metrics.publisher:publish_metrics", "run_on_after_service_shutdown_handlers=localstack.runtime.shutdown:run_on_after_service_shutdown_handlers", "run_shutdown_handlers=localstack.runtime.shutdown:run_shutdown_handlers", "shutdown_services=localstack.runtime.shutdown:shutdown_services"], "localstack.packages": ["lambda-java-libs/community=localstack.services.lambda_.plugins:lambda_java_libs", "lambda-runtime/community=localstack.services.lambda_.plugins:lambda_runtime_package", "ffmpeg/community=localstack.packages.plugins:ffmpeg_package", "java/community=localstack.packages.plugins:java_package", "terraform/community=localstack.packages.plugins:terraform_package", "jpype-jsonata/community=localstack.services.stepfunctions.plugins:jpype_jsonata_package", "opensearch/community=localstack.services.opensearch.plugins:opensearch_package", "kinesis-mock/community=localstack.services.kinesis.plugins:kinesismock_package", "vosk/community=localstack.services.transcribe.plugins:vosk_package", "dynamodb-local/community=localstack.services.dynamodb.plugins:dynamodb_local_package", "elasticsearch/community=localstack.services.es.plugins:elasticsearch_package"], "localstack.init.runner": ["py=localstack.runtime.init:PythonScriptRunner", "sh=localstack.runtime.init:ShellScriptRunner"], "localstack.hooks.on_infra_ready": ["_run_init_scripts_on_ready=localstack.runtime.init:_run_init_scripts_on_ready"], "localstack.hooks.configure_localstack_container": ["_mount_machine_file=localstack.utils.analytics.metadata:_mount_machine_file"], "localstack.hooks.prepare_host": ["prepare_host_machine_id=localstack.utils.analytics.metadata:prepare_host_machine_id"], "localstack.openapi.spec": ["localstack=localstack.plugins:CoreOASPlugin"], "localstack.runtime.components": ["aws=localstack.aws.components:AwsComponents"], "localstack.aws.provider": ["acm:default=localstack.services.providers:acm", "apigateway:default=localstack.services.providers:apigateway", "apigateway:legacy=localstack.services.providers:apigateway_legacy", "apigateway:next_gen=localstack.services.providers:apigateway_next_gen", "config:default=localstack.services.providers:awsconfig", "cloudformation:default=localstack.services.providers:cloudformation", "cloudformation:engine-v2=localstack.services.providers:cloudformation_v2", "cloudwatch:default=localstack.services.providers:cloudwatch", "cloudwatch:v1=localstack.services.providers:cloudwatch_v1", "cloudwatch:v2=localstack.services.providers:cloudwatch_v2", "dynamodb:default=localstack.services.providers:dynamodb", "dynamodb:v2=localstack.services.providers:dynamodb_v2", "dynamodbstreams:default=localstack.services.providers:dynamodbstreams", "dynamodbstreams:v2=localstack.services.providers:dynamodbstreams_v2", "ec2:default=localstack.services.providers:ec2", "es:default=localstack.services.providers:es", "events:default=localstack.services.providers:events", "events:legacy=localstack.services.providers:events_legacy", "events:v1=localstack.services.providers:events_v1", "events:v2=localstack.services.providers:events_v2", "firehose:default=localstack.services.providers:firehose", "iam:default=localstack.services.providers:iam", "kinesis:default=localstack.services.providers:kinesis", "kms:default=localstack.services.providers:kms", "lambda:default=localstack.services.providers:lambda_", "lambda:asf=localstack.services.providers:lambda_asf", "lambda:v2=localstack.services.providers:lambda_v2", "logs:default=localstack.services.providers:logs", "opensearch:default=localstack.services.providers:opensearch", "redshift:default=localstack.services.providers:redshift", "resource-groups:default=localstack.services.providers:resource_groups", "resourcegroupstaggingapi:default=localstack.services.providers:resourcegroupstaggingapi", "route53:default=localstack.services.providers:route53", "route53resolver:default=localstack.services.providers:route53resolver", "s3:default=localstack.services.providers:s3", "s3control:default=localstack.services.providers:s3control", "scheduler:default=localstack.services.providers:scheduler", "secretsmanager:default=localstack.services.providers:secretsmanager", "ses:default=localstack.services.providers:ses", "sns:default=localstack.services.providers:sns", "sqs:default=localstack.services.providers:sqs", "ssm:default=localstack.services.providers:ssm", "stepfunctions:default=localstack.services.providers:stepfunctions", "stepfunctions:v2=localstack.services.providers:stepfunctions_v2", "sts:default=localstack.services.providers:sts", "support:default=localstack.services.providers:support", "swf:default=localstack.services.providers:swf", "transcribe:default=localstack.services.providers:transcribe"]}