localstack-core 4.10.1.dev42__py3-none-any.whl → 4.11.2.dev14__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 (116) hide show
  1. localstack/aws/api/apigateway/__init__.py +42 -0
  2. localstack/aws/api/cloudformation/__init__.py +161 -0
  3. localstack/aws/api/ec2/__init__.py +1165 -12
  4. localstack/aws/api/iam/__init__.py +227 -0
  5. localstack/aws/api/kms/__init__.py +1 -0
  6. localstack/aws/api/lambda_/__init__.py +418 -66
  7. localstack/aws/api/logs/__init__.py +312 -0
  8. localstack/aws/api/opensearch/__init__.py +89 -0
  9. localstack/aws/api/redshift/__init__.py +69 -0
  10. localstack/aws/api/resourcegroupstaggingapi/__init__.py +36 -0
  11. localstack/aws/api/route53/__init__.py +42 -0
  12. localstack/aws/api/route53resolver/__init__.py +1 -0
  13. localstack/aws/api/s3/__init__.py +62 -0
  14. localstack/aws/api/secretsmanager/__init__.py +28 -23
  15. localstack/aws/api/stepfunctions/__init__.py +52 -10
  16. localstack/aws/api/sts/__init__.py +52 -0
  17. localstack/aws/handlers/logging.py +8 -4
  18. localstack/aws/handlers/service.py +11 -2
  19. localstack/aws/protocol/serializer.py +1 -1
  20. localstack/deprecations.py +0 -6
  21. localstack/services/acm/provider.py +4 -0
  22. localstack/services/apigateway/legacy/provider.py +28 -15
  23. localstack/services/cloudformation/engine/template_preparer.py +6 -2
  24. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +12 -0
  25. localstack/services/cloudwatch/provider.py +10 -3
  26. localstack/services/cloudwatch/provider_v2.py +6 -3
  27. localstack/services/configservice/provider.py +5 -1
  28. localstack/services/dynamodb/provider.py +1 -0
  29. localstack/services/dynamodb/v2/provider.py +1 -0
  30. localstack/services/dynamodbstreams/provider.py +6 -0
  31. localstack/services/dynamodbstreams/v2/provider.py +6 -0
  32. localstack/services/ec2/provider.py +6 -0
  33. localstack/services/es/provider.py +6 -0
  34. localstack/services/events/provider.py +4 -0
  35. localstack/services/events/v1/provider.py +9 -0
  36. localstack/services/firehose/provider.py +5 -0
  37. localstack/services/iam/provider.py +4 -0
  38. localstack/services/kms/models.py +10 -20
  39. localstack/services/kms/provider.py +4 -0
  40. localstack/services/lambda_/api_utils.py +37 -20
  41. localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py +1 -1
  42. localstack/services/lambda_/invocation/assignment.py +4 -1
  43. localstack/services/lambda_/invocation/execution_environment.py +21 -2
  44. localstack/services/lambda_/invocation/lambda_models.py +27 -2
  45. localstack/services/lambda_/invocation/lambda_service.py +51 -3
  46. localstack/services/lambda_/invocation/models.py +9 -1
  47. localstack/services/lambda_/invocation/version_manager.py +18 -3
  48. localstack/services/lambda_/provider.py +239 -95
  49. localstack/services/lambda_/resource_providers/aws_lambda_function.py +33 -1
  50. localstack/services/lambda_/runtimes.py +3 -1
  51. localstack/services/logs/provider.py +9 -0
  52. localstack/services/opensearch/provider.py +53 -3
  53. localstack/services/resource_groups/provider.py +5 -1
  54. localstack/services/resourcegroupstaggingapi/provider.py +6 -1
  55. localstack/services/s3/provider.py +28 -15
  56. localstack/services/s3/utils.py +35 -14
  57. localstack/services/s3control/provider.py +101 -2
  58. localstack/services/s3control/validation.py +50 -0
  59. localstack/services/sns/constants.py +3 -1
  60. localstack/services/sns/publisher.py +15 -6
  61. localstack/services/sns/v2/models.py +6 -0
  62. localstack/services/sns/v2/provider.py +650 -19
  63. localstack/services/sns/v2/utils.py +12 -0
  64. localstack/services/stepfunctions/asl/component/common/path/result_path.py +1 -1
  65. localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py +0 -1
  66. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py +0 -1
  67. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py +8 -8
  68. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/{mock_eval_utils.py → local_mock_eval_utils.py} +13 -9
  69. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py +6 -6
  70. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py +1 -1
  71. localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py +4 -0
  72. localstack/services/stepfunctions/asl/component/test_state/state/base_mock.py +118 -0
  73. localstack/services/stepfunctions/asl/component/test_state/state/common.py +82 -0
  74. localstack/services/stepfunctions/asl/component/test_state/state/execution.py +139 -0
  75. localstack/services/stepfunctions/asl/component/test_state/state/map.py +77 -0
  76. localstack/services/stepfunctions/asl/component/test_state/state/task.py +44 -0
  77. localstack/services/stepfunctions/asl/eval/environment.py +30 -22
  78. localstack/services/stepfunctions/asl/eval/states.py +1 -1
  79. localstack/services/stepfunctions/asl/eval/test_state/environment.py +49 -9
  80. localstack/services/stepfunctions/asl/eval/test_state/program_state.py +22 -0
  81. localstack/services/stepfunctions/asl/jsonata/jsonata.py +5 -1
  82. localstack/services/stepfunctions/asl/parse/preprocessor.py +67 -24
  83. localstack/services/stepfunctions/asl/parse/test_state/asl_parser.py +5 -4
  84. localstack/services/stepfunctions/asl/parse/test_state/preprocessor.py +222 -31
  85. localstack/services/stepfunctions/asl/static_analyser/test_state/test_state_analyser.py +170 -22
  86. localstack/services/stepfunctions/backend/execution.py +6 -6
  87. localstack/services/stepfunctions/backend/execution_worker.py +5 -5
  88. localstack/services/stepfunctions/backend/test_state/execution.py +36 -0
  89. localstack/services/stepfunctions/backend/test_state/execution_worker.py +33 -1
  90. localstack/services/stepfunctions/backend/test_state/test_state_mock.py +127 -0
  91. localstack/services/stepfunctions/local_mocking/__init__.py +9 -0
  92. localstack/services/stepfunctions/{mocking → local_mocking}/mock_config.py +24 -17
  93. localstack/services/stepfunctions/provider.py +78 -27
  94. localstack/services/stepfunctions/test_state/mock_config.py +47 -0
  95. localstack/testing/pytest/fixtures.py +28 -0
  96. localstack/testing/snapshots/transformer_utility.py +5 -0
  97. localstack/utils/analytics/publisher.py +37 -155
  98. localstack/utils/analytics/service_request_aggregator.py +6 -4
  99. localstack/utils/aws/arns.py +7 -0
  100. localstack/utils/batching.py +258 -0
  101. localstack/utils/collections.py +23 -11
  102. localstack/version.py +2 -2
  103. {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/METADATA +5 -5
  104. {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/RECORD +113 -105
  105. localstack_core-4.11.2.dev14.dist-info/plux.json +1 -0
  106. localstack/services/stepfunctions/mocking/__init__.py +0 -0
  107. localstack/utils/batch_policy.py +0 -124
  108. localstack_core-4.10.1.dev42.dist-info/plux.json +0 -1
  109. /localstack/services/stepfunctions/{mocking → local_mocking}/mock_config_file.py +0 -0
  110. {localstack_core-4.10.1.dev42.data → localstack_core-4.11.2.dev14.data}/scripts/localstack +0 -0
  111. {localstack_core-4.10.1.dev42.data → localstack_core-4.11.2.dev14.data}/scripts/localstack-supervisor +0 -0
  112. {localstack_core-4.10.1.dev42.data → localstack_core-4.11.2.dev14.data}/scripts/localstack.bat +0 -0
  113. {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/WHEEL +0 -0
  114. {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/entry_points.txt +0 -0
  115. {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/licenses/LICENSE.txt +0 -0
  116. {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/top_level.txt +0 -0
@@ -27,6 +27,7 @@ from localstack.aws.api.lambda_ import (
27
27
  Arn,
28
28
  Blob,
29
29
  BlobStream,
30
+ CapacityProviderConfig,
30
31
  CodeSigningConfigArn,
31
32
  CodeSigningConfigNotFoundException,
32
33
  CodeSigningPolicies,
@@ -39,6 +40,7 @@ from localstack.aws.api.lambda_ import (
39
40
  CreateFunctionRequest,
40
41
  CreateFunctionUrlConfigResponse,
41
42
  DeleteCodeSigningConfigResponse,
43
+ DeleteFunctionResponse,
42
44
  Description,
43
45
  DestinationConfig,
44
46
  EventSourceMappingConfiguration,
@@ -48,6 +50,7 @@ from localstack.aws.api.lambda_ import (
48
50
  FunctionName,
49
51
  FunctionUrlAuthType,
50
52
  FunctionUrlQualifier,
53
+ FunctionVersionLatestPublished,
51
54
  GetAccountSettingsResponse,
52
55
  GetCodeSigningConfigResponse,
53
56
  GetFunctionCodeSigningConfigResponse,
@@ -65,6 +68,7 @@ from localstack.aws.api.lambda_ import (
65
68
  InvokeAsyncResponse,
66
69
  InvokeMode,
67
70
  LambdaApi,
71
+ LambdaManagedInstancesCapacityProviderConfig,
68
72
  LastUpdateStatus,
69
73
  LayerName,
70
74
  LayerPermissionAllowedAction,
@@ -99,6 +103,7 @@ from localstack.aws.api.lambda_ import (
99
103
  MaxProvisionedConcurrencyConfigListItems,
100
104
  NamespacedFunctionName,
101
105
  NamespacedStatementId,
106
+ NumericLatestPublishedOrAliasQualifier,
102
107
  OnFailure,
103
108
  OnSuccess,
104
109
  OrganizationId,
@@ -130,6 +135,7 @@ from localstack.aws.api.lambda_ import (
130
135
  TaggableResource,
131
136
  TagKeyList,
132
137
  Tags,
138
+ TenantId,
133
139
  TracingMode,
134
140
  UnqualifiedFunctionName,
135
141
  UpdateCodeSigningConfigResponse,
@@ -137,7 +143,7 @@ from localstack.aws.api.lambda_ import (
137
143
  UpdateFunctionCodeRequest,
138
144
  UpdateFunctionConfigurationRequest,
139
145
  UpdateFunctionUrlConfigResponse,
140
- Version,
146
+ VersionWithLatestPublished,
141
147
  )
142
148
  from localstack.aws.api.lambda_ import FunctionVersion as FunctionVersionApi
143
149
  from localstack.aws.api.lambda_ import ServiceException as LambdaServiceException
@@ -209,6 +215,7 @@ from localstack.services.lambda_.invocation.lambda_service import (
209
215
  store_lambda_archive,
210
216
  store_s3_bucket_archive,
211
217
  )
218
+ from localstack.services.lambda_.invocation.models import CapacityProvider as CapacityProviderModel
212
219
  from localstack.services.lambda_.invocation.models import LambdaStore
213
220
  from localstack.services.lambda_.invocation.runtime_executor import get_runtime_executor
214
221
  from localstack.services.lambda_.lambda_utils import HINT_LOG
@@ -231,6 +238,7 @@ from localstack.services.plugins import ServiceLifecycleHook
231
238
  from localstack.state import StateVisitor
232
239
  from localstack.utils.aws.arns import (
233
240
  ArnData,
241
+ capacity_provider_arn,
234
242
  extract_resource_from_arn,
235
243
  extract_service_from_arn,
236
244
  get_partition,
@@ -239,7 +247,7 @@ from localstack.utils.aws.arns import (
239
247
  )
240
248
  from localstack.utils.aws.client_types import ServicePrincipal
241
249
  from localstack.utils.bootstrap import is_api_enabled
242
- from localstack.utils.collections import PaginatedList
250
+ from localstack.utils.collections import PaginatedList, merge_recursive
243
251
  from localstack.utils.event_matcher import validate_event_pattern
244
252
  from localstack.utils.strings import get_random_hex, short_uid, to_bytes, to_str
245
253
  from localstack.utils.sync import poll_condition
@@ -306,6 +314,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
306
314
  new_config = dataclasses.replace(fn_version.config, state=new_state)
307
315
  new_version = dataclasses.replace(fn_version, config=new_config)
308
316
  fn.versions[fn_version.id.qualifier] = new_version
317
+ # TODO: consider skipping this for $LATEST versions of functions with a capacity provider
309
318
  self.lambda_service.create_function_version(fn_version).result(
310
319
  timeout=5
311
320
  )
@@ -419,6 +428,23 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
419
428
  )
420
429
  return esm
421
430
 
431
+ @staticmethod
432
+ def _get_capacity_provider(
433
+ capacity_provider_name: str,
434
+ account_id: str,
435
+ region: str,
436
+ error_msg_template: str = "Capacity provider not found: {}",
437
+ ) -> CapacityProviderModel:
438
+ state = lambda_stores[account_id][region]
439
+ cp = state.capacity_providers.get(capacity_provider_name)
440
+ if not cp:
441
+ arn = capacity_provider_arn(capacity_provider_name, account_id, region)
442
+ raise ResourceNotFoundException(
443
+ error_msg_template.format(arn),
444
+ Type="User",
445
+ )
446
+ return cp
447
+
422
448
  @staticmethod
423
449
  def _validate_qualifier_expression(qualifier: str) -> None:
424
450
  if error_messages := api_utils.validate_qualifier(qualifier):
@@ -489,7 +515,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
489
515
  subnet_id = subnet_ids[0]
490
516
  if not bool(SUBNET_ID_REGEX.match(subnet_id)):
491
517
  raise ValidationException(
492
- f"1 validation error detected: Value '[{subnet_id}]' at 'vpcConfig.subnetIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: ^subnet-[0-9a-z]*$]"
518
+ f"1 validation error detected: Value '[{subnet_id}]' at 'vpcConfig.subnetIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: subnet-[0-9a-z]*]"
493
519
  )
494
520
 
495
521
  return VpcConfig(
@@ -506,6 +532,8 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
506
532
  description: str | None = None,
507
533
  revision_id: str | None = None,
508
534
  code_sha256: str | None = None,
535
+ publish_to: FunctionVersionLatestPublished | None = None,
536
+ is_active: bool = False,
509
537
  ) -> tuple[FunctionVersion, bool]:
510
538
  """
511
539
  Release a new version to the model if all restrictions are met.
@@ -568,38 +596,57 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
568
596
  ):
569
597
  return prev_version, False
570
598
  # TODO check if there was a change since last version
571
- next_version = str(function.next_version)
572
- function.next_version += 1
599
+ if publish_to == FunctionVersionLatestPublished.LATEST_PUBLISHED:
600
+ qualifier = "$LATEST.PUBLISHED"
601
+ else:
602
+ qualifier = str(function.next_version)
603
+ function.next_version += 1
573
604
  new_id = VersionIdentifier(
574
605
  function_name=function_name,
575
- qualifier=next_version,
606
+ qualifier=qualifier,
576
607
  region=region,
577
608
  account=account_id,
578
609
  )
579
- apply_on = current_latest_version.config.snap_start["ApplyOn"]
580
- optimization_status = SnapStartOptimizationStatus.Off
581
- if apply_on == SnapStartApplyOn.PublishedVersions:
582
- optimization_status = SnapStartOptimizationStatus.On
583
- snap_start = SnapStartResponse(
584
- ApplyOn=apply_on,
585
- OptimizationStatus=optimization_status,
610
+
611
+ if current_latest_version.config.CapacityProviderConfig:
612
+ # for lambda managed functions, snap start is not supported
613
+ snap_start = None
614
+ else:
615
+ apply_on = current_latest_version.config.snap_start["ApplyOn"]
616
+ optimization_status = SnapStartOptimizationStatus.Off
617
+ if apply_on == SnapStartApplyOn.PublishedVersions:
618
+ optimization_status = SnapStartOptimizationStatus.On
619
+ snap_start = SnapStartResponse(
620
+ ApplyOn=apply_on,
621
+ OptimizationStatus=optimization_status,
622
+ )
623
+
624
+ last_update = None
625
+ new_state = VersionState(
626
+ state=State.Pending,
627
+ code=StateReasonCode.Creating,
628
+ reason="The function is being created.",
586
629
  )
630
+ if publish_to == FunctionVersionLatestPublished.LATEST_PUBLISHED:
631
+ last_update = UpdateStatus(
632
+ status=LastUpdateStatus.InProgress,
633
+ code="Updating",
634
+ reason="The function is being updated.",
635
+ )
636
+ if is_active:
637
+ new_state = VersionState(state=State.Active)
587
638
  new_version = dataclasses.replace(
588
639
  current_latest_version,
589
640
  config=dataclasses.replace(
590
641
  current_latest_version.config,
591
- last_update=None, # versions never have a last update status
592
- state=VersionState(
593
- state=State.Pending,
594
- code=StateReasonCode.Creating,
595
- reason="The function is being created.",
596
- ),
642
+ last_update=last_update,
643
+ state=new_state,
597
644
  snap_start=snap_start,
598
645
  **changes,
599
646
  ),
600
647
  id=new_id,
601
648
  )
602
- function.versions[next_version] = new_version
649
+ function.versions[qualifier] = new_version
603
650
  return new_version, True
604
651
 
605
652
  def _publish_version_from_existing_version(
@@ -610,6 +657,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
610
657
  description: str | None = None,
611
658
  revision_id: str | None = None,
612
659
  code_sha256: str | None = None,
660
+ publish_to: FunctionVersionLatestPublished | None = None,
613
661
  ) -> FunctionVersion:
614
662
  """
615
663
  Publish version from an existing, already initialized LATEST
@@ -622,6 +670,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
622
670
  :param code_sha256: code sha (check if current code matches)
623
671
  :return: new version
624
672
  """
673
+ is_active = True if publish_to == FunctionVersionLatestPublished.LATEST_PUBLISHED else False
625
674
  new_version, changed = self._create_version_model(
626
675
  function_name=function_name,
627
676
  region=region,
@@ -629,18 +678,34 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
629
678
  description=description,
630
679
  revision_id=revision_id,
631
680
  code_sha256=code_sha256,
681
+ publish_to=publish_to,
682
+ is_active=is_active,
632
683
  )
633
684
  if not changed:
634
685
  return new_version
635
- self.lambda_service.publish_version(new_version)
686
+
687
+ if new_version.config.CapacityProviderConfig:
688
+ self.lambda_service.publish_version_async(new_version)
689
+ else:
690
+ self.lambda_service.publish_version(new_version)
636
691
  state = lambda_stores[account_id][region]
637
692
  function = state.functions.get(function_name)
693
+
694
+ # Update revision id for $LATEST version
638
695
  # TODO: re-evaluate data model to prevent this dirty hack just for bumping the revision id
639
696
  latest_version = function.versions["$LATEST"]
640
697
  function.versions["$LATEST"] = dataclasses.replace(
641
698
  latest_version, config=dataclasses.replace(latest_version.config)
642
699
  )
643
- return function.versions.get(new_version.id.qualifier)
700
+ if new_version.config.CapacityProviderConfig:
701
+ # publish_version happens async for functions with a capacity provider.
702
+ # Therefore, we return the new_version with State=Pending or LastUpdateStatus=InProgress ($LATEST.PUBLISHED)
703
+ return new_version
704
+ else:
705
+ # Regular functions yield an Active state modified during `publish_version` (sync).
706
+ # Therefore, we need to get the updated version from the store.
707
+ updated_version = function.versions.get(new_version.id.qualifier)
708
+ return updated_version
644
709
 
645
710
  def _publish_version_with_changes(
646
711
  self,
@@ -650,6 +715,8 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
650
715
  description: str | None = None,
651
716
  revision_id: str | None = None,
652
717
  code_sha256: str | None = None,
718
+ publish_to: FunctionVersionLatestPublished | None = None,
719
+ is_active: bool = False,
653
720
  ) -> FunctionVersion:
654
721
  """
655
722
  Publish version together with a new latest version (publish on create / update)
@@ -669,6 +736,8 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
669
736
  description=description,
670
737
  revision_id=revision_id,
671
738
  code_sha256=code_sha256,
739
+ publish_to=publish_to,
740
+ is_active=is_active,
672
741
  )
673
742
  if not changed:
674
743
  return new_version
@@ -720,7 +789,8 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
720
789
  if layer_version_str is None:
721
790
  raise ValidationException(
722
791
  f"1 validation error detected: Value '[{layer_version_arn}]'"
723
- + r" at 'layers' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 140, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: (arn:[a-zA-Z0-9-]+:lambda:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\d{1}:\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+), Member must not be null]",
792
+ + " at 'layers' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 2048, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: "
793
+ + "(arn:(aws[a-zA-Z-]*)?:lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+), Member must not be null]",
724
794
  )
725
795
 
726
796
  state = lambda_stores[layer_account_id][layer_region]
@@ -941,11 +1011,13 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
941
1011
  account_id=context_account_id,
942
1012
  )
943
1013
  else:
944
- raise LambdaServiceException("Gotta have s3 bucket or zip file")
1014
+ raise LambdaServiceException("A ZIP file or S3 bucket is required")
945
1015
  elif package_type == PackageType.Image:
946
1016
  image = request_code.get("ImageUri")
947
1017
  if not image:
948
- raise LambdaServiceException("Gotta have an image when package type is image")
1018
+ raise LambdaServiceException(
1019
+ "An image is required when the package type is set to 'image'"
1020
+ )
949
1021
  image = create_image_code(image_uri=image)
950
1022
 
951
1023
  image_config_req = request.get("ImageConfig", {})
@@ -956,6 +1028,25 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
956
1028
  )
957
1029
  # Runtime management controls are not available when providing a custom image
958
1030
  runtime_version_config = None
1031
+
1032
+ # TODO: validations and figure out in which order
1033
+ capacity_provider_config = None
1034
+ memory_size = request.get("MemorySize", LAMBDA_DEFAULT_MEMORY_SIZE)
1035
+ if "CapacityProviderConfig" in request:
1036
+ capacity_provider_config = request["CapacityProviderConfig"]
1037
+ default_config = CapacityProviderConfig(
1038
+ LambdaManagedInstancesCapacityProviderConfig=LambdaManagedInstancesCapacityProviderConfig(
1039
+ ExecutionEnvironmentMemoryGiBPerVCpu=2.0,
1040
+ PerExecutionEnvironmentMaxConcurrency=16,
1041
+ )
1042
+ )
1043
+ capacity_provider_config = merge_recursive(default_config, capacity_provider_config)
1044
+ memory_size = 2048
1045
+ if request.get("LoggingConfig", {}).get("LogFormat") == LogFormat.Text:
1046
+ raise InvalidParameterValueException(
1047
+ 'LogLevel is not supported when LogFormat is set to "Text". Remove LogLevel from your request or change the LogFormat to "JSON" and try again.',
1048
+ Type="User",
1049
+ )
959
1050
  if "LoggingConfig" in request:
960
1051
  logging_config = request["LoggingConfig"]
961
1052
  LOG.warning(
@@ -979,11 +1070,25 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
979
1070
  | logging_config
980
1071
  )
981
1072
 
1073
+ elif capacity_provider_config:
1074
+ logging_config = LoggingConfig(
1075
+ LogFormat=LogFormat.JSON,
1076
+ LogGroup=f"/aws/lambda/{function_name}",
1077
+ ApplicationLogLevel="INFO",
1078
+ SystemLogLevel="INFO",
1079
+ )
982
1080
  else:
983
1081
  logging_config = LoggingConfig(
984
1082
  LogFormat=LogFormat.Text, LogGroup=f"/aws/lambda/{function_name}"
985
1083
  )
986
-
1084
+ snap_start = (
1085
+ None
1086
+ if capacity_provider_config
1087
+ else SnapStartResponse(
1088
+ ApplyOn=request.get("SnapStart", {}).get("ApplyOn", SnapStartApplyOn.None_),
1089
+ OptimizationStatus=SnapStartOptimizationStatus.Off,
1090
+ )
1091
+ )
987
1092
  version = FunctionVersion(
988
1093
  id=arn,
989
1094
  config=VersionFunctionConfiguration(
@@ -992,7 +1097,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
992
1097
  role=request["Role"],
993
1098
  timeout=request.get("Timeout", LAMBDA_DEFAULT_TIMEOUT),
994
1099
  runtime=request.get("Runtime"),
995
- memory_size=request.get("MemorySize", LAMBDA_DEFAULT_MEMORY_SIZE),
1100
+ memory_size=memory_size,
996
1101
  handler=request.get("Handler"),
997
1102
  package_type=package_type,
998
1103
  environment=env_vars,
@@ -1008,10 +1113,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1008
1113
  ephemeral_storage=LambdaEphemeralStorage(
1009
1114
  size=request.get("EphemeralStorage", {}).get("Size", 512)
1010
1115
  ),
1011
- snap_start=SnapStartResponse(
1012
- ApplyOn=request.get("SnapStart", {}).get("ApplyOn", SnapStartApplyOn.None_),
1013
- OptimizationStatus=SnapStartOptimizationStatus.Off,
1014
- ),
1116
+ snap_start=snap_start,
1015
1117
  runtime_version_config=runtime_version_config,
1016
1118
  dead_letter_arn=request.get("DeadLetterConfig", {}).get("TargetArn"),
1017
1119
  vpc_config=self._build_vpc_config(
@@ -1023,9 +1125,22 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1023
1125
  reason="The function is being created.",
1024
1126
  ),
1025
1127
  logging_config=logging_config,
1128
+ # TODO: might need something like **optional_kwargs if None
1129
+ # -> Test with regular GetFunction (i.e., without a capacity provider)
1130
+ CapacityProviderConfig=capacity_provider_config,
1026
1131
  ),
1027
1132
  )
1028
- fn.versions["$LATEST"] = version
1133
+ version_post_response = None
1134
+ if capacity_provider_config:
1135
+ version_post_response = dataclasses.replace(
1136
+ version,
1137
+ config=dataclasses.replace(
1138
+ version.config,
1139
+ last_update=UpdateStatus(status=LastUpdateStatus.Successful),
1140
+ state=VersionState(state=State.ActiveNonInvocable),
1141
+ ),
1142
+ )
1143
+ fn.versions["$LATEST"] = version_post_response or version
1029
1144
  state.functions[function_name] = fn
1030
1145
  function_counter.labels(
1031
1146
  operation=FunctionOperation.create,
@@ -1034,7 +1149,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1034
1149
  invocation_type="n/a",
1035
1150
  package_type=package_type,
1036
1151
  )
1037
- self.lambda_service.create_function_version(version)
1152
+ # TODO: consider potential other side effects of not having a function version for $LATEST
1153
+ # Provisioning happens upon publishing for functions using a capacity provider
1154
+ if not capacity_provider_config:
1155
+ self.lambda_service.create_function_version(version)
1038
1156
 
1039
1157
  if tags := request.get("Tags"):
1040
1158
  # This will check whether the function exists.
@@ -1042,7 +1160,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1042
1160
 
1043
1161
  if request.get("Publish"):
1044
1162
  version = self._publish_version_with_changes(
1045
- function_name=function_name, region=context_region, account_id=context_account_id
1163
+ function_name=function_name,
1164
+ region=context_region,
1165
+ account_id=context_account_id,
1166
+ publish_to=request.get("PublishTo"),
1046
1167
  )
1047
1168
 
1048
1169
  if config.LAMBDA_SYNCHRONOUS_CREATE:
@@ -1051,7 +1172,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1051
1172
  lambda: get_function_version(
1052
1173
  function_name, version.id.qualifier, version.id.account, version.id.region
1053
1174
  ).config.state.state
1054
- in [State.Active, State.Failed],
1175
+ in [State.Active, State.ActiveNonInvocable, State.Failed],
1055
1176
  timeout=10,
1056
1177
  ):
1057
1178
  LOG.warning(
@@ -1327,7 +1448,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1327
1448
  code = None
1328
1449
  image = create_image_code(image_uri=image)
1329
1450
  else:
1330
- raise LambdaServiceException("Gotta have s3 bucket or zip file or image")
1451
+ raise LambdaServiceException("A ZIP file, S3 bucket, or image is required")
1331
1452
 
1332
1453
  old_function_version = function.versions.get("$LATEST")
1333
1454
  replace_kwargs = {"code": code} if code else {"image": image}
@@ -1365,7 +1486,12 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1365
1486
  self.lambda_service.update_version(new_version=function_version)
1366
1487
  if request.get("Publish"):
1367
1488
  function_version = self._publish_version_with_changes(
1368
- function_name=function_name, region=region, account_id=account_id
1489
+ function_name=function_name,
1490
+ region=region,
1491
+ account_id=account_id,
1492
+ # TODO: validations for PublishTo without Publish=True
1493
+ publish_to=request.get("PublishTo"),
1494
+ is_active=True,
1369
1495
  )
1370
1496
  return api_utils.map_config_out(
1371
1497
  function_version, return_qualified_arn=bool(request.get("Publish"))
@@ -1380,10 +1506,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1380
1506
  def delete_function(
1381
1507
  self,
1382
1508
  context: RequestContext,
1383
- function_name: FunctionName,
1384
- qualifier: Qualifier = None,
1509
+ function_name: NamespacedFunctionName,
1510
+ qualifier: NumericLatestPublishedOrAliasQualifier | None = None,
1385
1511
  **kwargs,
1386
- ) -> None:
1512
+ ) -> DeleteFunctionResponse:
1387
1513
  account_id, region = api_utils.get_account_and_region(function_name, context)
1388
1514
  function_name, qualifier = api_utils.get_name_and_qualifier(
1389
1515
  function_name, qualifier, context
@@ -1409,10 +1535,13 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1409
1535
  raise e
1410
1536
  function = store.functions.get(function_name)
1411
1537
 
1538
+ function_has_capacity_provider = False
1412
1539
  if qualifier:
1413
1540
  # delete a version of the function
1414
1541
  version = function.versions.pop(qualifier, None)
1415
1542
  if version:
1543
+ if version.config.CapacityProviderConfig:
1544
+ function_has_capacity_provider = True
1416
1545
  self.lambda_service.stop_version(version.id.qualified_arn())
1417
1546
  destroy_code_if_not_used(code=version.config.code, function=function)
1418
1547
  else:
@@ -1421,11 +1550,20 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1421
1550
  # the old version gets cleaned up in the internal lambda service.
1422
1551
  function = store.functions.pop(function_name)
1423
1552
  for version in function.versions.values():
1424
- self.lambda_service.stop_version(qualified_arn=version.id.qualified_arn())
1553
+ # Functions with a capacity provider do NOT have a version manager for $LATEST because only
1554
+ # published versions are invokable.
1555
+ if version.config.CapacityProviderConfig:
1556
+ function_has_capacity_provider = True
1557
+ if version.id.qualifier == "$LATEST":
1558
+ pass
1559
+ else:
1560
+ self.lambda_service.stop_version(qualified_arn=version.id.qualified_arn())
1425
1561
  # we can safely destroy the code here
1426
1562
  if version.config.code:
1427
1563
  version.config.code.destroy()
1428
1564
 
1565
+ return DeleteFunctionResponse(StatusCode=202 if function_has_capacity_provider else 204)
1566
+
1429
1567
  def list_functions(
1430
1568
  self,
1431
1569
  context: RequestContext,
@@ -1469,7 +1607,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1469
1607
  self,
1470
1608
  context: RequestContext,
1471
1609
  function_name: NamespacedFunctionName,
1472
- qualifier: Qualifier = None,
1610
+ qualifier: NumericLatestPublishedOrAliasQualifier | None = None,
1473
1611
  **kwargs,
1474
1612
  ) -> GetFunctionResponse:
1475
1613
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -1540,7 +1678,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1540
1678
  self,
1541
1679
  context: RequestContext,
1542
1680
  function_name: NamespacedFunctionName,
1543
- qualifier: Qualifier = None,
1681
+ qualifier: NumericLatestPublishedOrAliasQualifier | None = None,
1544
1682
  **kwargs,
1545
1683
  ) -> FunctionConfiguration:
1546
1684
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -1560,11 +1698,12 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1560
1698
  self,
1561
1699
  context: RequestContext,
1562
1700
  function_name: NamespacedFunctionName,
1563
- invocation_type: InvocationType = None,
1564
- log_type: LogType = None,
1565
- client_context: String = None,
1566
- payload: IO[Blob] = None,
1567
- qualifier: Qualifier = None,
1701
+ invocation_type: InvocationType | None = None,
1702
+ log_type: LogType | None = None,
1703
+ client_context: String | None = None,
1704
+ payload: IO[Blob] | None = None,
1705
+ qualifier: NumericLatestPublishedOrAliasQualifier | None = None,
1706
+ tenant_id: TenantId | None = None,
1568
1707
  **kwargs,
1569
1708
  ) -> InvocationResponse:
1570
1709
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -1634,9 +1773,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1634
1773
  self,
1635
1774
  context: RequestContext,
1636
1775
  function_name: FunctionName,
1637
- code_sha256: String = None,
1638
- description: Description = None,
1639
- revision_id: String = None,
1776
+ code_sha256: String | None = None,
1777
+ description: Description | None = None,
1778
+ revision_id: String | None = None,
1779
+ publish_to: FunctionVersionLatestPublished | None = None,
1640
1780
  **kwargs,
1641
1781
  ) -> FunctionConfiguration:
1642
1782
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -1648,6 +1788,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1648
1788
  region=region,
1649
1789
  revision_id=revision_id,
1650
1790
  code_sha256=code_sha256,
1791
+ publish_to=publish_to,
1651
1792
  )
1652
1793
  return api_utils.map_config_out(new_version, return_qualified_arn=True)
1653
1794
 
@@ -1706,7 +1847,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1706
1847
  )
1707
1848
  if not api_utils.qualifier_is_version(key):
1708
1849
  raise ValidationException(
1709
- f"1 validation error detected: Value '{{{key}={value}}}' at 'routingConfig.additionalVersionWeights' failed to satisfy constraint: Map keys must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: [0-9]+, Member must not be null]"
1850
+ f"1 validation error detected: Value '{{{key}={value}}}' at 'routingConfig.additionalVersionWeights' failed to satisfy constraint: Map keys must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: [0-9]+]"
1710
1851
  )
1711
1852
 
1712
1853
  # checking if the version in the config exists
@@ -1723,7 +1864,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1723
1864
  context: RequestContext,
1724
1865
  function_name: FunctionName,
1725
1866
  name: Alias,
1726
- function_version: Version,
1867
+ function_version: VersionWithLatestPublished,
1727
1868
  description: Description = None,
1728
1869
  routing_config: AliasRoutingConfiguration = None,
1729
1870
  **kwargs,
@@ -1774,7 +1915,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1774
1915
  self,
1775
1916
  context: RequestContext,
1776
1917
  function_name: FunctionName,
1777
- function_version: Version = None,
1918
+ function_version: VersionWithLatestPublished = None,
1778
1919
  marker: String = None,
1779
1920
  max_items: MaxListItems = None,
1780
1921
  **kwargs,
@@ -1842,7 +1983,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1842
1983
  context: RequestContext,
1843
1984
  function_name: FunctionName,
1844
1985
  name: Alias,
1845
- function_version: Version = None,
1986
+ function_version: VersionWithLatestPublished = None,
1846
1987
  description: Description = None,
1847
1988
  routing_config: AliasRoutingConfiguration = None,
1848
1989
  revision_id: String = None,
@@ -2591,7 +2732,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
2591
2732
  if revision_id != fn_revision_id:
2592
2733
  raise PreconditionFailedException(
2593
2734
  "The Revision Id provided does not match the latest Revision Id. "
2594
- "Call the GetFunction/GetAlias API to retrieve the latest Revision Id",
2735
+ "Call the GetPolicy API to retrieve the latest Revision Id",
2595
2736
  Type="User",
2596
2737
  )
2597
2738
 
@@ -2649,10 +2790,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
2649
2790
  def remove_permission(
2650
2791
  self,
2651
2792
  context: RequestContext,
2652
- function_name: FunctionName,
2793
+ function_name: NamespacedFunctionName,
2653
2794
  statement_id: NamespacedStatementId,
2654
- qualifier: Qualifier = None,
2655
- revision_id: String = None,
2795
+ qualifier: NumericLatestPublishedOrAliasQualifier | None = None,
2796
+ revision_id: String | None = None,
2656
2797
  **kwargs,
2657
2798
  ) -> None:
2658
2799
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -2716,7 +2857,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
2716
2857
  self,
2717
2858
  context: RequestContext,
2718
2859
  function_name: NamespacedFunctionName,
2719
- qualifier: Qualifier = None,
2860
+ qualifier: NumericLatestPublishedOrAliasQualifier | None = None,
2720
2861
  **kwargs,
2721
2862
  ) -> GetPolicyResponse:
2722
2863
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -2758,9 +2899,9 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
2758
2899
  self,
2759
2900
  context: RequestContext,
2760
2901
  allowed_publishers: AllowedPublishers,
2761
- description: Description = None,
2762
- code_signing_policies: CodeSigningPolicies = None,
2763
- tags: Tags = None,
2902
+ description: Description | None = None,
2903
+ code_signing_policies: CodeSigningPolicies | None = None,
2904
+ tags: Tags | None = None,
2764
2905
  **kwargs,
2765
2906
  ) -> CreateCodeSigningConfigResponse:
2766
2907
  account = context.account_id
@@ -2785,7 +2926,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
2785
2926
  self,
2786
2927
  context: RequestContext,
2787
2928
  code_signing_config_arn: CodeSigningConfigArn,
2788
- function_name: FunctionName,
2929
+ function_name: NamespacedFunctionName,
2789
2930
  **kwargs,
2790
2931
  ) -> PutFunctionCodeSigningConfigResponse:
2791
2932
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -2852,7 +2993,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
2852
2993
  return GetCodeSigningConfigResponse(CodeSigningConfig=api_utils.map_csc(csc))
2853
2994
 
2854
2995
  def get_function_code_signing_config(
2855
- self, context: RequestContext, function_name: FunctionName, **kwargs
2996
+ self, context: RequestContext, function_name: NamespacedFunctionName, **kwargs
2856
2997
  ) -> GetFunctionCodeSigningConfigResponse:
2857
2998
  account_id, region = api_utils.get_account_and_region(function_name, context)
2858
2999
  state = lambda_stores[account_id][region]
@@ -2870,7 +3011,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
2870
3011
  return GetFunctionCodeSigningConfigResponse()
2871
3012
 
2872
3013
  def delete_function_code_signing_config(
2873
- self, context: RequestContext, function_name: FunctionName, **kwargs
3014
+ self, context: RequestContext, function_name: NamespacedFunctionName, **kwargs
2874
3015
  ) -> None:
2875
3016
  account_id, region = api_utils.get_account_and_region(function_name, context)
2876
3017
  state = lambda_stores[account_id][region]
@@ -3280,7 +3421,8 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3280
3421
  raise ValidationException(
3281
3422
  "1 validation error detected: Value '"
3282
3423
  + destination_arn
3283
- + r"' at 'destinationConfig.onFailure.destination' failed to satisfy constraint: Member must satisfy regular expression pattern: ^$|arn:(aws[a-zA-Z0-9-]*):([a-zA-Z0-9\-])+:([a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\d{1})?:(\d{12})?:(.*)"
3424
+ + "' at 'destinationConfig.onFailure.destination' failed to satisfy constraint: Member must satisfy regular expression pattern: "
3425
+ + "$|kafka://([^.]([a-zA-Z0-9\\-_.]{0,248}))|arn:(aws[a-zA-Z0-9-]*):([a-zA-Z0-9\\-])+:((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1})?:(\\d{12})?:(.*)"
3284
3426
  )
3285
3427
 
3286
3428
  match destination_arn.split(":")[2]:
@@ -3330,7 +3472,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3330
3472
  self,
3331
3473
  context: RequestContext,
3332
3474
  function_name: FunctionName,
3333
- qualifier: Qualifier = None,
3475
+ qualifier: NumericLatestPublishedOrAliasQualifier = None,
3334
3476
  maximum_retry_attempts: MaximumRetryAttempts = None,
3335
3477
  maximum_event_age_in_seconds: MaximumEventAgeInSeconds = None,
3336
3478
  destination_config: DestinationConfig = None,
@@ -3412,7 +3554,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3412
3554
  self,
3413
3555
  context: RequestContext,
3414
3556
  function_name: FunctionName,
3415
- qualifier: Qualifier = None,
3557
+ qualifier: NumericLatestPublishedOrAliasQualifier | None = None,
3416
3558
  **kwargs,
3417
3559
  ) -> FunctionEventInvokeConfig:
3418
3560
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -3489,7 +3631,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3489
3631
  self,
3490
3632
  context: RequestContext,
3491
3633
  function_name: FunctionName,
3492
- qualifier: Qualifier = None,
3634
+ qualifier: NumericLatestPublishedOrAliasQualifier | None = None,
3493
3635
  **kwargs,
3494
3636
  ) -> None:
3495
3637
  account_id, region = api_utils.get_account_and_region(function_name, context)
@@ -3517,7 +3659,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3517
3659
  self,
3518
3660
  context: RequestContext,
3519
3661
  function_name: FunctionName,
3520
- qualifier: Qualifier = None,
3662
+ qualifier: NumericLatestPublishedOrAliasQualifier = None,
3521
3663
  maximum_retry_attempts: MaximumRetryAttempts = None,
3522
3664
  maximum_event_age_in_seconds: MaximumEventAgeInSeconds = None,
3523
3665
  destination_config: DestinationConfig = None,
@@ -3608,10 +3750,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3608
3750
  context: RequestContext,
3609
3751
  layer_name: LayerName,
3610
3752
  content: LayerVersionContentInput,
3611
- description: Description = None,
3612
- compatible_runtimes: CompatibleRuntimes = None,
3613
- license_info: LicenseInfo = None,
3614
- compatible_architectures: CompatibleArchitectures = None,
3753
+ description: Description | None = None,
3754
+ compatible_runtimes: CompatibleRuntimes | None = None,
3755
+ license_info: LicenseInfo | None = None,
3756
+ compatible_architectures: CompatibleArchitectures | None = None,
3615
3757
  **kwargs,
3616
3758
  ) -> PublishLayerVersionResponse:
3617
3759
  """
@@ -3749,10 +3891,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3749
3891
  def list_layers(
3750
3892
  self,
3751
3893
  context: RequestContext,
3752
- compatible_runtime: Runtime = None,
3753
- marker: String = None,
3754
- max_items: MaxLayerListItems = None,
3755
- compatible_architecture: Architecture = None,
3894
+ compatible_runtime: Runtime | None = None,
3895
+ marker: String | None = None,
3896
+ max_items: MaxLayerListItems | None = None,
3897
+ compatible_architecture: Architecture | None = None,
3756
3898
  **kwargs,
3757
3899
  ) -> ListLayersResponse:
3758
3900
  validation_errors = []
@@ -3804,10 +3946,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3804
3946
  self,
3805
3947
  context: RequestContext,
3806
3948
  layer_name: LayerName,
3807
- compatible_runtime: Runtime = None,
3808
- marker: String = None,
3809
- max_items: MaxLayerListItems = None,
3810
- compatible_architecture: Architecture = None,
3949
+ compatible_runtime: Runtime | None = None,
3950
+ marker: String | None = None,
3951
+ max_items: MaxLayerListItems | None = None,
3952
+ compatible_architecture: Architecture | None = None,
3811
3953
  **kwargs,
3812
3954
  ) -> ListLayerVersionsResponse:
3813
3955
  validation_errors = api_utils.validate_layer_runtimes_and_architectures(
@@ -4155,7 +4297,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
4155
4297
 
4156
4298
  def fetch_lambda_store_for_tagging(self, resource: TaggableResource) -> LambdaStore:
4157
4299
  """
4158
- Takes a resource ARN for a TaggableResource (Lambda Function, Event Source Mapping, or Code Signing Config) and returns a corresponding
4300
+ Takes a resource ARN for a TaggableResource (Lambda Function, Event Source Mapping, Code Signing Config, or Capacity Provider) and returns a corresponding
4159
4301
  LambdaStore for its region and account.
4160
4302
 
4161
4303
  In addition, this function validates that the ARN is a valid TaggableResource type, and that the TaggableResource exists.
@@ -4190,9 +4332,8 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
4190
4332
  _raise_validation_exception()
4191
4333
 
4192
4334
  resource_type, resource_identifier, *qualifier = parts
4193
- if resource_type not in {"event-source-mapping", "code-signing-config", "function"}:
4194
- _raise_validation_exception()
4195
4335
 
4336
+ # Qualifier validation raises before checking for NotFound
4196
4337
  if qualifier:
4197
4338
  if resource_type == "function":
4198
4339
  raise InvalidParameterValueException(
@@ -4201,15 +4342,18 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
4201
4342
  )
4202
4343
  _raise_validation_exception()
4203
4344
 
4204
- match resource_type:
4205
- case "event-source-mapping":
4206
- self._get_esm(resource_identifier, account_id, region)
4207
- case "code-signing-config":
4208
- raise NotImplementedError("Resource tagging on CSC not yet implemented.")
4209
- case "function":
4210
- self._get_function(
4211
- function_name=resource_identifier, account_id=account_id, region=region
4212
- )
4345
+ if resource_type == "event-source-mapping":
4346
+ self._get_esm(resource_identifier, account_id, region)
4347
+ elif resource_type == "code-signing-config":
4348
+ raise NotImplementedError("Resource tagging on CSC not yet implemented.")
4349
+ elif resource_type == "function":
4350
+ self._get_function(
4351
+ function_name=resource_identifier, account_id=account_id, region=region
4352
+ )
4353
+ elif resource_type == "capacity-provider":
4354
+ self._get_capacity_provider(resource_identifier, account_id, region)
4355
+ else:
4356
+ _raise_validation_exception()
4213
4357
 
4214
4358
  # If no exceptions are raised, assume ARN and referenced resource is valid for tag operations
4215
4359
  return lambda_stores[account_id][region]