qontract-reconcile 0.10.2.dev308__py3-none-any.whl → 0.10.2.dev309__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.
@@ -1,4 +1,6 @@
1
1
  # ruff: noqa: N801
2
+ from __future__ import annotations
3
+
2
4
  import base64
3
5
  import enum
4
6
  import json
@@ -9,7 +11,6 @@ import re
9
11
  import string
10
12
  import tempfile
11
13
  from collections import Counter
12
- from collections.abc import Iterable, Mapping, MutableMapping
13
14
  from dataclasses import dataclass, field
14
15
  from ipaddress import (
15
16
  ip_address,
@@ -18,7 +19,10 @@ from ipaddress import (
18
19
  from json import JSONDecodeError
19
20
  from threading import Lock
20
21
  from typing import (
22
+ TYPE_CHECKING,
21
23
  Any,
24
+ Self,
25
+ TypeAlias,
22
26
  cast,
23
27
  )
24
28
 
@@ -34,12 +38,14 @@ from terrascript import (
34
38
  Backend,
35
39
  Block,
36
40
  Data,
41
+ Locals,
37
42
  Module,
38
43
  Output,
39
44
  Provider,
40
45
  Resource,
41
46
  Terraform,
42
47
  Terrascript,
48
+ Variable,
43
49
  data,
44
50
  provider,
45
51
  )
@@ -143,9 +149,6 @@ import reconcile.utils.aws_helper as awsh
143
149
  from reconcile import queries
144
150
  from reconcile.cli import TERRAFORM_VERSION
145
151
  from reconcile.github_org import get_default_config
146
- from reconcile.gql_definitions.fragments.aws_vpc_request import (
147
- VPCRequest,
148
- )
149
152
  from reconcile.gql_definitions.terraform_resources.terraform_resources_namespaces import (
150
153
  NamespaceTerraformResourceLifecycleV1,
151
154
  )
@@ -168,10 +171,6 @@ from reconcile.utils.exceptions import (
168
171
  FetchResourceError,
169
172
  PrintToFileInGitRepositoryError,
170
173
  )
171
- from reconcile.utils.external_resource_spec import (
172
- ExternalResourceSpec,
173
- ExternalResourceSpecInventory,
174
- )
175
174
  from reconcile.utils.external_resources import (
176
175
  PROVIDER_AWS,
177
176
  get_external_resource_specs,
@@ -180,7 +179,6 @@ from reconcile.utils.git import is_file_in_git_repo
180
179
  from reconcile.utils.gitlab_api import GitLabApi
181
180
  from reconcile.utils.jenkins_api import JenkinsApi
182
181
  from reconcile.utils.jinja2.utils import process_extracurlyjinja2_template
183
- from reconcile.utils.ocm import OCMMap
184
182
  from reconcile.utils.password_validator import (
185
183
  PasswordPolicy,
186
184
  PasswordValidator,
@@ -189,6 +187,25 @@ from reconcile.utils.secret_reader import SecretReader, SecretReaderBase
189
187
  from reconcile.utils.terraform import safe_resource_id
190
188
  from reconcile.utils.vcs import VCS
191
189
 
190
+ if TYPE_CHECKING:
191
+ from collections.abc import Iterable, Mapping, MutableMapping
192
+
193
+ from reconcile.gql_definitions.fragments.aws_vpc_request import (
194
+ VPCRequest,
195
+ )
196
+ from reconcile.terraform_tgw_attachments import DesiredStateItem
197
+ from reconcile.terraform_users import Role
198
+ from reconcile.utils.external_resource_spec import (
199
+ ExternalResourceSpec,
200
+ ExternalResourceSpecInventory,
201
+ )
202
+ from reconcile.utils.ocm import OCMMap
203
+
204
+
205
+ TFResource: TypeAlias = type[
206
+ Resource | Data | Module | Provider | Variable | Output | Locals | Terraform
207
+ ]
208
+
192
209
  GH_BASE_URL = os.environ.get("GITHUB_API", "https://api.github.com")
193
210
  ROSA_AUTH_LOGTOES_RELEASE = "repos/app-sre/logs-to-elasticsearch-lambda/releases/latest"
194
211
  ROSA_AUTH_KINESIS_TO_OS_RELEASE = (
@@ -306,7 +323,7 @@ AWS_US_GOV_ELB_ACCOUNT_IDS = {
306
323
 
307
324
 
308
325
  class OutputResourceNameNotUniqueError(Exception):
309
- def __init__(self, namespace, duplicates):
326
+ def __init__(self, namespace: str | None, duplicates: Iterable[str]) -> None:
310
327
  self.namespace, self.duplicates = namespace, duplicates
311
328
  super().__init__(
312
329
  str.format(
@@ -326,7 +343,7 @@ class StateInaccessibleError(Exception):
326
343
 
327
344
 
328
345
  class UnknownProviderError(Exception):
329
- def __init__(self, msg):
346
+ def __init__(self, msg: str) -> None:
330
347
  super().__init__("unknown provider error: " + str(msg))
331
348
 
332
349
 
@@ -453,9 +470,9 @@ class TerrascriptClient:
453
470
  integration: str,
454
471
  integration_prefix: str,
455
472
  thread_pool_size: int,
456
- accounts: Iterable[dict[str, Any]],
473
+ accounts: Iterable[MutableMapping[str, Any]],
457
474
  settings: Mapping[str, Any] | None = None,
458
- prefetch_resources_by_schemas: list[str] | None = None,
475
+ prefetch_resources_by_schemas: Iterable[str] | None = None,
459
476
  secret_reader: SecretReaderBase | None = None,
460
477
  ) -> None:
461
478
  self.integration = integration
@@ -541,10 +558,10 @@ class TerrascriptClient:
541
558
  self.accounts = {a["name"]: a for a in filtered_accounts}
542
559
  self.uids = {a["name"]: a["uid"] for a in filtered_accounts}
543
560
  # default_regions info is needed in populate_tf_resource_rds, even in disabled accounts
544
- self.default_regions = {
561
+ self.default_regions: dict[str, str] = {
545
562
  a["name"]: a["resourcesDefaultRegion"] for a in accounts
546
563
  }
547
- self.partitions = {
564
+ self.partitions: dict[str, str] = {
548
565
  a["name"]: a.get("partition") or "aws" for a in filtered_accounts
549
566
  }
550
567
  self.rosa_auth_logtoes_zip = ""
@@ -566,19 +583,19 @@ class TerrascriptClient:
566
583
  for schema in prefetch_resources_by_schemas:
567
584
  self._resource_cache.update(self.prefetch_resources(schema))
568
585
 
569
- def __enter__(self):
586
+ def __enter__(self) -> Self:
570
587
  return self
571
588
 
572
- def __exit__(self, *exc):
589
+ def __exit__(self, *exc: Any) -> None:
573
590
  self.cleanup()
574
591
 
575
- def cleanup(self):
592
+ def cleanup(self) -> None:
576
593
  if self.gitlab is not None:
577
594
  self.gitlab.cleanup()
578
595
 
579
596
  @staticmethod
580
597
  def state_bucket_for_account(
581
- integration: str, account_name: str, config: dict[str, Any]
598
+ integration: str, account_name: str, config: Mapping[str, Any]
582
599
  ) -> Backend:
583
600
  # creds
584
601
  access_key_backend_value = config["aws_access_key_id"]
@@ -643,7 +660,7 @@ class TerrascriptClient:
643
660
  f.write(r.content)
644
661
  return zip_file
645
662
 
646
- def get_logtoes_zip(self, release_url):
663
+ def get_logtoes_zip(self, release_url: str) -> str:
647
664
  if not self.rosa_auth_logtoes_zip:
648
665
  with self.rosa_auth_logtoes_zip_lock:
649
666
  # this may have already happened, so we check again
@@ -656,7 +673,7 @@ class TerrascriptClient:
656
673
  return self.rosa_auth_logtoes_zip
657
674
  return self.download_logtoes_zip(release_url)
658
675
 
659
- def download_logtoes_zip(self, release_url):
676
+ def download_logtoes_zip(self, release_url: str) -> str:
660
677
  headers = {"Authorization": "token " + self.token}
661
678
  r = requests.get(GH_BASE_URL + "/" + release_url, headers=headers, timeout=60)
662
679
  r.raise_for_status()
@@ -670,7 +687,7 @@ class TerrascriptClient:
670
687
  f.write(r.content)
671
688
  return zip_file
672
689
 
673
- def get_rosa_auth_pre_signup_zip(self, release_url):
690
+ def get_rosa_auth_pre_signup_zip(self, release_url: str) -> str:
674
691
  if not self.rosa_auth_pre_signup_zip:
675
692
  with self.rosa_auth_pre_signup_zip_lock:
676
693
  # this may have already happened, so we check again
@@ -685,7 +702,7 @@ class TerrascriptClient:
685
702
  return self.rosa_auth_pre_signup_zip
686
703
  return self.download_rosa_auth_pre_signup_zip(release_url)
687
704
 
688
- def download_rosa_auth_pre_signup_zip(self, release_url):
705
+ def download_rosa_auth_pre_signup_zip(self, release_url: str) -> str:
689
706
  headers = {"Authorization": "token " + self.token}
690
707
  r = requests.get(GH_BASE_URL + "/" + release_url, headers=headers, timeout=60)
691
708
  r.raise_for_status()
@@ -699,7 +716,7 @@ class TerrascriptClient:
699
716
  f.write(r.content)
700
717
  return zip_file
701
718
 
702
- def get_rosa_auth_pre_token_zip(self, release_url):
719
+ def get_rosa_auth_pre_token_zip(self, release_url: str) -> str:
703
720
  if not self.rosa_auth_pre_token_zip:
704
721
  with self.rosa_auth_pre_token_zip_lock:
705
722
  # this may have already happened, so we check again
@@ -714,7 +731,7 @@ class TerrascriptClient:
714
731
  return self.rosa_auth_pre_token_zip
715
732
  return self.download_rosa_auth_pre_token_zip(release_url)
716
733
 
717
- def download_rosa_auth_pre_token_zip(self, release_url):
734
+ def download_rosa_auth_pre_token_zip(self, release_url: str) -> str:
718
735
  headers = {"Authorization": "token " + self.token}
719
736
  r = requests.get(GH_BASE_URL + "/" + release_url, headers=headers, timeout=60)
720
737
  r.raise_for_status()
@@ -744,7 +761,7 @@ class TerrascriptClient:
744
761
  self.gitlab = GitLabApi(instance, secret_reader=self.secret_reader)
745
762
  return self.gitlab
746
763
 
747
- def init_jenkins(self, instance: dict) -> JenkinsApi:
764
+ def init_jenkins(self, instance: Mapping[str, Any]) -> JenkinsApi:
748
765
  instance_name = instance["name"]
749
766
  if not self.jenkins_map.get(instance_name):
750
767
  with self.jenkins_lock:
@@ -758,8 +775,8 @@ class TerrascriptClient:
758
775
  return self.jenkins_map[instance_name]
759
776
 
760
777
  def filter_disabled_accounts(
761
- self, accounts: Iterable[dict[str, Any]]
762
- ) -> list[dict[str, Any]]:
778
+ self, accounts: Iterable[MutableMapping[str, Any]]
779
+ ) -> list[MutableMapping[str, Any]]:
763
780
  filtered_accounts = []
764
781
  for account in accounts:
765
782
  integration = self.integration.replace("_", "-")
@@ -767,7 +784,7 @@ class TerrascriptClient:
767
784
  filtered_accounts.append(account)
768
785
  return filtered_accounts
769
786
 
770
- def populate_configs(self, accounts: Iterable[awsh.Account]):
787
+ def populate_configs(self, accounts: Iterable[awsh.Account]) -> None:
771
788
  results = threaded.run(
772
789
  awsh.get_tf_secrets,
773
790
  accounts,
@@ -781,14 +798,14 @@ class TerrascriptClient:
781
798
  config["terraformState"] = account["terraformState"]
782
799
  self.configs[account_name] = config
783
800
 
784
- def _get_partition(self, account):
801
+ def _get_partition(self, account: str) -> str:
785
802
  return self.partitions.get(account) or "aws"
786
803
 
787
804
  @staticmethod
788
- def get_tf_iam_group(group_name):
805
+ def get_tf_iam_group(group_name: str) -> aws_iam_group:
789
806
  return aws_iam_group(group_name, name=group_name)
790
807
 
791
- def get_tf_iam_user(self, user_name):
808
+ def get_tf_iam_user(self, user_name: str) -> aws_iam_user:
792
809
  return aws_iam_user(
793
810
  user_name,
794
811
  name=user_name,
@@ -796,8 +813,8 @@ class TerrascriptClient:
796
813
  tags={"managed_by_integration": self.integration},
797
814
  )
798
815
 
799
- def populate_iam_groups(self, roles):
800
- groups = {}
816
+ def populate_iam_groups(self, roles: Iterable[Role]) -> dict[str, dict[str, str]]:
817
+ groups: dict[str, dict[str, str]] = {}
801
818
  for role in roles:
802
819
  users = role["users"]
803
820
  if len(users) == 0:
@@ -840,7 +857,7 @@ class TerrascriptClient:
840
857
  return groups
841
858
 
842
859
  @staticmethod
843
- def _get_aws_username(user):
860
+ def _get_aws_username(user: Mapping[str, str]) -> str:
844
861
  return user.get("aws_username") or user["org_username"]
845
862
 
846
863
  @staticmethod
@@ -865,10 +882,10 @@ class TerrascriptClient:
865
882
 
866
883
  def populate_iam_users(
867
884
  self,
868
- roles,
869
- skip_reencrypt_accounts: list[str],
885
+ roles: Iterable[Role],
886
+ skip_reencrypt_accounts: Iterable[str],
870
887
  appsre_pgp_key: str | None,
871
- ):
888
+ ) -> bool:
872
889
  error = False
873
890
  for role in roles:
874
891
  users = role["users"]
@@ -997,10 +1014,10 @@ class TerrascriptClient:
997
1014
 
998
1015
  def populate_users(
999
1016
  self,
1000
- roles,
1001
- skip_reencrypt_accounts: list[str],
1017
+ roles: Iterable[Role],
1018
+ skip_reencrypt_accounts: Iterable[str],
1002
1019
  appsre_pgp_key: str | None = None,
1003
- ):
1020
+ ) -> bool:
1004
1021
  self.populate_iam_groups(roles)
1005
1022
  err = self.populate_iam_users(
1006
1023
  roles,
@@ -1019,7 +1036,7 @@ class TerrascriptClient:
1019
1036
 
1020
1037
  @staticmethod
1021
1038
  def get_resource_lifecycle(
1022
- common_values: dict[str, Any],
1039
+ common_values: Mapping[str, Any],
1023
1040
  ) -> dict[str, Any] | None:
1024
1041
  if lifecycle := common_values.get("lifecycle"):
1025
1042
  lifecycle = NamespaceTerraformResourceLifecycleV1(**lifecycle)
@@ -1036,7 +1053,9 @@ class TerrascriptClient:
1036
1053
  return lifecycle.dict(by_alias=True) | {"ignore_changes": ignore_changes}
1037
1054
  return None
1038
1055
 
1039
- def populate_additional_providers(self, infra_account_name: str, accounts):
1056
+ def populate_additional_providers(
1057
+ self, infra_account_name: str, accounts: Iterable[Mapping[str, Any]]
1058
+ ) -> None:
1040
1059
  for account in accounts:
1041
1060
  account_name = account["name"]
1042
1061
  assume_role = account.get("assume_role")
@@ -1067,7 +1086,7 @@ class TerrascriptClient:
1067
1086
  )
1068
1087
 
1069
1088
  def populate_route53(
1070
- self, desired_state: Iterable[dict[str, Any]], default_ttl: int = 300
1089
+ self, desired_state: Iterable[Mapping[str, Any]], default_ttl: int = 300
1071
1090
  ) -> None:
1072
1091
  for zone in desired_state:
1073
1092
  acct_name = zone["account_name"]
@@ -1086,10 +1105,10 @@ class TerrascriptClient:
1086
1105
  def populate_route53_records(
1087
1106
  self,
1088
1107
  acct_name: str,
1089
- zone: dict[str, Any],
1108
+ zone: Mapping[str, Any],
1090
1109
  zone_resource: aws_route53_zone,
1091
1110
  default_ttl: int = 300,
1092
- ):
1111
+ ) -> None:
1093
1112
  counts = {}
1094
1113
  for record in zone.get("records") or []:
1095
1114
  record_fqdn = f"{record['name']}.{zone['name']}"
@@ -1166,7 +1185,7 @@ class TerrascriptClient:
1166
1185
  record_resource = aws_route53_record(record_id, **record_values)
1167
1186
  self.add_resource(acct_name, record_resource)
1168
1187
 
1169
- def populate_vpc_peerings(self, desired_state):
1188
+ def populate_vpc_peerings(self, desired_state: Iterable[Mapping[str, Any]]) -> None:
1170
1189
  for item in desired_state:
1171
1190
  if item["deleted"]:
1172
1191
  continue
@@ -1187,7 +1206,7 @@ class TerrascriptClient:
1187
1206
 
1188
1207
  # Requester's side of the connection - the cluster's account
1189
1208
  identifier = f"{requester['vpc_id']}-{accepter['vpc_id']}"
1190
- values = {
1209
+ values: dict[str, Any] = {
1191
1210
  # adding the alias to the provider will add this resource
1192
1211
  # to the cluster's AWS account
1193
1212
  "provider": "aws." + req_alias,
@@ -1381,7 +1400,9 @@ class TerrascriptClient:
1381
1400
  )
1382
1401
  self.add_resource(aws_account, public_subnets_output)
1383
1402
 
1384
- def populate_tgw_attachments(self, desired_state):
1403
+ def populate_tgw_attachments(
1404
+ self, desired_state: Iterable[DesiredStateItem]
1405
+ ) -> None:
1385
1406
  for item in desired_state:
1386
1407
  if item.deleted:
1387
1408
  continue
@@ -1404,30 +1425,32 @@ class TerrascriptClient:
1404
1425
 
1405
1426
  tags = {"managed_by_integration": self.integration, "Name": connection_name}
1406
1427
  # add resource share
1407
- values = {
1428
+ values_share: dict[str, Any] = {
1408
1429
  "name": connection_name,
1409
1430
  "allow_external_principals": True,
1410
1431
  "tags": tags,
1411
1432
  }
1412
1433
  if self._multiregion_account(req_account_name):
1413
- values["provider"] = "aws." + requester.region
1414
- tf_resource_share = aws_ram_resource_share(connection_name, **values)
1434
+ values_share["provider"] = "aws." + requester.region
1435
+ tf_resource_share = aws_ram_resource_share(connection_name, **values_share)
1415
1436
  self.add_resource(infra_account_name, tf_resource_share)
1416
1437
 
1417
1438
  # share with accepter aws account
1418
- values = {
1439
+ values_resource_principal_association: dict[str, str] = {
1419
1440
  "principal": acc_uid,
1420
1441
  "resource_share_arn": "${" + tf_resource_share.arn + "}",
1421
1442
  }
1422
1443
  if self._multiregion_account(req_account_name):
1423
- values["provider"] = "aws." + requester.region
1424
- tf_resource_association = aws_ram_principal_association(
1425
- connection_name, **values
1444
+ values_resource_principal_association["provider"] = (
1445
+ "aws." + requester.region
1446
+ )
1447
+ tf_resource_principal_association = aws_ram_principal_association(
1448
+ connection_name, **values_resource_principal_association
1426
1449
  )
1427
- self.add_resource(infra_account_name, tf_resource_association)
1450
+ self.add_resource(infra_account_name, tf_resource_principal_association)
1428
1451
 
1429
1452
  # accept resource share from accepter aws account
1430
- values = {
1453
+ values_share_resource_accepter: dict[str, Any] = {
1431
1454
  "provider": "aws." + acc_alias,
1432
1455
  "share_arn": "${" + tf_resource_share.arn + "}",
1433
1456
  "depends_on": [
@@ -1436,7 +1459,7 @@ class TerrascriptClient:
1436
1459
  ],
1437
1460
  }
1438
1461
  tf_resource_share_accepter = aws_ram_resource_share_accepter(
1439
- connection_name, **values
1462
+ connection_name, **values_share_resource_accepter
1440
1463
  )
1441
1464
  self.add_resource(infra_account_name, tf_resource_share_accepter)
1442
1465
 
@@ -1446,20 +1469,23 @@ class TerrascriptClient:
1446
1469
 
1447
1470
  # tgw share association
1448
1471
  identifier = f"{requester.tgw_id}-{accepter.vpc_id}"
1449
- values = {
1472
+ values_resource_association: dict[str, str] = {
1450
1473
  "resource_arn": requester.tgw_arn,
1451
1474
  "resource_share_arn": "${" + tf_resource_share.arn + "}",
1452
1475
  }
1453
1476
  if self._multiregion_account(req_account_name):
1454
- values["provider"] = "aws." + requester.region
1455
- tf_resource_association = aws_ram_resource_association(identifier, **values)
1477
+ values_resource_association["provider"] = "aws." + requester.region
1478
+ tf_resource_association = aws_ram_resource_association(
1479
+ identifier, **values_resource_association
1480
+ )
1456
1481
  self.add_resource(infra_account_name, tf_resource_association)
1457
1482
 
1458
1483
  # now that the tgw is shared to the cluster's aws account
1459
1484
  # we can create a vpc attachment to the tgw
1460
1485
  subnets_id_az = accepter.subnets_id_az
1486
+ assert subnets_id_az is not None # make mypy happy
1461
1487
  subnets = self.get_az_unique_subnet_ids(subnets_id_az)
1462
- values = {
1488
+ values_resource_attachment: dict[str, Any] = {
1463
1489
  "provider": "aws." + acc_alias,
1464
1490
  "subnet_ids": subnets,
1465
1491
  "transit_gateway_id": requester.tgw_id,
@@ -1471,20 +1497,22 @@ class TerrascriptClient:
1471
1497
  "tags": tags,
1472
1498
  }
1473
1499
  tf_resource_attachment = aws_ec2_transit_gateway_vpc_attachment(
1474
- identifier, **values
1500
+ identifier, **values_resource_attachment
1475
1501
  )
1476
1502
  # we send the attachment from the cluster's aws account
1477
1503
  self.add_resource(infra_account_name, tf_resource_attachment)
1478
1504
 
1479
1505
  # and accept the attachment in the non cluster's aws account
1480
- values = {
1506
+ values_attachment_accepter = {
1481
1507
  "transit_gateway_attachment_id": "${" + tf_resource_attachment.id + "}",
1482
1508
  "tags": tags,
1483
1509
  }
1484
1510
  if self._multiregion_account(req_account_name):
1485
- values["provider"] = "aws." + requester.region
1511
+ values_attachment_accepter["provider"] = "aws." + requester.region
1486
1512
  tf_resource_attachment_accepter = (
1487
- aws_ec2_transit_gateway_vpc_attachment_accepter(identifier, **values)
1513
+ aws_ec2_transit_gateway_vpc_attachment_accepter(
1514
+ identifier, **values_attachment_accepter
1515
+ )
1488
1516
  )
1489
1517
  self.add_resource(infra_account_name, tf_resource_attachment_accepter)
1490
1518
 
@@ -1530,16 +1558,16 @@ class TerrascriptClient:
1530
1558
  + f"unsupported region: {route_region}"
1531
1559
  )
1532
1560
  continue
1533
- values = {
1561
+ values_gateway_router = {
1534
1562
  "destination_cidr_block": route["cidr_block"],
1535
1563
  "transit_gateway_attachment_id": route["tgw_attachment_id"],
1536
1564
  "transit_gateway_route_table_id": route["tgw_route_table_id"],
1537
1565
  }
1538
1566
  if self._multiregion_account(req_account_name):
1539
- values["provider"] = "aws." + route_region
1567
+ values_gateway_router["provider"] = "aws." + route_region
1540
1568
  route_identifier = f"{identifier}-{route['tgw_id']}"
1541
1569
  tf_resource = aws_ec2_transit_gateway_route(
1542
- route_identifier, **values
1570
+ route_identifier, **values_gateway_router
1543
1571
  )
1544
1572
  self.add_resource(infra_account_name, tf_resource)
1545
1573
 
@@ -1569,7 +1597,7 @@ class TerrascriptClient:
1569
1597
  + f"unsupported region: {rule_region}"
1570
1598
  )
1571
1599
  continue
1572
- values = {
1600
+ values_rule = {
1573
1601
  "type": "ingress",
1574
1602
  "from_port": 0,
1575
1603
  "to_port": 0,
@@ -1578,31 +1606,37 @@ class TerrascriptClient:
1578
1606
  "security_group_id": rule["security_group_id"],
1579
1607
  }
1580
1608
  if self._multiregion_account(req_account_name):
1581
- values["provider"] = "aws." + rule_region
1609
+ values_rule["provider"] = "aws." + rule_region
1582
1610
  rule_identifier = f"{identifier}-{rule['vpc_id']}"
1583
- tf_resource = aws_security_group_rule(rule_identifier, **values)
1611
+ tf_resource = aws_security_group_rule(
1612
+ rule_identifier, **values_rule
1613
+ )
1584
1614
  self.add_resource(infra_account_name, tf_resource)
1585
1615
 
1586
1616
  for zone in requester.hostedzones or []:
1587
1617
  id = f"{identifier}-{zone}"
1588
- values = {
1618
+ values_authorization = {
1589
1619
  "vpc_id": accepter.vpc_id,
1590
1620
  "vpc_region": accepter.region,
1591
1621
  "zone_id": zone,
1592
1622
  }
1593
- authorization = aws_route53_vpc_association_authorization(id, **values)
1623
+ authorization = aws_route53_vpc_association_authorization(
1624
+ id, **values_authorization
1625
+ )
1594
1626
  self.add_resource(infra_account_name, authorization)
1595
- values = {
1627
+ values_association = {
1596
1628
  "provider": "aws." + acc_alias,
1597
1629
  "vpc_id": f"${{aws_route53_vpc_association_authorization.{id}.vpc_id}}",
1598
1630
  "vpc_region": accepter.region,
1599
1631
  "zone_id": f"${{aws_route53_vpc_association_authorization.{id}.zone_id}}",
1600
1632
  }
1601
- association = aws_route53_zone_association(id, **values)
1633
+ association = aws_route53_zone_association(id, **values_association)
1602
1634
  self.add_resource(infra_account_name, association)
1603
1635
 
1604
1636
  @staticmethod
1605
- def get_az_unique_subnet_ids(subnets_id_az):
1637
+ def get_az_unique_subnet_ids(
1638
+ subnets_id_az: Iterable[Mapping[str, str]],
1639
+ ) -> list[str]:
1606
1640
  """returns a list of subnet ids which are unique per az"""
1607
1641
  results = []
1608
1642
  azs = []
@@ -1710,7 +1744,9 @@ class TerrascriptClient:
1710
1744
 
1711
1745
  self.resource_spec_inventory[spec.id_object()] = spec
1712
1746
 
1713
- def populate_tf_resources(self, spec, ocm_map=None):
1747
+ def populate_tf_resources(
1748
+ self, spec: ExternalResourceSpec, ocm_map: OCMMap | None = None
1749
+ ) -> None:
1714
1750
  if spec.provision_provider != PROVIDER_AWS:
1715
1751
  raise UnknownProviderError(spec.provision_provider)
1716
1752
 
@@ -1769,13 +1805,13 @@ class TerrascriptClient:
1769
1805
  else:
1770
1806
  raise UnknownProviderError(provider)
1771
1807
 
1772
- def populate_tf_resource_rds(self, spec):
1808
+ def populate_tf_resource_rds(self, spec: ExternalResourceSpec) -> None:
1773
1809
  account = spec.provisioner_name
1774
1810
  identifier = spec.identifier
1775
1811
  values = self.init_values(spec)
1776
1812
  output_prefix = spec.output_prefix
1777
1813
 
1778
- tf_resources = []
1814
+ tf_resources: list[TFResource] = []
1779
1815
  self.init_common_outputs(tf_resources, spec)
1780
1816
 
1781
1817
  # we want to allow an empty name, so we
@@ -1804,7 +1840,9 @@ class TerrascriptClient:
1804
1840
  # To get the provider we should use, we get the region
1805
1841
  # and use that as an alias in the provider definition
1806
1842
  if az:
1807
- provider = "aws." + self._region_from_availability_zone(az)
1843
+ region_az = self._region_from_availability_zone(az)
1844
+ assert region_az # make mypy happy
1845
+ provider = "aws." + region_az
1808
1846
  values["provider"] = provider
1809
1847
  if region:
1810
1848
  provider_region = f"aws.{region}"
@@ -1844,7 +1882,7 @@ class TerrascriptClient:
1844
1882
  # 'deps' should contain a list of terraform resource names
1845
1883
  # (not full objects) that must be created
1846
1884
  # before the actual RDS instance should be created
1847
- deps = []
1885
+ deps: list[str] = []
1848
1886
 
1849
1887
  parameter_group = values.pop("parameter_group", None)
1850
1888
  if parameter_group:
@@ -1905,14 +1943,14 @@ class TerrascriptClient:
1905
1943
  role_res_name = self.get_dependencies([role_tf_resource])[0]
1906
1944
  deps.append(role_res_name)
1907
1945
 
1908
- em_values = {
1946
+ em_values_attachment: dict[str, Any] = {
1909
1947
  "role": role_tf_resource.name,
1910
1948
  "policy_arn": f"arn:{self._get_partition(account)}:iam::aws:policy/service-role/"
1911
1949
  + "AmazonRDSEnhancedMonitoringRole",
1912
1950
  "depends_on": self.get_dependencies([role_tf_resource]),
1913
1951
  }
1914
1952
  attachment_tf_resource = aws_iam_role_policy_attachment(
1915
- em_identifier, **em_values
1953
+ em_identifier, **em_values_attachment
1916
1954
  )
1917
1955
  tf_resources.append(attachment_tf_resource)
1918
1956
 
@@ -1930,9 +1968,8 @@ class TerrascriptClient:
1930
1968
  if reset_password:
1931
1969
  password = self.generate_random_password()
1932
1970
  else:
1933
- password = spec.get_secret_field("db.password")
1934
- if not password:
1935
- password = self.generate_random_password()
1971
+ db_password = spec.get_secret_field("db.password")
1972
+ password = db_password or self.generate_random_password()
1936
1973
  else:
1937
1974
  password = ""
1938
1975
  values["password"] = password
@@ -2024,7 +2061,7 @@ class TerrascriptClient:
2024
2061
  # to a provider version with this bug fix.
2025
2062
  # https://github.com/hashicorp/terraform-provider-aws/pull/20926
2026
2063
  if enhanced_monitoring and replica_source:
2027
- sleep_vals = {}
2064
+ sleep_vals: dict[str, Any] = {}
2028
2065
  sleep_vals["depends_on"] = [attachment_res_name]
2029
2066
  sleep_vals["create_duration"] = "30s"
2030
2067
 
@@ -2117,7 +2154,7 @@ class TerrascriptClient:
2117
2154
 
2118
2155
  self.add_resources(account, tf_resources)
2119
2156
 
2120
- def _multiregion_account(self, name):
2157
+ def _multiregion_account(self, name: str) -> bool:
2121
2158
  if name not in self.configs:
2122
2159
  return False
2123
2160
 
@@ -2134,11 +2171,11 @@ class TerrascriptClient:
2134
2171
  return spec
2135
2172
  return None
2136
2173
 
2137
- def _get_db_name_from_values(self, values: dict) -> str:
2174
+ def _get_db_name_from_values(self, values: Mapping[str, Any]) -> str:
2138
2175
  return values.get("name") or values.get("db_name") or ""
2139
2176
 
2140
2177
  @staticmethod
2141
- def _region_from_availability_zone(az):
2178
+ def _region_from_availability_zone(az: str) -> str | None:
2142
2179
  # Find the region by removing the last character from the
2143
2180
  # availability zone. Availability zone is defined like
2144
2181
  # us-east-1a, us-east-1b, etc. If there is no availability
@@ -2148,39 +2185,38 @@ class TerrascriptClient:
2148
2185
  return None
2149
2186
 
2150
2187
  @staticmethod
2151
- def _db_needs_auth(config):
2152
- return bool(
2153
- "replicate_source_db" not in config
2154
- and config.get("replica_source", None) is None
2188
+ def _db_needs_auth(config: Mapping[str, Any]) -> bool:
2189
+ return (
2190
+ "replicate_source_db" not in config and config.get("replica_source") is None
2155
2191
  )
2156
2192
 
2157
2193
  @staticmethod
2158
- def validate_db_name(name):
2194
+ def validate_db_name(name: str) -> bool:
2159
2195
  """Handle for Error creating DB Instance:
2160
2196
  InvalidParameterValue: DBName must begin with a letter
2161
2197
  and contain only alphanumeric characters."""
2162
2198
  pattern = r"^[a-zA-Z][a-zA-Z0-9_]+$"
2163
- return re.search(pattern, name) and len(name) < 64
2199
+ return len(name) < 64 and re.search(pattern, name) is not None
2164
2200
 
2165
2201
  @staticmethod
2166
- def generate_random_password(string_length=20):
2202
+ def generate_random_password(string_length: int = 20) -> str:
2167
2203
  """Generate a random string of letters and digits"""
2168
2204
  letters_and_digits = string.ascii_letters + string.digits
2169
2205
  return "".join(random.choice(letters_and_digits) for i in range(string_length))
2170
2206
 
2171
- def populate_tf_resource_s3(self, spec):
2207
+ def populate_tf_resource_s3(self, spec: ExternalResourceSpec) -> aws_s3_bucket:
2172
2208
  account = spec.provisioner_name
2173
2209
  identifier = spec.identifier
2174
2210
  common_values = self.init_values(spec)
2175
2211
  output_prefix = spec.output_prefix
2176
2212
 
2177
- tf_resources = []
2213
+ tf_resources: list[TFResource] = []
2178
2214
  self.init_common_outputs(tf_resources, spec)
2179
2215
 
2180
2216
  # s3 bucket
2181
2217
  # Terraform resource reference:
2182
2218
  # https://www.terraform.io/docs/providers/aws/r/s3_bucket.html
2183
- values = {}
2219
+ values: dict[str, Any] = {}
2184
2220
  values["bucket"] = identifier
2185
2221
  versioning = common_values.get("versioning", True)
2186
2222
  values["versioning"] = {"enabled": versioning}
@@ -2307,7 +2343,7 @@ class TerrascriptClient:
2307
2343
 
2308
2344
  rc_values.clear()
2309
2345
  rc_values["name"] = config["rule_name"] + "_iam_policy"
2310
- policy = {
2346
+ policy: dict[str, Any] = {
2311
2347
  "Version": "2012-10-17",
2312
2348
  "Statement": [
2313
2349
  {
@@ -2374,6 +2410,7 @@ class TerrascriptClient:
2374
2410
  if len(deps) > 0:
2375
2411
  values["depends_on"] = self.get_dependencies(deps)
2376
2412
  region = common_values.get("region") or self.default_regions.get(account)
2413
+ assert region # make mypy happy
2377
2414
  if self._multiregion_account(account):
2378
2415
  values["provider"] = "aws." + region
2379
2416
  bucket_tf_resource = aws_s3_bucket(identifier, **values)
@@ -2508,10 +2545,12 @@ class TerrascriptClient:
2508
2545
  # https://www.terraform.io/docs/providers/aws/r/iam_access_key.html
2509
2546
 
2510
2547
  # iam user for bucket
2511
- values = {}
2512
- values["name"] = identifier
2513
- values["tags"] = common_values["tags"]
2514
- values["depends_on"] = self.get_dependencies([bucket_tf_resource])
2548
+ values = {
2549
+ "name": identifier,
2550
+ "tags": common_values["tags"],
2551
+ "depends_on": self.get_dependencies([bucket_tf_resource]),
2552
+ }
2553
+
2515
2554
  user_tf_resource = aws_iam_user(identifier, **values)
2516
2555
  tf_resources.append(user_tf_resource)
2517
2556
 
@@ -2521,8 +2560,7 @@ class TerrascriptClient:
2521
2560
  )
2522
2561
 
2523
2562
  # iam user policy for bucket
2524
- values = {}
2525
- values["name"] = identifier
2563
+ values = {"name": identifier}
2526
2564
 
2527
2565
  action = ["s3:*Object*"]
2528
2566
  if common_values.get("acl", "private") == "public-read":
@@ -2566,7 +2604,7 @@ class TerrascriptClient:
2566
2604
 
2567
2605
  return bucket_tf_resource
2568
2606
 
2569
- def populate_tf_resource_elasticache(self, spec):
2607
+ def populate_tf_resource_elasticache(self, spec: ExternalResourceSpec) -> None:
2570
2608
  account = spec.provisioner_name
2571
2609
  identifier = spec.identifier
2572
2610
  values = self.init_values(spec)
@@ -2574,7 +2612,7 @@ class TerrascriptClient:
2574
2612
  values.setdefault("replication_group_id", values["identifier"])
2575
2613
  values.pop("identifier", None)
2576
2614
 
2577
- tf_resources = []
2615
+ tf_resources: list[TFResource] = []
2578
2616
  self.init_common_outputs(tf_resources, spec)
2579
2617
 
2580
2618
  default_region = self.default_regions.get(account)
@@ -2654,19 +2692,23 @@ class TerrascriptClient:
2654
2692
 
2655
2693
  self.add_resources(account, tf_resources)
2656
2694
 
2657
- def populate_tf_resource_service_account(self, spec, ocm_map=None):
2695
+ def populate_tf_resource_service_account(
2696
+ self, spec: ExternalResourceSpec, ocm_map: OCMMap | None = None
2697
+ ) -> None:
2658
2698
  account = spec.provisioner_name
2659
2699
  identifier = spec.identifier
2660
2700
  common_values = self.init_values(spec)
2661
2701
  output_prefix = spec.output_prefix
2662
2702
 
2663
- tf_resources = []
2703
+ tf_resources: list[TFResource] = []
2664
2704
  self.init_common_outputs(tf_resources, spec)
2665
2705
 
2666
2706
  # iam user for bucket
2667
- values = {}
2668
- values["name"] = identifier
2669
- values["tags"] = common_values["tags"]
2707
+ values = {
2708
+ "name": identifier,
2709
+ "tags": common_values["tags"],
2710
+ }
2711
+
2670
2712
  user_tf_resource = aws_iam_user(identifier, **values)
2671
2713
  tf_resources.append(user_tf_resource)
2672
2714
 
@@ -2750,13 +2792,15 @@ class TerrascriptClient:
2750
2792
 
2751
2793
  self.add_resources(account, tf_resources)
2752
2794
 
2753
- def populate_tf_resource_secrets_manager_sa(self, spec):
2795
+ def populate_tf_resource_secrets_manager_sa(
2796
+ self, spec: ExternalResourceSpec
2797
+ ) -> None:
2754
2798
  account = spec.provisioner_name
2755
2799
  identifier = spec.identifier
2756
2800
  common_values = self.init_values(spec)
2757
2801
  output_prefix = spec.output_prefix
2758
2802
 
2759
- tf_resources = []
2803
+ tf_resources: list[TFResource] = []
2760
2804
  self.init_common_outputs(tf_resources, spec)
2761
2805
 
2762
2806
  secrets_prefix = common_values["secrets_prefix"]
@@ -2780,7 +2824,7 @@ class TerrascriptClient:
2780
2824
 
2781
2825
  tf_resources.extend(
2782
2826
  self.get_tf_iam_service_user(
2783
- [], identifier, policy, common_values["tags"], output_prefix
2827
+ None, identifier, policy, common_values["tags"], output_prefix
2784
2828
  )
2785
2829
  )
2786
2830
 
@@ -2790,20 +2834,20 @@ class TerrascriptClient:
2790
2834
 
2791
2835
  self.add_resources(account, tf_resources)
2792
2836
 
2793
- def populate_tf_resource_role(self, spec):
2837
+ def populate_tf_resource_role(self, spec: ExternalResourceSpec) -> None:
2794
2838
  account = spec.provisioner_name
2795
2839
  identifier = spec.identifier
2796
2840
  common_values = self.init_values(spec)
2797
2841
  output_prefix = spec.output_prefix
2798
2842
 
2799
- tf_resources = []
2843
+ tf_resources: list[TFResource] = []
2800
2844
  self.init_common_outputs(tf_resources, spec)
2801
2845
 
2802
2846
  assume_role = common_values["assume_role"]
2803
2847
  assume_role = {k: v for k, v in assume_role.items() if v is not None}
2804
2848
  assume_action = common_values.get("assume_action") or "AssumeRole"
2805
2849
  # assume role policy
2806
- assume_role_policy = {
2850
+ assume_role_policy: dict[str, Any] = {
2807
2851
  "Version": "2012-10-17",
2808
2852
  "Statement": [
2809
2853
  {
@@ -2818,7 +2862,7 @@ class TerrascriptClient:
2818
2862
  assume_role_policy["Statement"][0]["Condition"] = assume_condition
2819
2863
 
2820
2864
  # iam role
2821
- values = {
2865
+ values: dict[str, Any] = {
2822
2866
  "name": identifier,
2823
2867
  "tags": common_values["tags"],
2824
2868
  "assume_role_policy": json.dumps(assume_role_policy),
@@ -2871,7 +2915,9 @@ class TerrascriptClient:
2871
2915
 
2872
2916
  self.add_resources(account, tf_resources)
2873
2917
 
2874
- def populate_iam_policy(self, account: str, name: str, policy: dict[str, Any]):
2918
+ def populate_iam_policy(
2919
+ self, account: str, name: str, policy: Mapping[str, Any]
2920
+ ) -> None:
2875
2921
  tf_aws_iam_policy = aws_iam_policy(
2876
2922
  f"{account}-{name}", name=name, policy=json.dumps(policy)
2877
2923
  )
@@ -2882,8 +2928,8 @@ class TerrascriptClient:
2882
2928
  account: str,
2883
2929
  name: str,
2884
2930
  saml_provider_name: str,
2885
- aws_managed_policies: list[str],
2886
- customer_managed_policies: list[str] | None = None,
2931
+ aws_managed_policies: Iterable[str],
2932
+ customer_managed_policies: Iterable[str] | None = None,
2887
2933
  max_session_duration_hours: int = 1,
2888
2934
  ) -> None:
2889
2935
  """Manage the an IAM role needed for SAML authentication."""
@@ -2921,17 +2967,19 @@ class TerrascriptClient:
2921
2967
  )
2922
2968
  self.add_resource(account, role_tf_resource)
2923
2969
 
2924
- def populate_tf_resource_sqs(self, spec):
2970
+ def populate_tf_resource_sqs(self, spec: ExternalResourceSpec) -> None:
2925
2971
  account = spec.provisioner_name
2926
2972
  identifier = spec.identifier
2927
2973
  common_values = self.init_values(spec)
2928
2974
  output_prefix = spec.output_prefix
2929
2975
  uid = self.uids.get(account)
2930
2976
 
2931
- tf_resources = []
2977
+ tf_resources: list[TFResource] = []
2932
2978
  self.init_common_outputs(tf_resources, spec)
2933
2979
  region = common_values.get("region") or self.default_regions.get(account)
2980
+ assert region # make mypy happy
2934
2981
  specs = common_values.get("specs")
2982
+ assert specs is not None # make mypy happy
2935
2983
  all_queues_per_spec = []
2936
2984
  kms_keys = set()
2937
2985
  for _spec in specs:
@@ -3005,9 +3053,11 @@ class TerrascriptClient:
3005
3053
  # https://www.terraform.io/docs/providers/aws/r/iam_access_key.html
3006
3054
 
3007
3055
  # iam user for queue
3008
- values = {}
3009
- values["name"] = identifier
3010
- values["tags"] = common_values["tags"]
3056
+ values = {
3057
+ "name": identifier,
3058
+ "tags": common_values["tags"],
3059
+ }
3060
+
3011
3061
  user_tf_resource = aws_iam_user(identifier, **values)
3012
3062
  tf_resources.append(user_tf_resource)
3013
3063
 
@@ -3021,9 +3071,9 @@ class TerrascriptClient:
3021
3071
  policy_identifier = f"{identifier}-{policy_index}"
3022
3072
  if len(all_queues_per_spec) == 1:
3023
3073
  policy_identifier = identifier
3024
- values = {}
3025
- values["name"] = policy_identifier
3026
- policy = {
3074
+ values = {"name": policy_identifier}
3075
+
3076
+ policy: dict[str, Any] = {
3027
3077
  "Version": "2012-10-17",
3028
3078
  "Statement": [
3029
3079
  {
@@ -3049,27 +3099,29 @@ class TerrascriptClient:
3049
3099
  tf_resources.append(policy_tf_resource)
3050
3100
 
3051
3101
  # iam user policy attachment
3052
- values = {}
3053
- values["user"] = identifier
3054
- values["policy_arn"] = "${" + policy_tf_resource.arn + "}"
3055
- values["depends_on"] = self.get_dependencies([
3056
- user_tf_resource,
3057
- policy_tf_resource,
3058
- ])
3102
+ values = {
3103
+ "user": identifier,
3104
+ "policy_arn": "${" + policy_tf_resource.arn + "}",
3105
+ "depends_on": self.get_dependencies([
3106
+ user_tf_resource,
3107
+ policy_tf_resource,
3108
+ ]),
3109
+ }
3110
+
3059
3111
  tf_resource = aws_iam_user_policy_attachment(policy_identifier, **values)
3060
3112
  tf_resources.append(tf_resource)
3061
3113
 
3062
3114
  self.add_resources(account, tf_resources)
3063
3115
 
3064
- def populate_tf_resource_sns(self, spec):
3116
+ def populate_tf_resource_sns(self, spec: ExternalResourceSpec) -> None:
3065
3117
  account = spec.provisioner_name
3066
3118
  identifier = spec.identifier
3067
3119
  common_values = self.init_values(spec)
3068
3120
  output_prefix = spec.output_prefix
3069
3121
  policy = common_values.get("inline_policy")
3070
3122
  region = common_values.get("region") or self.default_regions.get(account)
3071
-
3072
- values = {}
3123
+ assert region # make mypy happy
3124
+ values: dict[str, Any] = {}
3073
3125
  fifo_topic = common_values.get("fifo_topic", False)
3074
3126
  topic_name = identifier + ".fifo" if fifo_topic else identifier
3075
3127
 
@@ -3077,16 +3129,18 @@ class TerrascriptClient:
3077
3129
  values["policy"] = policy
3078
3130
  values["fifo_topic"] = fifo_topic
3079
3131
 
3080
- tf_resources = []
3132
+ tf_resources: list[TFResource] = []
3081
3133
  self.init_common_outputs(tf_resources, spec)
3082
3134
  tf_resource = aws_sns_topic(identifier, **values)
3083
3135
  tf_resources.append(tf_resource)
3084
3136
 
3085
3137
  if "subscriptions" in common_values:
3086
- subscriptions = common_values.get("subscriptions")
3138
+ subscriptions = common_values["subscriptions"]
3087
3139
  for index, sub in enumerate(subscriptions):
3088
- sub_values = {}
3089
- sub_values["topic_arn"] = "${aws_sns_topic" + "." + identifier + ".arn}"
3140
+ sub_values = {
3141
+ "topic_arn": "${aws_sns_topic" + "." + identifier + ".arn}"
3142
+ }
3143
+
3090
3144
  protocol = sub["protocol"]
3091
3145
  endpoint = sub["endpoint"]
3092
3146
  if protocol == "email" and not EMAIL_REGEX.match(endpoint):
@@ -3111,17 +3165,19 @@ class TerrascriptClient:
3111
3165
  tf_resources.append(Output(output_name, value=output_value))
3112
3166
  self.add_resources(account, tf_resources)
3113
3167
 
3114
- def populate_tf_resource_dynamodb(self, spec):
3168
+ def populate_tf_resource_dynamodb(self, spec: ExternalResourceSpec) -> None:
3115
3169
  account = spec.provisioner_name
3116
3170
  identifier = spec.identifier
3117
3171
  common_values = self.init_values(spec)
3118
3172
  output_prefix = spec.output_prefix
3119
3173
  uid = self.uids.get(account)
3120
3174
 
3121
- tf_resources = []
3175
+ tf_resources: list[TFResource] = []
3122
3176
  self.init_common_outputs(tf_resources, spec)
3123
3177
  region = common_values.get("region") or self.default_regions.get(account)
3178
+ assert region # make mypy happy
3124
3179
  specs = common_values.get("specs")
3180
+ assert specs is not None # make mypy happy
3125
3181
  all_tables = []
3126
3182
  for _spec in specs:
3127
3183
  defaults = self.get_values(_spec["defaults"])
@@ -3135,9 +3191,11 @@ class TerrascriptClient:
3135
3191
  # Terraform resource reference:
3136
3192
  # https://www.terraform.io/docs/providers/aws/r/
3137
3193
  # dynamodb_table.html
3138
- values = {}
3139
- values["name"] = table
3140
- values["tags"] = common_values["tags"]
3194
+ values = {
3195
+ "name": table,
3196
+ "tags": common_values["tags"],
3197
+ }
3198
+
3141
3199
  values.update(defaults)
3142
3200
  values["attribute"] = attributes
3143
3201
  if self._multiregion_account(account):
@@ -3158,9 +3216,11 @@ class TerrascriptClient:
3158
3216
  # https://www.terraform.io/docs/providers/aws/r/iam_access_key.html
3159
3217
 
3160
3218
  # iam user for table
3161
- values = {}
3162
- values["name"] = identifier
3163
- values["tags"] = common_values["tags"]
3219
+ values = {
3220
+ "name": identifier,
3221
+ "tags": common_values["tags"],
3222
+ }
3223
+
3164
3224
  user_tf_resource = aws_iam_user(identifier, **values)
3165
3225
  tf_resources.append(user_tf_resource)
3166
3226
 
@@ -3200,23 +3260,24 @@ class TerrascriptClient:
3200
3260
 
3201
3261
  self.add_resources(account, tf_resources)
3202
3262
 
3203
- def populate_tf_resource_ecr(self, spec):
3263
+ def populate_tf_resource_ecr(self, spec: ExternalResourceSpec) -> None:
3204
3264
  account = spec.provisioner_name
3205
3265
  identifier = spec.identifier
3206
3266
  common_values = self.init_values(spec)
3207
3267
  output_prefix = spec.output_prefix
3208
3268
 
3209
- tf_resources = []
3269
+ tf_resources: list[TFResource] = []
3210
3270
  self.init_common_outputs(tf_resources, spec)
3211
3271
 
3212
3272
  # ecr repository
3213
3273
  # Terraform resource reference:
3214
3274
  # https://www.terraform.io/docs/providers/aws/r/ecr_repository.html
3215
- values = {}
3275
+ values: dict[str, Any] = {}
3216
3276
  values["name"] = identifier
3217
3277
  values["tags"] = common_values["tags"]
3218
3278
 
3219
3279
  region = common_values.get("region") or self.default_regions.get(account)
3280
+ assert region # make mypy happy
3220
3281
  if self._multiregion_account(account):
3221
3282
  values["provider"] = "aws." + region
3222
3283
  ecr_tf_resource = aws_ecr_repository(identifier, **values)
@@ -3242,11 +3303,12 @@ class TerrascriptClient:
3242
3303
  # https://www.terraform.io/docs/providers/aws/r/iam_access_key.html
3243
3304
 
3244
3305
  # iam user for repository
3245
- values = {}
3246
- values["name"] = identifier
3247
- values["tags"] = common_values["tags"]
3248
- values["depends_on"] = self.get_dependencies([ecr_tf_resource])
3249
- user_tf_resource = aws_iam_user(identifier, **values)
3306
+ values_iam_user: dict[str, Any] = {
3307
+ "name": identifier,
3308
+ "tags": common_values["tags"],
3309
+ "depends_on": self.get_dependencies([ecr_tf_resource]),
3310
+ }
3311
+ user_tf_resource = aws_iam_user(identifier, **values_iam_user)
3250
3312
  tf_resources.append(user_tf_resource)
3251
3313
 
3252
3314
  # iam access key for user
@@ -3255,8 +3317,7 @@ class TerrascriptClient:
3255
3317
  )
3256
3318
 
3257
3319
  # iam user policy for bucket
3258
- values = {}
3259
- values["name"] = identifier
3320
+ values_policy: dict[str, Any] = {"name": identifier}
3260
3321
  policy = {
3261
3322
  "Version": "2012-10-17",
3262
3323
  "Statement": [
@@ -3293,10 +3354,10 @@ class TerrascriptClient:
3293
3354
  },
3294
3355
  ],
3295
3356
  }
3296
- values["policy"] = json.dumps(policy, sort_keys=True)
3297
- values["depends_on"] = self.get_dependencies([user_tf_resource])
3357
+ values_policy["policy"] = json.dumps(policy, sort_keys=True)
3358
+ values_policy["depends_on"] = self.get_dependencies([user_tf_resource])
3298
3359
 
3299
- tf_aws_iam_policy = aws_iam_policy(identifier, **values)
3360
+ tf_aws_iam_policy = aws_iam_policy(identifier, **values_policy)
3300
3361
  tf_resources.append(tf_aws_iam_policy)
3301
3362
 
3302
3363
  tf_aws_iam_user_policy_attachment = aws_iam_user_policy_attachment(
@@ -3309,7 +3370,7 @@ class TerrascriptClient:
3309
3370
 
3310
3371
  self.add_resources(account, tf_resources)
3311
3372
 
3312
- def populate_tf_resource_s3_cloudfront(self, spec):
3373
+ def populate_tf_resource_s3_cloudfront(self, spec: ExternalResourceSpec) -> None:
3313
3374
  account = spec.provisioner_name
3314
3375
  identifier = spec.identifier
3315
3376
  common_values = self.init_values(spec)
@@ -3317,17 +3378,15 @@ class TerrascriptClient:
3317
3378
 
3318
3379
  bucket_tf_resource = self.populate_tf_resource_s3(spec)
3319
3380
 
3320
- tf_resources = []
3381
+ tf_resources: list[TFResource] = []
3321
3382
 
3322
3383
  # cloudfront origin access identity
3323
- values = {}
3324
- values["comment"] = f"{identifier}-cf-identity"
3384
+ values = {"comment": f"{identifier}-cf-identity"}
3325
3385
  cf_oai_tf_resource = aws_cloudfront_origin_access_identity(identifier, **values)
3326
3386
  tf_resources.append(cf_oai_tf_resource)
3327
3387
 
3328
3388
  # bucket policy for cloudfront
3329
- values = {}
3330
- values["bucket"] = identifier
3389
+ values_policy: dict[str, Any] = {"bucket": identifier}
3331
3390
  policy = {
3332
3391
  "Version": "2012-10-17",
3333
3392
  "Statement": [
@@ -3345,26 +3404,27 @@ class TerrascriptClient:
3345
3404
  }
3346
3405
  ],
3347
3406
  }
3348
- values["policy"] = json.dumps(policy, sort_keys=True)
3349
- values["depends_on"] = self.get_dependencies([bucket_tf_resource])
3407
+ values_policy["policy"] = json.dumps(policy, sort_keys=True)
3408
+ values_policy["depends_on"] = self.get_dependencies([bucket_tf_resource])
3350
3409
  region = common_values.get("region") or self.default_regions.get(account)
3410
+ assert region # make mypy happy
3351
3411
  if self._multiregion_account(account):
3352
- values["provider"] = "aws." + region
3353
- bucket_policy_tf_resource = aws_s3_bucket_policy(identifier, **values)
3412
+ values_policy["provider"] = "aws." + region
3413
+ bucket_policy_tf_resource = aws_s3_bucket_policy(identifier, **values_policy)
3354
3414
  tf_resources.append(bucket_policy_tf_resource)
3355
3415
 
3356
- values = common_values.get("distribution_config", {})
3416
+ distribution_config = common_values.get("distribution_config", {})
3357
3417
  # aws_s3_bucket_acl
3358
- if "logging_config" in values:
3418
+ if "logging_config" in distribution_config:
3359
3419
  # we could set this at a global level with a standard name like "cloudfront"
3360
3420
  # but we need all aws accounts upgraded to aws provider >3.60 first
3361
3421
  tf_resources.append(
3362
3422
  aws_cloudfront_log_delivery_canonical_user_id(identifier)
3363
3423
  )
3364
3424
 
3365
- logging_config_bucket = values["logging_config"]
3425
+ logging_config_bucket = distribution_config["logging_config"]
3366
3426
  acl_values = {}
3367
- access_control_policy = {
3427
+ access_control_policy: dict[str, Any] = {
3368
3428
  "owner": {
3369
3429
  "id": "${data.aws_canonical_user_id.current.id}",
3370
3430
  },
@@ -3388,7 +3448,7 @@ class TerrascriptClient:
3388
3448
  }
3389
3449
  external_account_id = logging_config_bucket.pop("external_account_id", None)
3390
3450
  if external_account_id:
3391
- external_account_policy = {
3451
+ external_account_policy: dict[str, Any] = {
3392
3452
  "grantee": {
3393
3453
  "id": external_account_id,
3394
3454
  "type": "CanonicalUser",
@@ -3403,13 +3463,15 @@ class TerrascriptClient:
3403
3463
  tf_resources.append(aws_s3_bucket_acl_resource)
3404
3464
 
3405
3465
  # cloud front distribution
3406
- values["tags"] = common_values["tags"]
3407
- values.setdefault("default_cache_behavior", {}).setdefault(
3466
+ distribution_config["tags"] = common_values["tags"]
3467
+ distribution_config.setdefault("default_cache_behavior", {}).setdefault(
3408
3468
  "target_origin_id", "default"
3409
3469
  )
3410
3470
  origin = {
3411
3471
  "domain_name": "${" + bucket_tf_resource.bucket_domain_name + "}",
3412
- "origin_id": values["default_cache_behavior"]["target_origin_id"],
3472
+ "origin_id": distribution_config["default_cache_behavior"][
3473
+ "target_origin_id"
3474
+ ],
3413
3475
  "s3_origin_config": {
3414
3476
  "origin_access_identity": "origin-access-identity/cloudfront/"
3415
3477
  + "${"
@@ -3417,8 +3479,10 @@ class TerrascriptClient:
3417
3479
  + "}"
3418
3480
  },
3419
3481
  }
3420
- values["origin"] = [origin]
3421
- cf_distribution_tf_resource = aws_cloudfront_distribution(identifier, **values)
3482
+ distribution_config["origin"] = [origin]
3483
+ cf_distribution_tf_resource = aws_cloudfront_distribution(
3484
+ identifier, **distribution_config
3485
+ )
3422
3486
  tf_resources.append(cf_distribution_tf_resource)
3423
3487
 
3424
3488
  # outputs
@@ -3443,7 +3507,7 @@ class TerrascriptClient:
3443
3507
 
3444
3508
  self.add_resources(account, tf_resources)
3445
3509
 
3446
- def populate_tf_resource_s3_sqs(self, spec):
3510
+ def populate_tf_resource_s3_sqs(self, spec: ExternalResourceSpec) -> None:
3447
3511
  account = spec.provisioner_name
3448
3512
  identifier = spec.identifier
3449
3513
  common_values = self.init_values(spec)
@@ -3453,12 +3517,13 @@ class TerrascriptClient:
3453
3517
  bucket_tf_resource = self.populate_tf_resource_s3(spec)
3454
3518
 
3455
3519
  region = common_values.get("region") or self.default_regions.get(account)
3520
+ assert region # make mypy happy
3456
3521
  provider = ""
3457
3522
  if self._multiregion_account(account):
3458
3523
  provider = "aws." + region
3459
- tf_resources = []
3524
+ tf_resources: list[TFResource] = []
3460
3525
  sqs_identifier = f"{identifier}-sqs"
3461
- sqs_values = {"name": sqs_identifier}
3526
+ sqs_values: dict[str, Any] = {"name": sqs_identifier}
3462
3527
 
3463
3528
  sqs_values["visibility_timeout_seconds"] = int(
3464
3529
  common_values.get("visibility_timeout_seconds", 30)
@@ -3491,15 +3556,15 @@ class TerrascriptClient:
3491
3556
  if kms_encryption:
3492
3557
  kms_identifier = f"{identifier}-kms"
3493
3558
  kms_values = {
3494
- "description": "app-interface created KMS key for" + sqs_identifier
3559
+ "description": "app-interface created KMS key for" + sqs_identifier,
3560
+ "key_usage": str(
3561
+ common_values.get("key_usage", "ENCRYPT_DECRYPT")
3562
+ ).upper(),
3563
+ "customer_master_key_spec": str(
3564
+ common_values.get("customer_master_key_spec", "SYMMETRIC_DEFAULT")
3565
+ ).upper(),
3566
+ "is_enabled": common_values.get("is_enabled", True),
3495
3567
  }
3496
- kms_values["key_usage"] = str(
3497
- common_values.get("key_usage", "ENCRYPT_DECRYPT")
3498
- ).upper()
3499
- kms_values["customer_master_key_spec"] = str(
3500
- common_values.get("customer_master_key_spec", "SYMMETRIC_DEFAULT")
3501
- ).upper()
3502
- kms_values["is_enabled"] = common_values.get("is_enabled", True)
3503
3568
 
3504
3569
  kms_policy = {
3505
3570
  "Version": "2012-10-17",
@@ -3575,16 +3640,16 @@ class TerrascriptClient:
3575
3640
  # https://www.terraform.io/docs/providers/aws/r/iam_access_key.html
3576
3641
 
3577
3642
  # iam user for queue
3578
- values = {}
3579
- values["name"] = sqs_identifier
3643
+ values: dict[str, Any] = {"name": sqs_identifier}
3580
3644
  user_tf_resource = aws_iam_user(sqs_identifier, **values)
3581
3645
  tf_resources.append(user_tf_resource)
3582
3646
 
3583
3647
  # iam access key for user
3584
- values = {}
3585
- values["user"] = sqs_identifier
3586
- values["depends_on"] = self.get_dependencies([user_tf_resource])
3587
- access_key_tf_resource = aws_iam_access_key(sqs_identifier, **values)
3648
+ values_key: dict[str, Any] = {
3649
+ "user": sqs_identifier,
3650
+ "depends_on": self.get_dependencies([user_tf_resource]),
3651
+ }
3652
+ access_key_tf_resource = aws_iam_access_key(sqs_identifier, **values_key)
3588
3653
  tf_resources.append(access_key_tf_resource)
3589
3654
  # outputs
3590
3655
  # sqs_aws_access_key_id
@@ -3597,9 +3662,8 @@ class TerrascriptClient:
3597
3662
  tf_resources.append(Output(output_name, value=output_value, sensitive=True))
3598
3663
 
3599
3664
  # iam policy for queue
3600
- values = {}
3601
- values["name"] = sqs_identifier
3602
- policy = {
3665
+ values_policy: dict[str, Any] = {"name": sqs_identifier}
3666
+ policy: dict[str, Any] = {
3603
3667
  "Version": "2012-10-17",
3604
3668
  "Statement": [
3605
3669
  {
@@ -3620,20 +3684,21 @@ class TerrascriptClient:
3620
3684
  "Resource": [sqs_values["kms_master_key_id"]],
3621
3685
  }
3622
3686
  policy["Statement"].append(kms_statement)
3623
- values["policy"] = json.dumps(policy, sort_keys=True)
3624
- policy_tf_resource = aws_iam_policy(sqs_identifier, **values)
3687
+ values_policy["policy"] = json.dumps(policy, sort_keys=True)
3688
+ policy_tf_resource = aws_iam_policy(sqs_identifier, **values_policy)
3625
3689
  tf_resources.append(policy_tf_resource)
3626
3690
 
3627
3691
  # iam user policy attachment
3628
- values = {}
3629
- values["user"] = sqs_identifier
3630
- values["policy_arn"] = "${" + policy_tf_resource.arn + "}"
3631
- values["depends_on"] = self.get_dependencies([
3632
- user_tf_resource,
3633
- policy_tf_resource,
3634
- ])
3692
+ values_user_policy: dict[str, Any] = {
3693
+ "user": sqs_identifier,
3694
+ "policy_arn": "${" + policy_tf_resource.arn + "}",
3695
+ "depends_on": self.get_dependencies([
3696
+ user_tf_resource,
3697
+ policy_tf_resource,
3698
+ ]),
3699
+ }
3635
3700
  user_policy_attachment_tf_resource = aws_iam_user_policy_attachment(
3636
- sqs_identifier, **values
3701
+ sqs_identifier, **values_user_policy
3637
3702
  )
3638
3703
  tf_resources.append(user_policy_attachment_tf_resource)
3639
3704
 
@@ -3644,13 +3709,13 @@ class TerrascriptClient:
3644
3709
 
3645
3710
  self.add_resources(account, tf_resources)
3646
3711
 
3647
- def populate_tf_resource_cloudwatch(self, spec):
3712
+ def populate_tf_resource_cloudwatch(self, spec: ExternalResourceSpec) -> None:
3648
3713
  account = spec.provisioner_name
3649
3714
  identifier = spec.identifier
3650
3715
  common_values = self.init_values(spec)
3651
3716
  output_prefix = spec.output_prefix
3652
3717
 
3653
- tf_resources = []
3718
+ tf_resources: list[TFResource] = []
3654
3719
  self.init_common_outputs(tf_resources, spec)
3655
3720
 
3656
3721
  # ecr repository
@@ -3666,6 +3731,7 @@ class TerrascriptClient:
3666
3731
  }
3667
3732
 
3668
3733
  region = common_values.get("region") or self.default_regions.get(account)
3734
+ assert region # make mypy happy
3669
3735
  provider = ""
3670
3736
  if self._multiregion_account(account):
3671
3737
  provider = "aws." + region
@@ -3741,29 +3807,26 @@ class TerrascriptClient:
3741
3807
  "filename": zip_file,
3742
3808
  "source_code_hash": '${filebase64sha256("' + zip_file + '")}',
3743
3809
  "role": "${" + role_tf_resource.arn + "}",
3744
- }
3745
-
3746
- lambda_values["function_name"] = lambda_identifier
3747
- lambda_values["runtime"] = common_values.get("runtime", "nodejs18.x")
3748
- lambda_values["timeout"] = common_values.get("timeout", 30)
3749
- lambda_values["handler"] = common_values.get("handler", "index.handler")
3750
- lambda_values["memory_size"] = common_values.get("memory_size", 128)
3751
-
3752
- lambda_values["vpc_config"] = {
3753
- "subnet_ids": "${data.aws_elasticsearch_domain."
3754
- + es_identifier
3755
- + ".vpc_options.0.subnet_ids}",
3756
- "security_group_ids": "${data.aws_elasticsearch_domain."
3757
- + es_identifier
3758
- + ".vpc_options.0.security_group_ids}",
3759
- }
3760
-
3761
- lambda_values["environment"] = {
3762
- "variables": {
3763
- "es_endpoint": "${data.aws_elasticsearch_domain."
3810
+ "function_name": lambda_identifier,
3811
+ "runtime": common_values.get("runtime", "nodejs18.x"),
3812
+ "timeout": common_values.get("timeout", 30),
3813
+ "handler": common_values.get("handler", "index.handler"),
3814
+ "memory_size": common_values.get("memory_size", 128),
3815
+ "vpc_config": {
3816
+ "subnet_ids": "${data.aws_elasticsearch_domain."
3764
3817
  + es_identifier
3765
- + ".endpoint}"
3766
- }
3818
+ + ".vpc_options.0.subnet_ids}",
3819
+ "security_group_ids": "${data.aws_elasticsearch_domain."
3820
+ + es_identifier
3821
+ + ".vpc_options.0.security_group_ids}",
3822
+ },
3823
+ "environment": {
3824
+ "variables": {
3825
+ "es_endpoint": "${data.aws_elasticsearch_domain."
3826
+ + es_identifier
3827
+ + ".endpoint}"
3828
+ }
3829
+ },
3767
3830
  }
3768
3831
 
3769
3832
  if provider:
@@ -3869,13 +3932,13 @@ class TerrascriptClient:
3869
3932
 
3870
3933
  self.add_resources(account, tf_resources)
3871
3934
 
3872
- def populate_tf_resource_kms(self, spec):
3935
+ def populate_tf_resource_kms(self, spec: ExternalResourceSpec) -> None:
3873
3936
  account = spec.provisioner_name
3874
3937
  identifier = spec.identifier
3875
3938
  values = self.init_values(spec)
3876
3939
  output_prefix = spec.output_prefix
3877
3940
 
3878
- tf_resources = []
3941
+ tf_resources: list[TFResource] = []
3879
3942
  self.init_common_outputs(tf_resources, spec)
3880
3943
  values.pop("identifier", None)
3881
3944
 
@@ -3892,6 +3955,7 @@ class TerrascriptClient:
3892
3955
  if key in values:
3893
3956
  values[key] = values[key].upper()
3894
3957
  region = values.pop("region", None) or self.default_regions.get(account)
3958
+ assert region # make mypy happy
3895
3959
  if self._multiregion_account(account):
3896
3960
  values["provider"] = "aws." + region
3897
3961
 
@@ -3903,9 +3967,10 @@ class TerrascriptClient:
3903
3967
  output_value = "${" + tf_resource.key_id + "}"
3904
3968
  tf_resources.append(Output(output_name, value=output_value))
3905
3969
 
3906
- alias_values = {}
3907
- alias_values["name"] = "alias/" + identifier
3908
- alias_values["target_key_id"] = "${aws_kms_key." + identifier + ".key_id}"
3970
+ alias_values = {
3971
+ "name": "alias/" + identifier,
3972
+ "target_key_id": "${aws_kms_key." + identifier + ".key_id}",
3973
+ }
3909
3974
  if self._multiregion_account(account):
3910
3975
  alias_values["provider"] = "aws." + region
3911
3976
  tf_resource = aws_kms_alias(identifier, **alias_values)
@@ -3913,28 +3978,30 @@ class TerrascriptClient:
3913
3978
 
3914
3979
  self.add_resources(account, tf_resources)
3915
3980
 
3916
- def populate_tf_resource_kinesis(self, spec):
3981
+ def populate_tf_resource_kinesis(self, spec: ExternalResourceSpec) -> None:
3917
3982
  account = spec.provisioner_name
3918
3983
  identifier = spec.identifier
3919
3984
  common_values = self.init_values(spec)
3920
3985
  output_prefix = spec.output_prefix
3921
3986
 
3922
- tf_resources = []
3987
+ tf_resources: list[TFResource] = []
3923
3988
  self.init_common_outputs(tf_resources, spec)
3924
3989
 
3925
- tags = common_values["tags"]
3926
- kinesis_values = {
3990
+ tags: dict[str, str] = common_values["tags"]
3991
+ kinesis_values: dict[str, Any] = {
3927
3992
  "name": identifier,
3928
3993
  "tags": tags,
3994
+ "shard_count": common_values.get("shard_count"),
3995
+ "retention_period": common_values.get("retention_period", 24),
3996
+ "encryption_type": common_values.get("encryption_type", None),
3929
3997
  }
3930
- kinesis_values["shard_count"] = common_values.get("shard_count")
3931
- kinesis_values["retention_period"] = common_values.get("retention_period", 24)
3932
- kinesis_values["encryption_type"] = common_values.get("encryption_type", None)
3998
+
3933
3999
  if kinesis_values["encryption_type"] == "KMS":
3934
4000
  kinesis_values["kms_key_id"] = common_values.get("kms_key_id")
3935
4001
 
3936
4002
  # get region and set provider if required
3937
4003
  region = common_values.get("region") or self.default_regions.get(account)
4004
+ assert region # make mypy happy
3938
4005
  provider = ""
3939
4006
  if self._multiregion_account(account):
3940
4007
  provider = "aws." + region
@@ -4054,34 +4121,31 @@ class TerrascriptClient:
4054
4121
  "source_code_hash": '${filebase64sha256("' + zip_file + '")}',
4055
4122
  "role": "${" + role_tf_resource.arn + "}",
4056
4123
  "tags": tags,
4057
- }
4058
-
4059
- lambda_values["function_name"] = lambda_identifier
4060
- lambda_values["runtime"] = common_values.get("runtime", "python3.9")
4061
- lambda_values["timeout"] = common_values.get("timeout", 30)
4062
- lambda_values["handler"] = common_values.get(
4063
- "handler", "lambda_function.handler"
4064
- )
4065
- lambda_values["memory_size"] = common_values.get("memory_size", 128)
4066
-
4067
- lambda_values["vpc_config"] = {
4068
- "subnet_ids": "${data.aws_elasticsearch_domain."
4069
- + es_identifier
4070
- + ".vpc_options.0.subnet_ids}",
4071
- "security_group_ids": "${data.aws_elasticsearch_domain."
4072
- + es_identifier
4073
- + ".vpc_options.0.security_group_ids}",
4074
- }
4075
-
4076
- index_prefix = common_values.get("index_prefix", f"{identifier}-")
4077
- lambda_values["environment"] = {
4078
- "variables": {
4079
- "es_endpoint": "${data.aws_elasticsearch_domain."
4124
+ "function_name": lambda_identifier,
4125
+ "runtime": common_values.get("runtime", "python3.9"),
4126
+ "timeout": common_values.get("timeout", 30),
4127
+ "handler": common_values.get("handler", "lambda_function.handler"),
4128
+ "memory_size": common_values.get("memory_size", 128),
4129
+ "vpc_config": {
4130
+ "subnet_ids": "${data.aws_elasticsearch_domain."
4080
4131
  + es_identifier
4081
- + ".endpoint}",
4082
- "index_prefix": index_prefix,
4083
- }
4132
+ + ".vpc_options.0.subnet_ids}",
4133
+ "security_group_ids": "${data.aws_elasticsearch_domain."
4134
+ + es_identifier
4135
+ + ".vpc_options.0.security_group_ids}",
4136
+ },
4137
+ "environment": {
4138
+ "variables": {
4139
+ "es_endpoint": "${data.aws_elasticsearch_domain."
4140
+ + es_identifier
4141
+ + ".endpoint}",
4142
+ "index_prefix": common_values.get(
4143
+ "index_prefix", f"{identifier}-"
4144
+ ),
4145
+ }
4146
+ },
4084
4147
  }
4148
+
4085
4149
  secret_name = es_resource.get_secret_field("secret_name")
4086
4150
  if secret_name:
4087
4151
  lambda_values["environment"]["variables"]["secret_name"] = secret_name
@@ -4160,7 +4224,9 @@ class TerrascriptClient:
4160
4224
  self.add_resources(account, tf_resources)
4161
4225
 
4162
4226
  @staticmethod
4163
- def _get_retention_in_days(values, account, identifier):
4227
+ def _get_retention_in_days(
4228
+ values: Mapping[str, Any], account: str, identifier: str
4229
+ ) -> int:
4164
4230
  default_retention_in_days = 14
4165
4231
  allowed_retention_in_days = [
4166
4232
  1,
@@ -4194,17 +4260,21 @@ class TerrascriptClient:
4194
4260
  return retention_in_days
4195
4261
 
4196
4262
  def get_tf_iam_service_user(
4197
- self, dep_tf_resource, identifier, policy, tags, output_prefix
4198
- ):
4263
+ self,
4264
+ dep_tf_resource: TFResource | None,
4265
+ identifier: str,
4266
+ policy: Mapping[str, Any],
4267
+ tags: Mapping[str, str],
4268
+ output_prefix: str,
4269
+ ) -> list[TFResource]:
4199
4270
  # iam resources
4200
4271
  # Terraform resource reference:
4201
4272
  # https://www.terraform.io/docs/providers/aws/r/iam_access_key.html
4202
- tf_resources = []
4273
+ tf_resources: list[TFResource] = []
4203
4274
 
4204
4275
  # iam user
4205
- values = {}
4206
- values["name"] = identifier
4207
- values["tags"] = tags
4276
+ values: dict[str, Any] = {"name": identifier, "tags": tags}
4277
+
4208
4278
  if dep_tf_resource:
4209
4279
  values["depends_on"] = self.get_dependencies([dep_tf_resource])
4210
4280
  user_tf_resource = aws_iam_user(identifier, **values)
@@ -4216,12 +4286,13 @@ class TerrascriptClient:
4216
4286
  )
4217
4287
 
4218
4288
  # iam user policy
4219
- values = {}
4220
- values["name"] = identifier
4221
- values["policy"] = json.dumps(policy, sort_keys=True)
4222
- values["depends_on"] = self.get_dependencies([user_tf_resource])
4289
+ values_policy: dict[str, Any] = {
4290
+ "name": identifier,
4291
+ "policy": json.dumps(policy, sort_keys=True),
4292
+ "depends_on": self.get_dependencies([user_tf_resource]),
4293
+ }
4223
4294
 
4224
- tf_aws_iam_policy = aws_iam_policy(identifier, **values)
4295
+ tf_aws_iam_policy = aws_iam_policy(identifier, **values_policy)
4225
4296
  tf_resources.append(tf_aws_iam_policy)
4226
4297
 
4227
4298
  tf_aws_iam_user_policy_attachment = aws_iam_user_policy_attachment(
@@ -4234,11 +4305,15 @@ class TerrascriptClient:
4234
4305
 
4235
4306
  return tf_resources
4236
4307
 
4237
- def get_tf_iam_access_key(self, user_tf_resource, identifier, output_prefix):
4238
- tf_resources = []
4239
- values = {}
4240
- values["user"] = identifier
4241
- values["depends_on"] = self.get_dependencies([user_tf_resource])
4308
+ def get_tf_iam_access_key(
4309
+ self, user_tf_resource: aws_iam_user, identifier: str, output_prefix: str
4310
+ ) -> list[TFResource]:
4311
+ tf_resources: list[TFResource] = []
4312
+ values: dict[str, Any] = {
4313
+ "user": identifier,
4314
+ "depends_on": self.get_dependencies([user_tf_resource]),
4315
+ }
4316
+
4242
4317
  tf_resource = aws_iam_access_key(identifier, **values)
4243
4318
  tf_resources.append(tf_resource)
4244
4319
  # outputs
@@ -4253,11 +4328,11 @@ class TerrascriptClient:
4253
4328
 
4254
4329
  return tf_resources
4255
4330
 
4256
- def add_resources(self, account, tf_resources):
4331
+ def add_resources(self, account: str, tf_resources: Iterable[TFResource]) -> None:
4257
4332
  for r in tf_resources:
4258
4333
  self.add_resource(account, r)
4259
4334
 
4260
- def add_resource(self, account, tf_resource):
4335
+ def add_resource(self, account: str, tf_resource: TFResource) -> None:
4261
4336
  if account not in self.locks:
4262
4337
  logging.debug(
4263
4338
  f"integration {self.integration} is disabled for account {account}. "
@@ -4267,7 +4342,7 @@ class TerrascriptClient:
4267
4342
  with self.locks[account]:
4268
4343
  self.tss[account].add(tf_resource)
4269
4344
 
4270
- def add_moved(self, account: str, moved: Moved):
4345
+ def add_moved(self, account: str, moved: Moved) -> None:
4271
4346
  if account not in self.locks:
4272
4347
  logging.debug(
4273
4348
  f"integration {self.integration} is disabled for account {account}. "
@@ -4336,7 +4411,9 @@ class TerrascriptClient:
4336
4411
  for name, ts in self.tss.items()
4337
4412
  }
4338
4413
 
4339
- def init_values(self, spec: ExternalResourceSpec, init_tags: bool = True) -> dict:
4414
+ def init_values(
4415
+ self, spec: ExternalResourceSpec, init_tags: bool = True
4416
+ ) -> dict[str, Any]:
4340
4417
  """
4341
4418
  Initialize the values of the terraform resource and merge the defaults and
4342
4419
  overrides.
@@ -4389,7 +4466,7 @@ class TerrascriptClient:
4389
4466
  return values
4390
4467
 
4391
4468
  @staticmethod
4392
- def aggregate_values(values):
4469
+ def aggregate_values(values: dict[str, Any]) -> None:
4393
4470
  split_char = "."
4394
4471
  copy = values.copy()
4395
4472
  for k, v in copy.items():
@@ -4403,18 +4480,17 @@ class TerrascriptClient:
4403
4480
  values.pop(k, None)
4404
4481
 
4405
4482
  @staticmethod
4406
- def override_values(values, overrides):
4483
+ def override_values(values: dict[str, Any], overrides: str | None) -> None:
4407
4484
  if overrides is None:
4408
4485
  return
4409
4486
  data = json.loads(overrides)
4410
- for k, v in data.items():
4411
- values[k] = v
4487
+ values.update(data)
4412
4488
 
4413
4489
  def init_common_outputs(
4414
4490
  self,
4415
- tf_resources: list[Resource],
4491
+ tf_resources: list[TFResource],
4416
4492
  spec: ExternalResourceSpec,
4417
- ):
4493
+ ) -> None:
4418
4494
  output_format = "{}__{}_{}"
4419
4495
  # cluster
4420
4496
  output_name = output_format.format(
@@ -4449,11 +4525,11 @@ class TerrascriptClient:
4449
4525
  output_value = base64.b64encode(anno_json).decode()
4450
4526
  tf_resources.append(Output(output_name, value=output_value))
4451
4527
 
4452
- def prefetch_resources(self, schema) -> dict[str, dict[str, str]]:
4528
+ def prefetch_resources(self, schema: str) -> dict[str, dict[str, str]]:
4453
4529
  gqlapi = gql.get_api()
4454
4530
  return {r["path"]: r for r in gqlapi.get_resources_by_schema(schema)}
4455
4531
 
4456
- def get_raw_values(self, path) -> dict[str, str]:
4532
+ def get_raw_values(self, path: str) -> dict[str, str]:
4457
4533
  if path in self._resource_cache:
4458
4534
  return self._resource_cache[path]
4459
4535
 
@@ -4482,7 +4558,7 @@ class TerrascriptClient:
4482
4558
  ]
4483
4559
 
4484
4560
  @staticmethod
4485
- def get_elasticsearch_service_role_tf_resource():
4561
+ def get_elasticsearch_service_role_tf_resource() -> aws_iam_service_linked_role:
4486
4562
  """Service role for ElasticSearch."""
4487
4563
  service_role = {
4488
4564
  "aws_service_name": "es.amazonaws.com",
@@ -4490,7 +4566,7 @@ class TerrascriptClient:
4490
4566
  return aws_iam_service_linked_role("elasticsearch", **service_role)
4491
4567
 
4492
4568
  @staticmethod
4493
- def is_elasticsearch_domain_name_valid(name):
4569
+ def is_elasticsearch_domain_name_valid(name: str) -> bool:
4494
4570
  """Handle for Error creating Elasticsearch:
4495
4571
  InvalidParameterValue: Elasticsearch domain name must start with a
4496
4572
  lowercase letter and must be between 3 and 28 characters. Valid
@@ -4498,7 +4574,7 @@ class TerrascriptClient:
4498
4574
  if len(name) < 3 or len(name) > 28:
4499
4575
  return False
4500
4576
  pattern = r"^[a-z][a-z0-9-]+$"
4501
- return re.search(pattern, name)
4577
+ return re.search(pattern, name) is not None
4502
4578
 
4503
4579
  @staticmethod
4504
4580
  def elasticsearch_log_group_identifier(
@@ -4600,7 +4676,7 @@ class TerrascriptClient:
4600
4676
  resource: Mapping[str, Any],
4601
4677
  values: Mapping[str, Any],
4602
4678
  output_prefix: str,
4603
- ) -> tuple[list[dict[str, Any]], list[dict[str, object]]]:
4679
+ ) -> tuple[list[TFResource], list[dict[str, object]]]:
4604
4680
  """
4605
4681
  Generate cloud_watch_log_group terraform_resources
4606
4682
  for the given resource. Further, generate
@@ -4608,7 +4684,7 @@ class TerrascriptClient:
4608
4684
  by the consumer.
4609
4685
  """
4610
4686
  es_log_group_retention_days = 90
4611
- tf_resources = []
4687
+ tf_resources: list[TFResource] = []
4612
4688
  publishing_options = []
4613
4689
 
4614
4690
  # res.get('', []) won't work, as publish_log_types is
@@ -4711,13 +4787,13 @@ class TerrascriptClient:
4711
4787
 
4712
4788
  return advanced_security_options
4713
4789
 
4714
- def populate_tf_resource_elasticsearch(self, spec):
4790
+ def populate_tf_resource_elasticsearch(self, spec: ExternalResourceSpec) -> None:
4715
4791
  account = spec.provisioner_name
4716
4792
  identifier = spec.identifier
4717
4793
  values = self.init_values(spec)
4718
4794
  output_prefix = spec.output_prefix
4719
4795
 
4720
- tf_resources = []
4796
+ tf_resources: list[TFResource] = []
4721
4797
  self.init_common_outputs(tf_resources, spec)
4722
4798
 
4723
4799
  if not self.is_elasticsearch_domain_name_valid(values["identifier"]):
@@ -4730,10 +4806,11 @@ class TerrascriptClient:
4730
4806
  )
4731
4807
 
4732
4808
  tags = values["tags"]
4733
- es_values = {}
4734
- es_values["domain_name"] = identifier
4735
- es_values["tags"] = tags
4736
- es_values["elasticsearch_version"] = values.get("elasticsearch_version")
4809
+ es_values: dict[str, Any] = {
4810
+ "domain_name": identifier,
4811
+ "tags": tags,
4812
+ "elasticsearch_version": values.get("elasticsearch_version"),
4813
+ }
4737
4814
 
4738
4815
  (
4739
4816
  log_group_resources,
@@ -4919,6 +4996,7 @@ class TerrascriptClient:
4919
4996
  es_values["access_policies"] = json.dumps(access_policies, sort_keys=True)
4920
4997
 
4921
4998
  region = values.get("region") or self.default_regions.get(account)
4999
+ assert region # make mypy happy
4922
5000
  provider = ""
4923
5001
  if self._multiregion_account(account):
4924
5002
  provider = "aws." + region
@@ -5057,8 +5135,8 @@ class TerrascriptClient:
5057
5135
 
5058
5136
  # TODO: @fishi0x01 remove this function after migration APPSRE-3409
5059
5137
  def _build_es_advanced_security_options_deprecated(
5060
- self, advanced_security_options: MutableMapping[str, Any]
5061
- ) -> MutableMapping[str, Any]:
5138
+ self, advanced_security_options: dict[str, Any]
5139
+ ) -> dict[str, Any]:
5062
5140
  master_user_options = advanced_security_options.pop("master_user_options", {})
5063
5141
 
5064
5142
  if master_user_options:
@@ -5079,13 +5157,13 @@ class TerrascriptClient:
5079
5157
 
5080
5158
  return advanced_security_options
5081
5159
 
5082
- def populate_tf_resource_acm(self, spec):
5160
+ def populate_tf_resource_acm(self, spec: ExternalResourceSpec) -> None:
5083
5161
  account = spec.provisioner_name
5084
5162
  identifier = spec.identifier
5085
5163
  common_values = self.init_values(spec)
5086
5164
  output_prefix = spec.output_prefix
5087
5165
 
5088
- tf_resources = []
5166
+ tf_resources: list[TFResource] = []
5089
5167
  self.init_common_outputs(tf_resources, spec)
5090
5168
 
5091
5169
  values = {}
@@ -5124,6 +5202,7 @@ class TerrascriptClient:
5124
5202
  values["subject_alternative_names"] = alt_names
5125
5203
 
5126
5204
  region = common_values.get("region") or self.default_regions.get(account)
5205
+ assert region # make mypy happy
5127
5206
  if self._multiregion_account(account):
5128
5207
  values["provider"] = "aws." + region
5129
5208
 
@@ -5165,13 +5244,15 @@ class TerrascriptClient:
5165
5244
 
5166
5245
  self.add_resources(account, tf_resources)
5167
5246
 
5168
- def populate_tf_resource_s3_cloudfront_public_key(self, spec):
5247
+ def populate_tf_resource_s3_cloudfront_public_key(
5248
+ self, spec: ExternalResourceSpec
5249
+ ) -> None:
5169
5250
  account = spec.provisioner_name
5170
5251
  identifier = spec.identifier
5171
5252
  common_values = self.init_values(spec)
5172
5253
  output_prefix = spec.output_prefix
5173
5254
 
5174
- tf_resources = []
5255
+ tf_resources: list[TFResource] = []
5175
5256
  self.init_common_outputs(tf_resources, spec)
5176
5257
 
5177
5258
  values = {"name": identifier, "comment": "managed by app-interface"}
@@ -5213,8 +5294,13 @@ class TerrascriptClient:
5213
5294
  self.add_resources(account, tf_resources)
5214
5295
 
5215
5296
  def _get_alb_target_ips_by_openshift_service(
5216
- self, identifier, openshift_service, account_name, namespace_info, ocm_map
5217
- ):
5297
+ self,
5298
+ identifier: str,
5299
+ openshift_service: str,
5300
+ account_name: str,
5301
+ namespace_info: Mapping[str, Any],
5302
+ ocm_map: OCMMap,
5303
+ ) -> set[str]:
5218
5304
  account = self.accounts[account_name]
5219
5305
  cluster = namespace_info["cluster"]
5220
5306
  ocm = ocm_map.get(cluster["name"])
@@ -5240,7 +5326,9 @@ class TerrascriptClient:
5240
5326
  return ips
5241
5327
 
5242
5328
  @staticmethod
5243
- def _get_alb_rule_condition_value(condition):
5329
+ def _get_alb_rule_condition_value(
5330
+ condition: Mapping[str, Any],
5331
+ ) -> dict[str, dict[str, str]]:
5244
5332
  condition_type = condition["type"]
5245
5333
  condition_type_key = SUPPORTED_ALB_LISTENER_RULE_CONDITION_TYPE_MAPPING.get(
5246
5334
  condition_type
@@ -5250,7 +5338,7 @@ class TerrascriptClient:
5250
5338
  return {condition_type_key: {"values": condition[condition_type_key]}}
5251
5339
 
5252
5340
  @staticmethod
5253
- def _get_principal_for_s3_bucket_policy(region: str) -> Mapping[str, str]:
5341
+ def _get_principal_for_s3_bucket_policy(region: str) -> dict[str, str]:
5254
5342
  if region in AWS_ELB_ACCOUNT_IDS:
5255
5343
  return {"AWS": f"arn:aws:iam::{AWS_ELB_ACCOUNT_IDS[region]}:root"}
5256
5344
  if region in AWS_US_GOV_ELB_ACCOUNT_IDS:
@@ -5259,16 +5347,18 @@ class TerrascriptClient:
5259
5347
  }
5260
5348
  return {"Service": "logdelivery.elasticloadbalancing.amazonaws.com"}
5261
5349
 
5262
- def populate_tf_resource_alb(self, spec, ocm_map=None):
5350
+ def populate_tf_resource_alb(
5351
+ self, spec: ExternalResourceSpec, ocm_map: OCMMap | None = None
5352
+ ) -> None:
5263
5353
  account = spec.provisioner_name
5264
5354
  identifier = spec.identifier
5265
5355
  common_values = self.init_values(spec)
5266
5356
  output_prefix = spec.output_prefix
5267
- tf_resources = []
5357
+ tf_resources: list[TFResource] = []
5268
5358
  namespace_info = spec.namespace
5269
5359
  self.init_common_outputs(tf_resources, spec)
5270
5360
 
5271
- default_region = self.default_regions.get(account)
5361
+ default_region = self.default_regions[account]
5272
5362
  cluster_region = namespace_info["cluster"]["spec"]["region"]
5273
5363
 
5274
5364
  if self._multiregion_account(account):
@@ -5421,6 +5511,10 @@ class TerrascriptClient:
5421
5511
  t_protocol_version = t.get("protocol_version") or "HTTP1"
5422
5512
 
5423
5513
  if t_openshift_service:
5514
+ if ocm_map is None:
5515
+ raise ValueError(
5516
+ "ocm_map should be not none raising exception to make mypy happy"
5517
+ )
5424
5518
  target_ips = self._get_alb_target_ips_by_openshift_service(
5425
5519
  identifier, t_openshift_service, account, namespace_info, ocm_map
5426
5520
  )
@@ -5593,7 +5687,7 @@ class TerrascriptClient:
5593
5687
  for rule_num, rule in enumerate(resource["rules"]):
5594
5688
  # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener_rule#type
5595
5689
  action = rule["action"]
5596
- action_values = {}
5690
+ action_values: dict[str, Any] = {}
5597
5691
  action_type = action.get("type")
5598
5692
  if action_type == "forward":
5599
5693
  action_values = {
@@ -5679,18 +5773,19 @@ class TerrascriptClient:
5679
5773
 
5680
5774
  self.add_resources(account, tf_resources)
5681
5775
 
5682
- def populate_tf_resource_secrets_manager(self, spec):
5776
+ def populate_tf_resource_secrets_manager(self, spec: ExternalResourceSpec) -> None:
5683
5777
  account = spec.provisioner_name
5684
5778
  identifier = spec.identifier
5685
5779
  common_values = self.init_values(spec)
5686
5780
  output_prefix = spec.output_prefix
5687
5781
 
5688
- tf_resources = []
5782
+ tf_resources: list[TFResource] = []
5689
5783
  self.init_common_outputs(tf_resources, spec)
5690
5784
 
5691
5785
  values = {"name": identifier}
5692
5786
 
5693
5787
  region = common_values.get("region") or self.default_regions.get(account)
5788
+ assert region # make mypy happy
5694
5789
  if self._multiregion_account(account):
5695
5790
  values["provider"] = "aws." + region
5696
5791
 
@@ -5698,9 +5793,10 @@ class TerrascriptClient:
5698
5793
  tf_resources.append(aws_secret_resource)
5699
5794
 
5700
5795
  secret = common_values.get("secret")
5796
+ assert secret # make mypy happy
5701
5797
  secret_data = self.secret_reader.read_all(secret)
5702
5798
 
5703
- version_values = {
5799
+ version_values: dict[str, Any] = {
5704
5800
  "secret_id": "${" + aws_secret_resource.id + "}",
5705
5801
  "secret_string": json.dumps(secret_data, sort_keys=True),
5706
5802
  }
@@ -5781,7 +5877,7 @@ class TerrascriptClient:
5781
5877
  return True
5782
5878
  return False
5783
5879
 
5784
- def populate_tf_resource_asg(self, spec) -> None:
5880
+ def populate_tf_resource_asg(self, spec: ExternalResourceSpec) -> None:
5785
5881
  account = spec.provisioner_name
5786
5882
  identifier = spec.identifier
5787
5883
  common_values = self.init_values(spec)
@@ -5868,7 +5964,7 @@ class TerrascriptClient:
5868
5964
  template_resource = aws_launch_template(identifier, **template_values)
5869
5965
  tf_resources.append(template_resource)
5870
5966
 
5871
- asg_value = {
5967
+ asg_value: dict[str, Any] = {
5872
5968
  "name": identifier,
5873
5969
  "max_size": common_values.get("max_size"),
5874
5970
  "min_size": common_values.get("min_size"),
@@ -5924,12 +6020,12 @@ class TerrascriptClient:
5924
6020
 
5925
6021
  self.add_resources(account, tf_resources)
5926
6022
 
5927
- def populate_tf_resource_route53_zone(self, spec):
6023
+ def populate_tf_resource_route53_zone(self, spec: ExternalResourceSpec) -> None:
5928
6024
  account = spec.provisioner_name
5929
6025
  identifier = spec.identifier
5930
6026
  common_values = self.init_values(spec)
5931
6027
  output_prefix = spec.output_prefix
5932
- tf_resources = []
6028
+ tf_resources: list[TFResource] = []
5933
6029
  self.init_common_outputs(tf_resources, spec)
5934
6030
 
5935
6031
  # https://www.terraform.io/docs/providers/aws/r/route53_zone.html
@@ -5973,16 +6069,20 @@ class TerrascriptClient:
5973
6069
 
5974
6070
  self.add_resources(account, tf_resources)
5975
6071
 
5976
- def populate_tf_resource_rosa_authenticator(self, spec):
6072
+ def populate_tf_resource_rosa_authenticator(
6073
+ self, spec: ExternalResourceSpec
6074
+ ) -> None:
5977
6075
  account = spec.provisioner_name
5978
6076
  identifier = spec.identifier
5979
6077
  common_values = self.init_values(spec)
5980
- tf_resources = []
6078
+ tf_resources: list[TFResource] = []
5981
6079
  self.init_common_outputs(tf_resources, spec)
5982
6080
 
5983
6081
  # Prepare consts
5984
6082
  region = common_values.get("region") or self.default_regions.get(account)
6083
+ assert region # make mypy happy
5985
6084
  bucket_name = common_values.get("cognito_callback_bucket_name")
6085
+ assert bucket_name # make mypy happy
5986
6086
  bucket_url = f"https://{bucket_name}.s3.{region}.amazonaws.com"
5987
6087
  lambda_managed_policy_arn = (
5988
6088
  "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
@@ -5992,6 +6092,7 @@ class TerrascriptClient:
5992
6092
  vpc_id = common_values.get("vpc_id")
5993
6093
  subnet_ids = common_values.get("subnet_ids")
5994
6094
  network_interface_ids = common_values.get("network_interface_ids")
6095
+ assert network_interface_ids is not None # make mypy happy
5995
6096
  certificate_arn = common_values.get("certificate_arn")
5996
6097
  domain_name = common_values.get("domain_name")
5997
6098
  openshift_ingress_load_balancer_arn = common_values.get(
@@ -6868,15 +6969,18 @@ class TerrascriptClient:
6868
6969
 
6869
6970
  self.add_resources(account, tf_resources)
6870
6971
 
6871
- def populate_tf_resource_rosa_authenticator_vpce(self, spec):
6972
+ def populate_tf_resource_rosa_authenticator_vpce(
6973
+ self, spec: ExternalResourceSpec
6974
+ ) -> None:
6872
6975
  account = spec.provisioner_name
6873
6976
  identifier = spec.identifier
6874
6977
  common_values = self.init_values(spec)
6875
- tf_resources = []
6978
+ tf_resources: list[TFResource] = []
6876
6979
  self.init_common_outputs(tf_resources, spec)
6877
6980
 
6878
6981
  vpc_id = common_values.get("vpc_id")
6879
6982
  subnet_ids = common_values.get("subnet_ids")
6983
+ assert subnet_ids is not None # make mypy happy
6880
6984
  vpce_security_group_rule_common_args = common_values.get(
6881
6985
  "vpce_security_group_rule_common_properties", None
6882
6986
  )
@@ -6935,11 +7039,11 @@ class TerrascriptClient:
6935
7039
 
6936
7040
  self.add_resources(account, tf_resources)
6937
7041
 
6938
- def populate_tf_resource_msk(self, spec):
7042
+ def populate_tf_resource_msk(self, spec: ExternalResourceSpec) -> None:
6939
7043
  account = spec.provisioner_name
6940
7044
  values = self.init_values(spec)
6941
7045
  output_prefix = spec.output_prefix
6942
- tf_resources = []
7046
+ tf_resources: list[TFResource] = []
6943
7047
  resource_id = spec.identifier
6944
7048
 
6945
7049
  del values["identifier"]