localstack-core 4.3.1.dev35__py3-none-any.whl → 4.3.1.dev37__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 (25) hide show
  1. localstack/config.py +0 -6
  2. localstack/deprecations.py +14 -0
  3. localstack/services/cloudformation/engine/entities.py +9 -4
  4. localstack/services/cloudformation/engine/v2/change_set_model.py +32 -67
  5. localstack/services/cloudformation/engine/v2/change_set_model_describer.py +119 -487
  6. localstack/services/cloudformation/engine/v2/change_set_model_executor.py +107 -70
  7. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +574 -0
  8. localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +6 -6
  9. localstack/services/cloudformation/v2/provider.py +39 -5
  10. localstack/services/cloudformation/v2/utils.py +5 -0
  11. localstack/services/sns/resource_providers/aws_sns_topic.py +1 -0
  12. localstack/testing/pytest/cloudformation/__init__.py +0 -0
  13. localstack/testing/pytest/cloudformation/fixtures.py +169 -0
  14. localstack/version.py +2 -2
  15. {localstack_core-4.3.1.dev35.dist-info → localstack_core-4.3.1.dev37.dist-info}/METADATA +1 -1
  16. {localstack_core-4.3.1.dev35.dist-info → localstack_core-4.3.1.dev37.dist-info}/RECORD +24 -20
  17. localstack_core-4.3.1.dev37.dist-info/plux.json +1 -0
  18. localstack_core-4.3.1.dev35.dist-info/plux.json +0 -1
  19. {localstack_core-4.3.1.dev35.data → localstack_core-4.3.1.dev37.data}/scripts/localstack +0 -0
  20. {localstack_core-4.3.1.dev35.data → localstack_core-4.3.1.dev37.data}/scripts/localstack-supervisor +0 -0
  21. {localstack_core-4.3.1.dev35.data → localstack_core-4.3.1.dev37.data}/scripts/localstack.bat +0 -0
  22. {localstack_core-4.3.1.dev35.dist-info → localstack_core-4.3.1.dev37.dist-info}/WHEEL +0 -0
  23. {localstack_core-4.3.1.dev35.dist-info → localstack_core-4.3.1.dev37.dist-info}/entry_points.txt +0 -0
  24. {localstack_core-4.3.1.dev35.dist-info → localstack_core-4.3.1.dev37.dist-info}/licenses/LICENSE.txt +0 -0
  25. {localstack_core-4.3.1.dev35.dist-info → localstack_core-4.3.1.dev37.dist-info}/top_level.txt +0 -0
localstack/config.py CHANGED
@@ -1089,11 +1089,6 @@ LAMBDA_EVENT_SOURCE_MAPPING_MAX_BACKOFF_ON_EMPTY_POLL_SEC = float(
1089
1089
  os.environ.get("LAMBDA_EVENT_SOURCE_MAPPING_MAX_BACKOFF_ON_EMPTY_POLL_SEC") or 10
1090
1090
  )
1091
1091
 
1092
- # Adding Stepfunctions default port
1093
- LOCAL_PORT_STEPFUNCTIONS = int(os.environ.get("LOCAL_PORT_STEPFUNCTIONS") or 8083)
1094
- # Stepfunctions lambda endpoint override
1095
- STEPFUNCTIONS_LAMBDA_ENDPOINT = os.environ.get("STEPFUNCTIONS_LAMBDA_ENDPOINT", "").strip()
1096
-
1097
1092
  # path prefix for windows volume mounting
1098
1093
  WINDOWS_DOCKER_MOUNT_PREFIX = os.environ.get("WINDOWS_DOCKER_MOUNT_PREFIX", "/host_mnt")
1099
1094
 
@@ -1364,7 +1359,6 @@ CONFIG_ENV_VARS = [
1364
1359
  "SQS_ENDPOINT_STRATEGY",
1365
1360
  "SQS_DISABLE_CLOUDWATCH_METRICS",
1366
1361
  "SQS_CLOUDWATCH_METRICS_REPORT_INTERVAL",
1367
- "STEPFUNCTIONS_LAMBDA_ENDPOINT",
1368
1362
  "STRICT_SERVICE_LOADING",
1369
1363
  "TF_COMPAT_MODE",
1370
1364
  "USE_SSL",
@@ -311,6 +311,20 @@ DEPRECATIONS = [
311
311
  " is faster, achieves great AWS parity, and fixes compatibility issues with the StepFunctions JSONata feature."
312
312
  " Please remove EVENT_RULE_ENGINE.",
313
313
  ),
314
+ EnvVarDeprecation(
315
+ "STEPFUNCTIONS_LAMBDA_ENDPOINT",
316
+ "4.0.0",
317
+ "This is only supported for the legacy provider. URL to use as the Lambda service endpoint in Step Functions. "
318
+ "By default this is the LocalStack Lambda endpoint. Use default to select the original AWS Lambda endpoint.",
319
+ ),
320
+ EnvVarDeprecation(
321
+ "LOCAL_PORT_STEPFUNCTIONS",
322
+ "4.0.0",
323
+ "This is only supported for the legacy provider."
324
+ "It defines the local port to which Step Functions traffic is redirected."
325
+ "By default, LocalStack routes Step Functions traffic to its internal runtime. "
326
+ "Use this variable only if you need to redirect traffic to a different local Step Functions runtime.",
327
+ ),
314
328
  ]
315
329
 
316
330
 
@@ -422,12 +422,17 @@ class StackChangeSet(Stack):
422
422
  return result
423
423
 
424
424
  # V2 only
425
- def populate_update_graph(self, before_template: dict | None, after_template: dict | None):
425
+ def populate_update_graph(
426
+ self,
427
+ before_template: Optional[dict],
428
+ after_template: Optional[dict],
429
+ before_parameters: Optional[dict],
430
+ after_parameters: Optional[dict],
431
+ ) -> None:
426
432
  change_set_model = ChangeSetModel(
427
433
  before_template=before_template,
428
434
  after_template=after_template,
429
- # TODO
430
- before_parameters=None,
431
- after_parameters=None,
435
+ before_parameters=before_parameters,
436
+ after_parameters=after_parameters,
432
437
  )
433
438
  self.update_graph = change_set_model.get_update_model()
@@ -7,7 +7,6 @@ from typing import Any, Final, Generator, Optional, Union, cast
7
7
 
8
8
  from typing_extensions import TypeVar
9
9
 
10
- from localstack.aws.api.cloudformation import ChangeAction
11
10
  from localstack.utils.strings import camel_to_snake_case
12
11
 
13
12
  T = TypeVar("T")
@@ -67,15 +66,6 @@ class ChangeType(enum.Enum):
67
66
  def __str__(self):
68
67
  return self.value
69
68
 
70
- def to_action(self) -> ChangeAction | None:
71
- match self:
72
- case self.CREATED:
73
- return ChangeAction.Add
74
- case self.MODIFIED:
75
- return ChangeAction.Modify
76
- case self.REMOVED:
77
- return ChangeAction.Remove
78
-
79
69
  def for_child(self, child_change_type: ChangeType) -> ChangeType:
80
70
  if child_change_type == self:
81
71
  return self
@@ -525,7 +515,7 @@ class ChangeSetModel:
525
515
 
526
516
  node_parameter = self._retrieve_parameter_if_exists(parameter_name=logical_id)
527
517
  if isinstance(node_parameter, NodeParameter):
528
- return node_parameter.dynamic_value.change_type
518
+ return node_parameter.change_type
529
519
 
530
520
  # TODO: this should check the replacement flag for a resource update.
531
521
  node_resource = self._retrieve_or_visit_resource(resource_name=logical_id)
@@ -584,19 +574,16 @@ class ChangeSetModel:
584
574
  def _visit_array(
585
575
  self, scope: Scope, before_array: Maybe[list], after_array: Maybe[list]
586
576
  ) -> NodeArray:
587
- change_type = ChangeType.UNCHANGED
588
577
  array: list[ChangeSetEntity] = list()
589
578
  for index, (before_value, after_value) in enumerate(
590
579
  zip_longest(before_array, after_array, fillvalue=Nothing)
591
580
  ):
592
- # TODO: should extract this scoping logic.
593
581
  value_scope = scope.open_index(index=index)
594
582
  value = self._visit_value(
595
583
  scope=value_scope, before_value=before_value, after_value=after_value
596
584
  )
597
585
  array.append(value)
598
- if value.change_type != ChangeType.UNCHANGED:
599
- change_type = ChangeType.MODIFIED
586
+ change_type = self._change_type_for_parent_of([value.change_type for value in array])
600
587
  return NodeArray(scope=scope, change_type=change_type, array=array)
601
588
 
602
589
  def _visit_object(
@@ -695,28 +682,12 @@ class ChangeSetModel:
695
682
  node_property = self._visited_scopes.get(scope)
696
683
  if isinstance(node_property, NodeProperty):
697
684
  return node_property
698
-
699
685
  value = self._visit_value(
700
686
  scope=scope, before_value=before_property, after_value=after_property
701
687
  )
702
- if self._is_created(before=before_property, after=after_property):
703
- node_property = NodeProperty(
704
- scope=scope,
705
- change_type=ChangeType.CREATED,
706
- name=property_name,
707
- value=value,
708
- )
709
- elif self._is_removed(before=before_property, after=after_property):
710
- node_property = NodeProperty(
711
- scope=scope,
712
- change_type=ChangeType.REMOVED,
713
- name=property_name,
714
- value=value,
715
- )
716
- else:
717
- node_property = NodeProperty(
718
- scope=scope, change_type=value.change_type, name=property_name, value=value
719
- )
688
+ node_property = NodeProperty(
689
+ scope=scope, change_type=value.change_type, name=property_name, value=value
690
+ )
720
691
  self._visited_scopes[scope] = node_property
721
692
  return node_property
722
693
 
@@ -748,6 +719,13 @@ class ChangeSetModel:
748
719
  self._visited_scopes[scope] = node_properties
749
720
  return node_properties
750
721
 
722
+ def _visit_type(self, scope: Scope, before_type: Any, after_type: Any) -> TerminalValue:
723
+ value = self._visit_value(scope=scope, before_value=before_type, after_value=after_type)
724
+ if not isinstance(value, TerminalValue):
725
+ # TODO: decide where template schema validation should occur.
726
+ raise RuntimeError()
727
+ return value
728
+
751
729
  def _visit_resource(
752
730
  self,
753
731
  scope: Scope,
@@ -766,8 +744,12 @@ class ChangeSetModel:
766
744
  else:
767
745
  change_type = ChangeType.UNCHANGED
768
746
 
769
- # TODO: investigate behaviour with type changes, for now this is filler code.
770
- _, type_str = self._safe_access_in(scope, TypeKey, after_resource)
747
+ scope_type, (before_type, after_type) = self._safe_access_in(
748
+ scope, TypeKey, before_resource, after_resource
749
+ )
750
+ terminal_value_type = self._visit_type(
751
+ scope=scope_type, before_type=before_type, after_type=after_type
752
+ )
771
753
 
772
754
  condition_reference = None
773
755
  scope_condition, (before_condition, after_condition) = self._safe_access_in(
@@ -792,7 +774,7 @@ class ChangeSetModel:
792
774
  scope=scope,
793
775
  change_type=change_type,
794
776
  name=resource_name,
795
- type_=TerminalValueUnchanged(scope=scope, value=type_str),
777
+ type_=terminal_value_type,
796
778
  condition_reference=condition_reference,
797
779
  properties=properties,
798
780
  )
@@ -872,36 +854,19 @@ class ChangeSetModel:
872
854
  return node_parameter
873
855
  # TODO: add logic to compute defaults already in the graph building process?
874
856
  dynamic_value = self._visit_dynamic_parameter(parameter_name=parameter_name)
875
- if self._is_created(before=before_parameter, after=after_parameter):
876
- node_parameter = NodeParameter(
877
- scope=scope,
878
- change_type=ChangeType.CREATED,
879
- name=parameter_name,
880
- value=TerminalValueCreated(scope=scope, value=after_parameter),
881
- dynamic_value=dynamic_value,
882
- )
883
- elif self._is_removed(before=before_parameter, after=after_parameter):
884
- node_parameter = NodeParameter(
885
- scope=scope,
886
- change_type=ChangeType.REMOVED,
887
- name=parameter_name,
888
- value=TerminalValueRemoved(scope=scope, value=before_parameter),
889
- dynamic_value=dynamic_value,
890
- )
891
- else:
892
- value = self._visit_value(
893
- scope=scope, before_value=before_parameter, after_value=after_parameter
894
- )
895
- change_type = self._change_type_for_parent_of(
896
- change_types=[dynamic_value.change_type, value.change_type]
897
- )
898
- node_parameter = NodeParameter(
899
- scope=scope,
900
- change_type=change_type,
901
- name=parameter_name,
902
- value=value,
903
- dynamic_value=dynamic_value,
904
- )
857
+ value = self._visit_value(
858
+ scope=scope, before_value=before_parameter, after_value=after_parameter
859
+ )
860
+ change_type = self._change_type_for_parent_of(
861
+ change_types=[dynamic_value.change_type, value.change_type]
862
+ )
863
+ node_parameter = NodeParameter(
864
+ scope=scope,
865
+ change_type=change_type,
866
+ name=parameter_name,
867
+ value=value,
868
+ dynamic_value=dynamic_value,
869
+ )
905
870
  self._visited_scopes[scope] = node_parameter
906
871
  return node_parameter
907
872