cartography 0.102.0rc2__py3-none-any.whl → 0.103.0rc1__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.

Potentially problematic release.


This version of cartography might be problematic. Click here for more details.

Files changed (251) hide show
  1. cartography/__main__.py +1 -2
  2. cartography/_version.py +2 -2
  3. cartography/cli.py +302 -253
  4. cartography/client/core/tx.py +39 -18
  5. cartography/config.py +4 -0
  6. cartography/driftdetect/__main__.py +1 -2
  7. cartography/driftdetect/add_shortcut.py +10 -2
  8. cartography/driftdetect/cli.py +71 -75
  9. cartography/driftdetect/detect_deviations.py +7 -3
  10. cartography/driftdetect/get_states.py +20 -8
  11. cartography/driftdetect/model.py +5 -5
  12. cartography/driftdetect/serializers.py +8 -6
  13. cartography/driftdetect/storage.py +2 -2
  14. cartography/graph/cleanupbuilder.py +35 -15
  15. cartography/graph/job.py +46 -17
  16. cartography/graph/querybuilder.py +165 -80
  17. cartography/graph/statement.py +35 -26
  18. cartography/intel/analysis.py +4 -1
  19. cartography/intel/aws/__init__.py +114 -55
  20. cartography/intel/aws/apigateway.py +134 -63
  21. cartography/intel/aws/cloudtrail.py +127 -0
  22. cartography/intel/aws/config.py +56 -20
  23. cartography/intel/aws/dynamodb.py +108 -40
  24. cartography/intel/aws/ec2/__init__.py +2 -2
  25. cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
  26. cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
  27. cartography/intel/aws/ec2/images.py +49 -20
  28. cartography/intel/aws/ec2/instances.py +234 -136
  29. cartography/intel/aws/ec2/internet_gateways.py +40 -11
  30. cartography/intel/aws/ec2/key_pairs.py +44 -20
  31. cartography/intel/aws/ec2/launch_templates.py +101 -59
  32. cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
  33. cartography/intel/aws/ec2/load_balancers.py +82 -42
  34. cartography/intel/aws/ec2/network_acls.py +89 -65
  35. cartography/intel/aws/ec2/network_interfaces.py +146 -87
  36. cartography/intel/aws/ec2/reserved_instances.py +45 -16
  37. cartography/intel/aws/ec2/route_tables.py +138 -98
  38. cartography/intel/aws/ec2/security_groups.py +71 -21
  39. cartography/intel/aws/ec2/snapshots.py +61 -22
  40. cartography/intel/aws/ec2/subnets.py +54 -18
  41. cartography/intel/aws/ec2/tgw.py +100 -34
  42. cartography/intel/aws/ec2/util.py +1 -1
  43. cartography/intel/aws/ec2/volumes.py +69 -41
  44. cartography/intel/aws/ec2/vpc.py +37 -12
  45. cartography/intel/aws/ec2/vpc_peerings.py +83 -24
  46. cartography/intel/aws/ecr.py +88 -32
  47. cartography/intel/aws/ecs.py +83 -47
  48. cartography/intel/aws/eks.py +55 -29
  49. cartography/intel/aws/elasticache.py +42 -18
  50. cartography/intel/aws/elasticsearch.py +57 -20
  51. cartography/intel/aws/emr.py +61 -23
  52. cartography/intel/aws/iam.py +401 -145
  53. cartography/intel/aws/iam_instance_profiles.py +22 -22
  54. cartography/intel/aws/identitycenter.py +71 -37
  55. cartography/intel/aws/inspector.py +159 -89
  56. cartography/intel/aws/kms.py +92 -38
  57. cartography/intel/aws/lambda_function.py +103 -34
  58. cartography/intel/aws/organizations.py +30 -10
  59. cartography/intel/aws/permission_relationships.py +133 -51
  60. cartography/intel/aws/rds.py +249 -85
  61. cartography/intel/aws/redshift.py +107 -46
  62. cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
  63. cartography/intel/aws/resources.py +53 -46
  64. cartography/intel/aws/route53.py +108 -61
  65. cartography/intel/aws/s3.py +168 -83
  66. cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
  67. cartography/intel/aws/secretsmanager.py +24 -12
  68. cartography/intel/aws/securityhub.py +20 -9
  69. cartography/intel/aws/sns.py +166 -0
  70. cartography/intel/aws/sqs.py +60 -28
  71. cartography/intel/aws/ssm.py +70 -30
  72. cartography/intel/aws/util/arns.py +7 -7
  73. cartography/intel/aws/util/common.py +31 -4
  74. cartography/intel/azure/__init__.py +78 -19
  75. cartography/intel/azure/compute.py +101 -27
  76. cartography/intel/azure/cosmosdb.py +496 -170
  77. cartography/intel/azure/sql.py +296 -105
  78. cartography/intel/azure/storage.py +322 -113
  79. cartography/intel/azure/subscription.py +39 -23
  80. cartography/intel/azure/tenant.py +13 -4
  81. cartography/intel/azure/util/credentials.py +95 -55
  82. cartography/intel/bigfix/__init__.py +2 -2
  83. cartography/intel/bigfix/computers.py +93 -65
  84. cartography/intel/create_indexes.py +3 -2
  85. cartography/intel/crowdstrike/__init__.py +11 -9
  86. cartography/intel/crowdstrike/endpoints.py +5 -1
  87. cartography/intel/crowdstrike/spotlight.py +8 -3
  88. cartography/intel/cve/__init__.py +46 -13
  89. cartography/intel/cve/feed.py +48 -12
  90. cartography/intel/digitalocean/__init__.py +22 -13
  91. cartography/intel/digitalocean/compute.py +75 -108
  92. cartography/intel/digitalocean/management.py +44 -80
  93. cartography/intel/digitalocean/platform.py +48 -43
  94. cartography/intel/dns.py +36 -10
  95. cartography/intel/duo/__init__.py +21 -16
  96. cartography/intel/duo/api_host.py +14 -9
  97. cartography/intel/duo/endpoints.py +50 -45
  98. cartography/intel/duo/groups.py +18 -14
  99. cartography/intel/duo/phones.py +37 -34
  100. cartography/intel/duo/tokens.py +26 -23
  101. cartography/intel/duo/users.py +54 -50
  102. cartography/intel/duo/web_authn_credentials.py +30 -25
  103. cartography/intel/entra/__init__.py +25 -7
  104. cartography/intel/entra/ou.py +112 -0
  105. cartography/intel/entra/users.py +69 -63
  106. cartography/intel/gcp/__init__.py +185 -49
  107. cartography/intel/gcp/compute.py +418 -231
  108. cartography/intel/gcp/crm.py +96 -43
  109. cartography/intel/gcp/dns.py +60 -19
  110. cartography/intel/gcp/gke.py +72 -38
  111. cartography/intel/gcp/iam.py +61 -41
  112. cartography/intel/gcp/storage.py +84 -55
  113. cartography/intel/github/__init__.py +13 -11
  114. cartography/intel/github/repos.py +270 -137
  115. cartography/intel/github/teams.py +170 -88
  116. cartography/intel/github/users.py +70 -39
  117. cartography/intel/github/util.py +36 -34
  118. cartography/intel/gsuite/__init__.py +47 -26
  119. cartography/intel/gsuite/api.py +73 -30
  120. cartography/intel/jamf/__init__.py +19 -1
  121. cartography/intel/jamf/computers.py +30 -7
  122. cartography/intel/jamf/util.py +7 -2
  123. cartography/intel/kandji/__init__.py +6 -3
  124. cartography/intel/kandji/devices.py +14 -8
  125. cartography/intel/kubernetes/namespaces.py +7 -4
  126. cartography/intel/kubernetes/pods.py +7 -4
  127. cartography/intel/kubernetes/services.py +8 -4
  128. cartography/intel/lastpass/__init__.py +2 -2
  129. cartography/intel/lastpass/users.py +23 -12
  130. cartography/intel/oci/__init__.py +44 -11
  131. cartography/intel/oci/iam.py +134 -38
  132. cartography/intel/oci/organizations.py +13 -6
  133. cartography/intel/oci/utils.py +43 -20
  134. cartography/intel/okta/__init__.py +66 -15
  135. cartography/intel/okta/applications.py +42 -20
  136. cartography/intel/okta/awssaml.py +93 -33
  137. cartography/intel/okta/factors.py +16 -4
  138. cartography/intel/okta/groups.py +56 -29
  139. cartography/intel/okta/organization.py +5 -1
  140. cartography/intel/okta/origins.py +6 -2
  141. cartography/intel/okta/roles.py +15 -5
  142. cartography/intel/okta/users.py +20 -8
  143. cartography/intel/okta/utils.py +6 -4
  144. cartography/intel/pagerduty/__init__.py +8 -7
  145. cartography/intel/pagerduty/escalation_policies.py +18 -6
  146. cartography/intel/pagerduty/schedules.py +12 -4
  147. cartography/intel/pagerduty/services.py +11 -4
  148. cartography/intel/pagerduty/teams.py +8 -3
  149. cartography/intel/pagerduty/users.py +3 -1
  150. cartography/intel/pagerduty/vendors.py +3 -1
  151. cartography/intel/semgrep/__init__.py +24 -6
  152. cartography/intel/semgrep/dependencies.py +50 -28
  153. cartography/intel/semgrep/deployment.py +3 -1
  154. cartography/intel/semgrep/findings.py +42 -18
  155. cartography/intel/snipeit/__init__.py +17 -3
  156. cartography/intel/snipeit/asset.py +12 -6
  157. cartography/intel/snipeit/user.py +8 -5
  158. cartography/intel/snipeit/util.py +9 -4
  159. cartography/models/aws/apigateway.py +21 -17
  160. cartography/models/aws/apigatewaycertificate.py +28 -22
  161. cartography/models/aws/apigatewayresource.py +28 -20
  162. cartography/models/aws/apigatewaystage.py +33 -25
  163. cartography/models/aws/cloudtrail/__init__.py +0 -0
  164. cartography/models/aws/cloudtrail/trail.py +61 -0
  165. cartography/models/aws/dynamodb/gsi.py +30 -22
  166. cartography/models/aws/dynamodb/tables.py +25 -17
  167. cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
  168. cartography/models/aws/ec2/images.py +36 -34
  169. cartography/models/aws/ec2/instances.py +51 -45
  170. cartography/models/aws/ec2/keypair.py +21 -16
  171. cartography/models/aws/ec2/keypair_instance.py +28 -21
  172. cartography/models/aws/ec2/launch_configurations.py +30 -26
  173. cartography/models/aws/ec2/launch_template_versions.py +48 -38
  174. cartography/models/aws/ec2/launch_templates.py +21 -17
  175. cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
  176. cartography/models/aws/ec2/load_balancers.py +47 -37
  177. cartography/models/aws/ec2/network_acl_rules.py +38 -30
  178. cartography/models/aws/ec2/network_acls.py +38 -29
  179. cartography/models/aws/ec2/networkinterface_instance.py +52 -39
  180. cartography/models/aws/ec2/networkinterfaces.py +53 -37
  181. cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
  182. cartography/models/aws/ec2/reservations.py +18 -14
  183. cartography/models/aws/ec2/route_table_associations.py +44 -34
  184. cartography/models/aws/ec2/route_tables.py +50 -43
  185. cartography/models/aws/ec2/routes.py +45 -37
  186. cartography/models/aws/ec2/securitygroup_instance.py +29 -20
  187. cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
  188. cartography/models/aws/ec2/subnet_instance.py +24 -19
  189. cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
  190. cartography/models/aws/ec2/volumes.py +47 -40
  191. cartography/models/aws/eks/clusters.py +23 -21
  192. cartography/models/aws/emr.py +32 -30
  193. cartography/models/aws/iam/instanceprofile.py +33 -24
  194. cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
  195. cartography/models/aws/identitycenter/awspermissionset.py +37 -29
  196. cartography/models/aws/identitycenter/awsssouser.py +23 -21
  197. cartography/models/aws/inspector/findings.py +77 -65
  198. cartography/models/aws/inspector/packages.py +35 -29
  199. cartography/models/aws/s3/__init__.py +0 -0
  200. cartography/models/aws/s3/account_public_access_block.py +51 -0
  201. cartography/models/aws/sns/__init__.py +0 -0
  202. cartography/models/aws/sns/topic.py +50 -0
  203. cartography/models/aws/ssm/instance_information.py +51 -39
  204. cartography/models/aws/ssm/instance_patch.py +32 -26
  205. cartography/models/bigfix/bigfix_computer.py +42 -38
  206. cartography/models/bigfix/bigfix_root.py +3 -3
  207. cartography/models/core/common.py +12 -10
  208. cartography/models/core/nodes.py +5 -2
  209. cartography/models/core/relationships.py +14 -6
  210. cartography/models/crowdstrike/hosts.py +37 -35
  211. cartography/models/cve/cve.py +34 -32
  212. cartography/models/cve/cve_feed.py +6 -6
  213. cartography/models/digitalocean/__init__.py +0 -0
  214. cartography/models/digitalocean/account.py +21 -0
  215. cartography/models/digitalocean/droplet.py +56 -0
  216. cartography/models/digitalocean/project.py +48 -0
  217. cartography/models/duo/api_host.py +3 -3
  218. cartography/models/duo/endpoint.py +43 -41
  219. cartography/models/duo/group.py +14 -14
  220. cartography/models/duo/phone.py +27 -27
  221. cartography/models/duo/token.py +16 -16
  222. cartography/models/duo/user.py +46 -44
  223. cartography/models/duo/web_authn_credential.py +27 -19
  224. cartography/models/entra/ou.py +48 -0
  225. cartography/models/entra/tenant.py +24 -18
  226. cartography/models/entra/user.py +64 -48
  227. cartography/models/gcp/iam.py +23 -23
  228. cartography/models/github/orgs.py +5 -4
  229. cartography/models/github/teams.py +37 -31
  230. cartography/models/github/users.py +34 -23
  231. cartography/models/kandji/device.py +22 -16
  232. cartography/models/kandji/tenant.py +6 -4
  233. cartography/models/lastpass/tenant.py +3 -3
  234. cartography/models/lastpass/user.py +32 -28
  235. cartography/models/semgrep/dependencies.py +36 -24
  236. cartography/models/semgrep/deployment.py +5 -5
  237. cartography/models/semgrep/findings.py +58 -42
  238. cartography/models/semgrep/locations.py +27 -21
  239. cartography/models/snipeit/asset.py +30 -21
  240. cartography/models/snipeit/tenant.py +6 -4
  241. cartography/models/snipeit/user.py +19 -12
  242. cartography/stats.py +3 -3
  243. cartography/sync.py +107 -31
  244. cartography/util.py +84 -62
  245. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/METADATA +3 -14
  246. cartography-0.103.0rc1.dist-info/RECORD +396 -0
  247. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/WHEEL +1 -1
  248. cartography-0.102.0rc2.dist-info/RECORD +0 -381
  249. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/entry_points.txt +0 -0
  250. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/licenses/LICENSE +0 -0
  251. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/top_level.txt +0 -0
@@ -5,25 +5,36 @@ from typing import List
5
5
  import boto3
6
6
  import neo4j
7
7
 
8
- from .util import get_botocore_config
9
8
  from cartography.util import aws_handle_regions
10
9
  from cartography.util import run_cleanup_job
11
10
  from cartography.util import timeit
12
11
 
12
+ from .util import get_botocore_config
13
+
13
14
  logger = logging.getLogger(__name__)
14
15
 
15
16
 
16
17
  @timeit
17
18
  @aws_handle_regions
18
- def get_internet_gateways(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
19
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
20
- return client.describe_internet_gateways()['InternetGateways']
19
+ def get_internet_gateways(
20
+ boto3_session: boto3.session.Session,
21
+ region: str,
22
+ ) -> List[Dict]:
23
+ client = boto3_session.client(
24
+ "ec2",
25
+ region_name=region,
26
+ config=get_botocore_config(),
27
+ )
28
+ return client.describe_internet_gateways()["InternetGateways"]
21
29
 
22
30
 
23
31
  @timeit
24
32
  def load_internet_gateways(
25
- neo4j_session: neo4j.Session, internet_gateways: List[Dict], region: str,
26
- current_aws_account_id: str, update_tag: int,
33
+ neo4j_session: neo4j.Session,
34
+ internet_gateways: List[Dict],
35
+ region: str,
36
+ current_aws_account_id: str,
37
+ update_tag: int,
27
38
  ) -> None:
28
39
  logger.info("Loading %d Internet Gateways in %s.", len(internet_gateways), region)
29
40
  # TODO: Right now this won't work in non-AWS commercial (GovCloud, China) as partition is hardcoded
@@ -64,17 +75,35 @@ def load_internet_gateways(
64
75
  @timeit
65
76
  def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
66
77
  logger.debug("Running Internet Gateway cleanup job.")
67
- run_cleanup_job('aws_import_internet_gateways_cleanup.json', neo4j_session, common_job_parameters)
78
+ run_cleanup_job(
79
+ "aws_import_internet_gateways_cleanup.json",
80
+ neo4j_session,
81
+ common_job_parameters,
82
+ )
68
83
 
69
84
 
70
85
  @timeit
71
86
  def sync_internet_gateways(
72
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
73
- update_tag: int, common_job_parameters: Dict,
87
+ neo4j_session: neo4j.Session,
88
+ boto3_session: boto3.session.Session,
89
+ regions: List[str],
90
+ current_aws_account_id: str,
91
+ update_tag: int,
92
+ common_job_parameters: Dict,
74
93
  ) -> None:
75
94
  for region in regions:
76
- logger.info("Syncing Internet Gateways for region '%s' in account '%s'.", region, current_aws_account_id)
95
+ logger.info(
96
+ "Syncing Internet Gateways for region '%s' in account '%s'.",
97
+ region,
98
+ current_aws_account_id,
99
+ )
77
100
  internet_gateways = get_internet_gateways(boto3_session, region)
78
- load_internet_gateways(neo4j_session, internet_gateways, region, current_aws_account_id, update_tag)
101
+ load_internet_gateways(
102
+ neo4j_session,
103
+ internet_gateways,
104
+ region,
105
+ current_aws_account_id,
106
+ update_tag,
107
+ )
79
108
 
80
109
  cleanup(neo4j_session, common_job_parameters)
@@ -17,34 +17,43 @@ logger = logging.getLogger(__name__)
17
17
 
18
18
  @timeit
19
19
  @aws_handle_regions
20
- def get_ec2_key_pairs(boto3_session: boto3.session.Session, region: str) -> list[dict[str, Any]]:
21
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
22
- return client.describe_key_pairs()['KeyPairs']
20
+ def get_ec2_key_pairs(
21
+ boto3_session: boto3.session.Session,
22
+ region: str,
23
+ ) -> list[dict[str, Any]]:
24
+ client = boto3_session.client(
25
+ "ec2",
26
+ region_name=region,
27
+ config=get_botocore_config(),
28
+ )
29
+ return client.describe_key_pairs()["KeyPairs"]
23
30
 
24
31
 
25
32
  def transform_ec2_key_pairs(
26
- key_pairs: list[dict[str, Any]],
27
- region: str,
28
- current_aws_account_id: str,
33
+ key_pairs: list[dict[str, Any]],
34
+ region: str,
35
+ current_aws_account_id: str,
29
36
  ) -> list[dict[str, Any]]:
30
37
  transformed_key_pairs = []
31
38
  for key_pair in key_pairs:
32
39
  key_name = key_pair["KeyName"]
33
- transformed_key_pairs.append({
34
- 'KeyPairArn': f'arn:aws:ec2:{region}:{current_aws_account_id}:key-pair/{key_name}',
35
- 'KeyName': key_name,
36
- 'KeyFingerprint': key_pair.get("KeyFingerprint"),
37
- })
40
+ transformed_key_pairs.append(
41
+ {
42
+ "KeyPairArn": f"arn:aws:ec2:{region}:{current_aws_account_id}:key-pair/{key_name}",
43
+ "KeyName": key_name,
44
+ "KeyFingerprint": key_pair.get("KeyFingerprint"),
45
+ },
46
+ )
38
47
  return transformed_key_pairs
39
48
 
40
49
 
41
50
  @timeit
42
51
  def load_ec2_key_pairs(
43
- neo4j_session: neo4j.Session,
44
- data: list[dict[str, Any]],
45
- region: str,
46
- current_aws_account_id: str,
47
- update_tag: int,
52
+ neo4j_session: neo4j.Session,
53
+ data: list[dict[str, Any]],
54
+ region: str,
55
+ current_aws_account_id: str,
56
+ update_tag: int,
48
57
  ) -> None:
49
58
  # Load EC2 keypairs as known by describe-key-pairs
50
59
  logger.info(f"Loading {len(data)} EC2 keypairs for region '{region}' into graph.")
@@ -59,8 +68,13 @@ def load_ec2_key_pairs(
59
68
 
60
69
 
61
70
  @timeit
62
- def cleanup_ec2_key_pairs(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
63
- GraphJob.from_node_schema(EC2KeyPairSchema(), common_job_parameters).run(neo4j_session)
71
+ def cleanup_ec2_key_pairs(
72
+ neo4j_session: neo4j.Session,
73
+ common_job_parameters: Dict,
74
+ ) -> None:
75
+ GraphJob.from_node_schema(EC2KeyPairSchema(), common_job_parameters).run(
76
+ neo4j_session,
77
+ )
64
78
 
65
79
 
66
80
  @timeit
@@ -73,8 +87,18 @@ def sync_ec2_key_pairs(
73
87
  common_job_parameters: dict[str, Any],
74
88
  ) -> None:
75
89
  for region in regions:
76
- logger.info("Syncing EC2 key pairs for region '%s' in account '%s'.", region, current_aws_account_id)
90
+ logger.info(
91
+ "Syncing EC2 key pairs for region '%s' in account '%s'.",
92
+ region,
93
+ current_aws_account_id,
94
+ )
77
95
  data = get_ec2_key_pairs(boto3_session, region)
78
96
  transformed_data = transform_ec2_key_pairs(data, region, current_aws_account_id)
79
- load_ec2_key_pairs(neo4j_session, transformed_data, region, current_aws_account_id, update_tag)
97
+ load_ec2_key_pairs(
98
+ neo4j_session,
99
+ transformed_data,
100
+ region,
101
+ current_aws_account_id,
102
+ update_tag,
103
+ )
80
104
  cleanup_ec2_key_pairs(neo4j_session, common_job_parameters)
@@ -5,14 +5,17 @@ import boto3
5
5
  import botocore
6
6
  import neo4j
7
7
 
8
- from .util import get_botocore_config
9
8
  from cartography.client.core.tx import load
10
9
  from cartography.graph.job import GraphJob
11
- from cartography.models.aws.ec2.launch_template_versions import LaunchTemplateVersionSchema
10
+ from cartography.models.aws.ec2.launch_template_versions import (
11
+ LaunchTemplateVersionSchema,
12
+ )
12
13
  from cartography.models.aws.ec2.launch_templates import LaunchTemplateSchema
13
14
  from cartography.util import aws_handle_regions
14
15
  from cartography.util import timeit
15
16
 
17
+ from .util import get_botocore_config
18
+
16
19
  logger = logging.getLogger(__name__)
17
20
 
18
21
 
@@ -22,11 +25,13 @@ def get_launch_templates(
22
25
  boto3_session: boto3.session.Session,
23
26
  region: str,
24
27
  ) -> list[dict[str, Any]]:
25
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
26
- paginator = client.get_paginator('describe_launch_templates')
28
+ client = boto3_session.client(
29
+ "ec2", region_name=region, config=get_botocore_config()
30
+ )
31
+ paginator = client.get_paginator("describe_launch_templates")
27
32
  templates: list[dict[str, Any]] = []
28
33
  for page in paginator.paginate():
29
- paginated_templates = page['LaunchTemplates']
34
+ paginated_templates = page["LaunchTemplates"]
30
35
  templates.extend(paginated_templates)
31
36
  return templates
32
37
 
@@ -40,8 +45,10 @@ def get_launch_template_versions(
40
45
  ) -> list[dict[str, Any]]:
41
46
  template_versions: list[dict[str, Any]] = []
42
47
  for template in launch_templates:
43
- launch_template_id = template['LaunchTemplateId']
44
- versions = get_launch_template_versions_by_template(boto3_session, launch_template_id, region)
48
+ launch_template_id = template["LaunchTemplateId"]
49
+ versions = get_launch_template_versions_by_template(
50
+ boto3_session, launch_template_id, region
51
+ )
45
52
  template_versions.extend(versions)
46
53
 
47
54
  return template_versions
@@ -50,46 +57,54 @@ def get_launch_template_versions(
50
57
  @timeit
51
58
  @aws_handle_regions
52
59
  def get_launch_template_versions_by_template(
53
- boto3_session: boto3.session.Session,
54
- launch_template_id: str,
55
- region: str,
60
+ boto3_session: boto3.session.Session,
61
+ launch_template_id: str,
62
+ region: str,
56
63
  ) -> list[dict[str, Any]]:
57
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
58
- v_paginator = client.get_paginator('describe_launch_template_versions')
64
+ client = boto3_session.client(
65
+ "ec2", region_name=region, config=get_botocore_config()
66
+ )
67
+ v_paginator = client.get_paginator("describe_launch_template_versions")
59
68
  template_versions = []
60
69
  try:
61
70
  for versions in v_paginator.paginate(LaunchTemplateId=launch_template_id):
62
- template_versions.extend(versions['LaunchTemplateVersions'])
71
+ template_versions.extend(versions["LaunchTemplateVersions"])
63
72
  except botocore.exceptions.ClientError as e:
64
- error_code = e.response['Error']['Code']
65
- if error_code == 'InvalidLaunchTemplateId.NotFound':
66
- logger.warning("Launch template %s no longer exists in region %s", launch_template_id, region)
73
+ error_code = e.response["Error"]["Code"]
74
+ if error_code == "InvalidLaunchTemplateId.NotFound":
75
+ logger.warning(
76
+ "Launch template %s no longer exists in region %s",
77
+ launch_template_id,
78
+ region,
79
+ )
67
80
  else:
68
81
  raise
69
82
  return template_versions
70
83
 
71
84
 
72
- def transform_launch_templates(templates: list[dict[str, Any]], versions: list[dict[str, Any]]) -> list[dict[str, Any]]:
73
- valid_template_ids = {v['LaunchTemplateId'] for v in versions}
85
+ def transform_launch_templates(
86
+ templates: list[dict[str, Any]], versions: list[dict[str, Any]]
87
+ ) -> list[dict[str, Any]]:
88
+ valid_template_ids = {v["LaunchTemplateId"] for v in versions}
74
89
  result: list[dict[str, Any]] = []
75
90
  for template in templates:
76
- if template['LaunchTemplateId'] not in valid_template_ids:
91
+ if template["LaunchTemplateId"] not in valid_template_ids:
77
92
  continue
78
93
 
79
94
  current = template.copy()
80
95
  # Convert CreateTime to timestamp string
81
- current['CreateTime'] = str(int(current['CreateTime'].timestamp()))
96
+ current["CreateTime"] = str(int(current["CreateTime"].timestamp()))
82
97
  result.append(current)
83
98
  return result
84
99
 
85
100
 
86
101
  @timeit
87
102
  def load_launch_templates(
88
- neo4j_session: neo4j.Session,
89
- data: list[dict[str, Any]],
90
- region: str,
91
- current_aws_account_id: str,
92
- update_tag: int,
103
+ neo4j_session: neo4j.Session,
104
+ data: list[dict[str, Any]],
105
+ region: str,
106
+ current_aws_account_id: str,
107
+ update_tag: int,
93
108
  ) -> None:
94
109
  load(
95
110
  neo4j_session,
@@ -101,41 +116,45 @@ def load_launch_templates(
101
116
  )
102
117
 
103
118
 
104
- def transform_launch_template_versions(versions: list[dict[str, Any]]) -> list[dict[str, Any]]:
119
+ def transform_launch_template_versions(
120
+ versions: list[dict[str, Any]],
121
+ ) -> list[dict[str, Any]]:
105
122
  result: list[dict[str, Any]] = []
106
123
  for version in versions:
107
124
  current = version.copy()
108
125
 
109
126
  # Reformat some fields
110
- current['Id'] = f"{version['LaunchTemplateId']}-{version['VersionNumber']}"
111
- current['CreateTime'] = str(int(version['CreateTime'].timestamp()))
127
+ current["Id"] = f"{version['LaunchTemplateId']}-{version['VersionNumber']}"
128
+ current["CreateTime"] = str(int(version["CreateTime"].timestamp()))
112
129
 
113
130
  # Handle the nested object returned from boto
114
- ltd = version['LaunchTemplateData']
115
- current['KernelId'] = ltd.get('KernelId')
116
- current['EbsOptimized'] = ltd.get('EbsOptimized')
117
- current['IamInstanceProfileArn'] = ltd.get('IamInstanceProfileArn')
118
- current['IamInstanceProfileName'] = ltd.get('IamInstanceProfileName')
119
- current['ImageId'] = ltd.get('ImageId')
120
- current['InstanceType'] = ltd.get('InstanceType')
121
- current['KeyName'] = ltd.get('KeyName')
122
- current['MonitoringEnabled'] = ltd.get('MonitoringEnabled')
123
- current['RamdiskId'] = ltd.get('RamdiskId')
124
- current['DisableApiTermination'] = ltd.get('DisableApiTermination')
125
- current['InstanceInitiatedShutDownBehavior'] = ltd.get('InstanceInitiatedShutDownBehavior')
126
- current['SecurityGroupIds'] = ltd.get('SecurityGroupIds')
127
- current['SecurityGroups'] = ltd.get('SecurityGroups')
131
+ ltd = version["LaunchTemplateData"]
132
+ current["KernelId"] = ltd.get("KernelId")
133
+ current["EbsOptimized"] = ltd.get("EbsOptimized")
134
+ current["IamInstanceProfileArn"] = ltd.get("IamInstanceProfileArn")
135
+ current["IamInstanceProfileName"] = ltd.get("IamInstanceProfileName")
136
+ current["ImageId"] = ltd.get("ImageId")
137
+ current["InstanceType"] = ltd.get("InstanceType")
138
+ current["KeyName"] = ltd.get("KeyName")
139
+ current["MonitoringEnabled"] = ltd.get("MonitoringEnabled")
140
+ current["RamdiskId"] = ltd.get("RamdiskId")
141
+ current["DisableApiTermination"] = ltd.get("DisableApiTermination")
142
+ current["InstanceInitiatedShutDownBehavior"] = ltd.get(
143
+ "InstanceInitiatedShutDownBehavior",
144
+ )
145
+ current["SecurityGroupIds"] = ltd.get("SecurityGroupIds")
146
+ current["SecurityGroups"] = ltd.get("SecurityGroups")
128
147
  result.append(current)
129
148
  return result
130
149
 
131
150
 
132
151
  @timeit
133
152
  def load_launch_template_versions(
134
- neo4j_session: neo4j.Session,
135
- data: list[dict[str, Any]],
136
- region: str,
137
- current_aws_account_id: str,
138
- update_tag: int,
153
+ neo4j_session: neo4j.Session,
154
+ data: list[dict[str, Any]],
155
+ region: str,
156
+ current_aws_account_id: str,
157
+ update_tag: int,
139
158
  ) -> None:
140
159
  load(
141
160
  neo4j_session,
@@ -148,35 +167,58 @@ def load_launch_template_versions(
148
167
 
149
168
 
150
169
  @timeit
151
- def cleanup(neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]) -> None:
170
+ def cleanup(
171
+ neo4j_session: neo4j.Session,
172
+ common_job_parameters: dict[str, Any],
173
+ ) -> None:
152
174
  logger.info("Running launch template cleanup job.")
153
- cleanup_job = GraphJob.from_node_schema(LaunchTemplateSchema(), common_job_parameters)
175
+ cleanup_job = GraphJob.from_node_schema(
176
+ LaunchTemplateSchema(),
177
+ common_job_parameters,
178
+ )
154
179
  cleanup_job.run(neo4j_session)
155
180
 
156
- cleanup_job = GraphJob.from_node_schema(LaunchTemplateVersionSchema(), common_job_parameters)
181
+ cleanup_job = GraphJob.from_node_schema(
182
+ LaunchTemplateVersionSchema(),
183
+ common_job_parameters,
184
+ )
157
185
  cleanup_job.run(neo4j_session)
158
186
 
159
187
 
160
188
  @timeit
161
189
  def sync_ec2_launch_templates(
162
- neo4j_session: neo4j.Session,
163
- boto3_session: boto3.session.Session,
164
- regions: list[str],
165
- current_aws_account_id: str,
166
- update_tag: int,
167
- common_job_parameters: dict[str, Any],
190
+ neo4j_session: neo4j.Session,
191
+ boto3_session: boto3.session.Session,
192
+ regions: list[str],
193
+ current_aws_account_id: str,
194
+ update_tag: int,
195
+ common_job_parameters: dict[str, Any],
168
196
  ) -> None:
169
197
  for region in regions:
170
- logger.info(f"Syncing launch templates for region '{region}' in account '{current_aws_account_id}'.")
198
+ logger.info(
199
+ f"Syncing launch templates for region '{region}' in account '{current_aws_account_id}'."
200
+ )
171
201
  templates = get_launch_templates(boto3_session, region)
172
202
  versions = get_launch_template_versions(boto3_session, region, templates)
173
203
 
174
204
  # Transform and load the templates that have versions
175
205
  transformed_templates = transform_launch_templates(templates, versions)
176
- load_launch_templates(neo4j_session, transformed_templates, region, current_aws_account_id, update_tag)
206
+ load_launch_templates(
207
+ neo4j_session,
208
+ transformed_templates,
209
+ region,
210
+ current_aws_account_id,
211
+ update_tag,
212
+ )
177
213
 
178
214
  # Transform and load the versions
179
215
  transformed_versions = transform_launch_template_versions(versions)
180
- load_launch_template_versions(neo4j_session, transformed_versions, region, current_aws_account_id, update_tag)
216
+ load_launch_template_versions(
217
+ neo4j_session,
218
+ transformed_versions,
219
+ region,
220
+ current_aws_account_id,
221
+ update_tag,
222
+ )
181
223
 
182
224
  cleanup(neo4j_session, common_job_parameters)