cartography 0.102.0rc1__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 +327 -0
  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 -44
  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 +97 -0
  184. cartography/models/aws/ec2/route_tables.py +128 -0
  185. cartography/models/aws/ec2/routes.py +85 -0
  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.0rc1.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.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/WHEEL +1 -1
  248. cartography-0.102.0rc1.dist-info/RECORD +0 -377
  249. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/entry_points.txt +0 -0
  250. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/licenses/LICENSE +0 -0
  251. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/top_level.txt +0 -0
@@ -20,22 +20,28 @@ stat_handler = get_stats_client(__name__)
20
20
 
21
21
  @timeit
22
22
  @aws_handle_regions
23
- def get_rds_cluster_data(boto3_session: boto3.session.Session, region: str) -> List[Any]:
23
+ def get_rds_cluster_data(
24
+ boto3_session: boto3.session.Session,
25
+ region: str,
26
+ ) -> List[Any]:
24
27
  """
25
28
  Create an RDS boto3 client and grab all the DBClusters.
26
29
  """
27
- client = boto3_session.client('rds', region_name=region)
28
- paginator = client.get_paginator('describe_db_clusters')
30
+ client = boto3_session.client("rds", region_name=region)
31
+ paginator = client.get_paginator("describe_db_clusters")
29
32
  instances: List[Any] = []
30
33
  for page in paginator.paginate():
31
- instances.extend(page['DBClusters'])
34
+ instances.extend(page["DBClusters"])
32
35
 
33
36
  return instances
34
37
 
35
38
 
36
39
  @timeit
37
40
  def load_rds_clusters(
38
- neo4j_session: neo4j.Session, data: Dict, region: str, current_aws_account_id: str,
41
+ neo4j_session: neo4j.Session,
42
+ data: Dict,
43
+ region: str,
44
+ current_aws_account_id: str,
39
45
  aws_update_tag: int,
40
46
  ) -> None:
41
47
  """
@@ -94,13 +100,31 @@ def load_rds_clusters(
94
100
  # TODO: track security groups
95
101
  # TODO: track subnet groups
96
102
 
97
- cluster['EarliestRestorableTime'] = dict_value_to_str(cluster, 'EarliestRestorableTime')
98
- cluster['LatestRestorableTime'] = dict_value_to_str(cluster, 'LatestRestorableTime')
99
- cluster['ClusterCreateTime'] = dict_value_to_str(cluster, 'ClusterCreateTime')
100
- cluster['EarliestBacktrackTime'] = dict_value_to_str(cluster, 'EarliestBacktrackTime')
101
- cluster['ScalingConfigurationInfoMinCapacity'] = cluster.get('ScalingConfigurationInfo', {}).get('MinCapacity')
102
- cluster['ScalingConfigurationInfoMaxCapacity'] = cluster.get('ScalingConfigurationInfo', {}).get('MaxCapacity')
103
- cluster['ScalingConfigurationInfoAutoPause'] = cluster.get('ScalingConfigurationInfo', {}).get('AutoPause')
103
+ cluster["EarliestRestorableTime"] = dict_value_to_str(
104
+ cluster,
105
+ "EarliestRestorableTime",
106
+ )
107
+ cluster["LatestRestorableTime"] = dict_value_to_str(
108
+ cluster,
109
+ "LatestRestorableTime",
110
+ )
111
+ cluster["ClusterCreateTime"] = dict_value_to_str(cluster, "ClusterCreateTime")
112
+ cluster["EarliestBacktrackTime"] = dict_value_to_str(
113
+ cluster,
114
+ "EarliestBacktrackTime",
115
+ )
116
+ cluster["ScalingConfigurationInfoMinCapacity"] = cluster.get(
117
+ "ScalingConfigurationInfo",
118
+ {},
119
+ ).get("MinCapacity")
120
+ cluster["ScalingConfigurationInfoMaxCapacity"] = cluster.get(
121
+ "ScalingConfigurationInfo",
122
+ {},
123
+ ).get("MaxCapacity")
124
+ cluster["ScalingConfigurationInfoAutoPause"] = cluster.get(
125
+ "ScalingConfigurationInfo",
126
+ {},
127
+ ).get("AutoPause")
104
128
 
105
129
  neo4j_session.run(
106
130
  ingest_rds_cluster,
@@ -113,22 +137,28 @@ def load_rds_clusters(
113
137
 
114
138
  @timeit
115
139
  @aws_handle_regions
116
- def get_rds_instance_data(boto3_session: boto3.session.Session, region: str) -> List[Any]:
140
+ def get_rds_instance_data(
141
+ boto3_session: boto3.session.Session,
142
+ region: str,
143
+ ) -> List[Any]:
117
144
  """
118
145
  Create an RDS boto3 client and grab all the DBInstances.
119
146
  """
120
- client = boto3_session.client('rds', region_name=region)
121
- paginator = client.get_paginator('describe_db_instances')
147
+ client = boto3_session.client("rds", region_name=region)
148
+ paginator = client.get_paginator("describe_db_instances")
122
149
  instances: List[Any] = []
123
150
  for page in paginator.paginate():
124
- instances.extend(page['DBInstances'])
151
+ instances.extend(page["DBInstances"])
125
152
 
126
153
  return instances
127
154
 
128
155
 
129
156
  @timeit
130
157
  def load_rds_instances(
131
- neo4j_session: neo4j.Session, data: Dict, region: str, current_aws_account_id: str,
158
+ neo4j_session: neo4j.Session,
159
+ data: Dict,
160
+ region: str,
161
+ current_aws_account_id: str,
132
162
  aws_update_tag: int,
133
163
  ) -> None:
134
164
  """
@@ -192,17 +222,17 @@ def load_rds_instances(
192
222
  if rds.get("DBClusterIdentifier"):
193
223
  clusters.append(rds)
194
224
 
195
- if rds.get('VpcSecurityGroups'):
225
+ if rds.get("VpcSecurityGroups"):
196
226
  secgroups.append(rds)
197
227
 
198
- if rds.get('DBSubnetGroup'):
228
+ if rds.get("DBSubnetGroup"):
199
229
  subnets.append(rds)
200
230
 
201
- rds['InstanceCreateTime'] = dict_value_to_str(rds, 'InstanceCreateTime')
202
- rds['LatestRestorableTime'] = dict_value_to_str(rds, 'LatestRestorableTime')
203
- rds['EndpointAddress'] = ep.get('Address')
204
- rds['EndpointHostedZoneId'] = ep.get('HostedZoneId')
205
- rds['EndpointPort'] = ep.get('Port')
231
+ rds["InstanceCreateTime"] = dict_value_to_str(rds, "InstanceCreateTime")
232
+ rds["LatestRestorableTime"] = dict_value_to_str(rds, "LatestRestorableTime")
233
+ rds["EndpointAddress"] = ep.get("Address")
234
+ rds["EndpointHostedZoneId"] = ep.get("HostedZoneId")
235
+ rds["EndpointPort"] = ep.get("Port")
206
236
 
207
237
  neo4j_session.run(
208
238
  ingest_rds_instance,
@@ -212,24 +242,36 @@ def load_rds_instances(
212
242
  aws_update_tag=aws_update_tag,
213
243
  )
214
244
  _attach_ec2_security_groups(neo4j_session, secgroups, aws_update_tag)
215
- _attach_ec2_subnet_groups(neo4j_session, subnets, region, current_aws_account_id, aws_update_tag)
245
+ _attach_ec2_subnet_groups(
246
+ neo4j_session,
247
+ subnets,
248
+ region,
249
+ current_aws_account_id,
250
+ aws_update_tag,
251
+ )
216
252
  _attach_read_replicas(neo4j_session, read_replicas, aws_update_tag)
217
253
  _attach_clusters(neo4j_session, clusters, aws_update_tag)
218
254
 
219
255
 
220
256
  @timeit
221
257
  @aws_handle_regions
222
- def get_rds_snapshot_data(boto3_session: boto3.session.Session, region: str) -> List[Any]:
258
+ def get_rds_snapshot_data(
259
+ boto3_session: boto3.session.Session,
260
+ region: str,
261
+ ) -> List[Any]:
223
262
  """
224
263
  Create an RDS boto3 client and grab all the DBSnapshots.
225
264
  """
226
- client = boto3_session.client('rds', region_name=region)
227
- return aws_paginate(client, 'describe_db_snapshots', 'DBSnapshots')
265
+ client = boto3_session.client("rds", region_name=region)
266
+ return aws_paginate(client, "describe_db_snapshots", "DBSnapshots")
228
267
 
229
268
 
230
269
  @timeit
231
270
  def load_rds_snapshots(
232
- neo4j_session: neo4j.Session, data: Dict, region: str, current_aws_account_id: str,
271
+ neo4j_session: neo4j.Session,
272
+ data: Dict,
273
+ region: str,
274
+ current_aws_account_id: str,
233
275
  aws_update_tag: int,
234
276
  ) -> None:
235
277
  """
@@ -293,7 +335,11 @@ def load_rds_snapshots(
293
335
 
294
336
 
295
337
  @timeit
296
- def _attach_snapshots(neo4j_session: neo4j.Session, snapshots: List[Dict], aws_update_tag: int) -> None:
338
+ def _attach_snapshots(
339
+ neo4j_session: neo4j.Session,
340
+ snapshots: List[Dict],
341
+ aws_update_tag: int,
342
+ ) -> None:
297
343
  """
298
344
  Attach snapshots to their source instance
299
345
  """
@@ -314,7 +360,10 @@ def _attach_snapshots(neo4j_session: neo4j.Session, snapshots: List[Dict], aws_u
314
360
 
315
361
  @timeit
316
362
  def _attach_ec2_subnet_groups(
317
- neo4j_session: neo4j.Session, instances: List[Dict], region: str, current_aws_account_id: str,
363
+ neo4j_session: neo4j.Session,
364
+ instances: List[Dict],
365
+ region: str,
366
+ current_aws_account_id: str,
318
367
  aws_update_tag: int,
319
368
  ) -> None:
320
369
  """
@@ -337,22 +386,35 @@ def _attach_ec2_subnet_groups(
337
386
  """
338
387
  db_sngs = []
339
388
  for instance in instances:
340
- db_sng = instance['DBSubnetGroup']
341
- db_sng['arn'] = _get_db_subnet_group_arn(region, current_aws_account_id, db_sng['DBSubnetGroupName'])
342
- db_sng['instance_arn'] = instance['DBInstanceArn']
389
+ db_sng = instance["DBSubnetGroup"]
390
+ db_sng["arn"] = _get_db_subnet_group_arn(
391
+ region,
392
+ current_aws_account_id,
393
+ db_sng["DBSubnetGroupName"],
394
+ )
395
+ db_sng["instance_arn"] = instance["DBInstanceArn"]
343
396
  db_sngs.append(db_sng)
344
397
  neo4j_session.run(
345
398
  attach_rds_to_subnet_group,
346
399
  SubnetGroups=db_sngs,
347
400
  aws_update_tag=aws_update_tag,
348
401
  )
349
- _attach_ec2_subnets_to_subnetgroup(neo4j_session, db_sngs, region, current_aws_account_id, aws_update_tag)
402
+ _attach_ec2_subnets_to_subnetgroup(
403
+ neo4j_session,
404
+ db_sngs,
405
+ region,
406
+ current_aws_account_id,
407
+ aws_update_tag,
408
+ )
350
409
 
351
410
 
352
411
  @timeit
353
412
  def _attach_ec2_subnets_to_subnetgroup(
354
- neo4j_session: neo4j.Session, db_subnet_groups: List[Dict], region: str,
355
- current_aws_account_id: str, aws_update_tag: int,
413
+ neo4j_session: neo4j.Session,
414
+ db_subnet_groups: List[Dict],
415
+ region: str,
416
+ current_aws_account_id: str,
417
+ aws_update_tag: int,
356
418
  ) -> None:
357
419
  """
358
420
  Attach EC2Subnets to their DB Subnet Group.
@@ -375,15 +437,21 @@ def _attach_ec2_subnets_to_subnetgroup(
375
437
  """
376
438
  subnets = []
377
439
  for subnet_group in db_subnet_groups:
378
- for subnet in subnet_group.get('Subnets', []):
379
- sn_id = subnet.get('SubnetIdentifier')
380
- sng_arn = _get_db_subnet_group_arn(region, current_aws_account_id, subnet_group['DBSubnetGroupName'])
381
- az = subnet.get('SubnetAvailabilityZone', {}).get('Name')
382
- subnets.append({
383
- 'sn_id': sn_id,
384
- 'sng_arn': sng_arn,
385
- 'az': az,
386
- })
440
+ for subnet in subnet_group.get("Subnets", []):
441
+ sn_id = subnet.get("SubnetIdentifier")
442
+ sng_arn = _get_db_subnet_group_arn(
443
+ region,
444
+ current_aws_account_id,
445
+ subnet_group["DBSubnetGroupName"],
446
+ )
447
+ az = subnet.get("SubnetAvailabilityZone", {}).get("Name")
448
+ subnets.append(
449
+ {
450
+ "sn_id": sn_id,
451
+ "sng_arn": sng_arn,
452
+ "az": az,
453
+ },
454
+ )
387
455
  neo4j_session.run(
388
456
  attach_subnets_to_sng,
389
457
  Subnets=subnets,
@@ -392,7 +460,11 @@ def _attach_ec2_subnets_to_subnetgroup(
392
460
 
393
461
 
394
462
  @timeit
395
- def _attach_ec2_security_groups(neo4j_session: neo4j.Session, instances: List[Dict], aws_update_tag: int) -> None:
463
+ def _attach_ec2_security_groups(
464
+ neo4j_session: neo4j.Session,
465
+ instances: List[Dict],
466
+ aws_update_tag: int,
467
+ ) -> None:
396
468
  """
397
469
  Attach an RDS instance to its EC2SecurityGroups
398
470
  """
@@ -406,11 +478,13 @@ def _attach_ec2_security_groups(neo4j_session: neo4j.Session, instances: List[Di
406
478
  """
407
479
  groups = []
408
480
  for instance in instances:
409
- for group in instance['VpcSecurityGroups']:
410
- groups.append({
411
- 'arn': instance['DBInstanceArn'],
412
- 'group_id': group['VpcSecurityGroupId'],
413
- })
481
+ for group in instance["VpcSecurityGroups"]:
482
+ groups.append(
483
+ {
484
+ "arn": instance["DBInstanceArn"],
485
+ "group_id": group["VpcSecurityGroupId"],
486
+ },
487
+ )
414
488
  neo4j_session.run(
415
489
  attach_rds_to_group,
416
490
  Groups=groups,
@@ -419,7 +493,11 @@ def _attach_ec2_security_groups(neo4j_session: neo4j.Session, instances: List[Di
419
493
 
420
494
 
421
495
  @timeit
422
- def _attach_read_replicas(neo4j_session: neo4j.Session, read_replicas: List[Dict], aws_update_tag: int) -> None:
496
+ def _attach_read_replicas(
497
+ neo4j_session: neo4j.Session,
498
+ read_replicas: List[Dict],
499
+ aws_update_tag: int,
500
+ ) -> None:
423
501
  """
424
502
  Attach read replicas to their source instances
425
503
  """
@@ -439,7 +517,11 @@ def _attach_read_replicas(neo4j_session: neo4j.Session, read_replicas: List[Dict
439
517
 
440
518
 
441
519
  @timeit
442
- def _attach_clusters(neo4j_session: neo4j.Session, cluster_members: List[Dict], aws_update_tag: int) -> None:
520
+ def _attach_clusters(
521
+ neo4j_session: neo4j.Session,
522
+ cluster_members: List[Dict],
523
+ aws_update_tag: int,
524
+ ) -> None:
443
525
  """
444
526
  Attach cluster members to their source clusters
445
527
  """
@@ -462,13 +544,20 @@ def _validate_rds_endpoint(rds: Dict) -> Dict:
462
544
  """
463
545
  Get Endpoint from RDS data structure. Log to debug if an Endpoint field does not exist.
464
546
  """
465
- ep = rds.get('Endpoint', {})
547
+ ep = rds.get("Endpoint", {})
466
548
  if not ep:
467
- logger.debug("RDS instance does not have an Endpoint field. Here is the object: %r", rds)
549
+ logger.debug(
550
+ "RDS instance does not have an Endpoint field. Here is the object: %r",
551
+ rds,
552
+ )
468
553
  return ep
469
554
 
470
555
 
471
- def _get_db_subnet_group_arn(region: str, current_aws_account_id: str, db_subnet_group_name: str) -> str:
556
+ def _get_db_subnet_group_arn(
557
+ region: str,
558
+ current_aws_account_id: str,
559
+ db_subnet_group_name: str,
560
+ ) -> str:
472
561
  """
473
562
  Return an ARN for the DB subnet group name by concatenating the account name and region.
474
563
  This is done to avoid another AWS API call since the describe_db_instances boto call does not return the DB subnet
@@ -476,7 +565,9 @@ def _get_db_subnet_group_arn(region: str, current_aws_account_id: str, db_subnet
476
565
  Form is arn:aws:rds:{region}:{account-id}:subgrp:{subnet-group-name}
477
566
  as per https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
478
567
  """
479
- return f"arn:aws:rds:{region}:{current_aws_account_id}:subgrp:{db_subnet_group_name}"
568
+ return (
569
+ f"arn:aws:rds:{region}:{current_aws_account_id}:subgrp:{db_subnet_group_name}"
570
+ )
480
571
 
481
572
 
482
573
  @timeit
@@ -486,49 +577,90 @@ def transform_rds_snapshots(data: Dict) -> List[Dict]:
486
577
  for snapshot in data:
487
578
  snapshots.append(snapshot)
488
579
 
489
- snapshot['SnapshotCreateTime'] = dict_value_to_str(snapshot, 'EarliestRestorableTime')
490
- snapshot['InstanceCreateTime'] = dict_value_to_str(snapshot, 'InstanceCreateTime')
491
- snapshot['ProcessorFeatures'] = dict_value_to_str(snapshot, 'ProcessorFeatures')
492
- snapshot['OriginalSnapshotCreateTime'] = dict_value_to_str(snapshot, 'OriginalSnapshotCreateTime')
493
- snapshot['SnapshotDatabaseTime'] = dict_value_to_str(snapshot, 'SnapshotDatabaseTime')
580
+ snapshot["SnapshotCreateTime"] = dict_value_to_str(
581
+ snapshot,
582
+ "EarliestRestorableTime",
583
+ )
584
+ snapshot["InstanceCreateTime"] = dict_value_to_str(
585
+ snapshot,
586
+ "InstanceCreateTime",
587
+ )
588
+ snapshot["ProcessorFeatures"] = dict_value_to_str(snapshot, "ProcessorFeatures")
589
+ snapshot["OriginalSnapshotCreateTime"] = dict_value_to_str(
590
+ snapshot,
591
+ "OriginalSnapshotCreateTime",
592
+ )
593
+ snapshot["SnapshotDatabaseTime"] = dict_value_to_str(
594
+ snapshot,
595
+ "SnapshotDatabaseTime",
596
+ )
494
597
 
495
598
  return snapshots
496
599
 
497
600
 
498
601
  @timeit
499
- def cleanup_rds_instances_and_db_subnet_groups(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
602
+ def cleanup_rds_instances_and_db_subnet_groups(
603
+ neo4j_session: neo4j.Session,
604
+ common_job_parameters: Dict,
605
+ ) -> None:
500
606
  """
501
607
  Remove RDS graph nodes and DBSubnetGroups that were created from other ingestion runs
502
608
  """
503
- run_cleanup_job('aws_import_rds_instances_cleanup.json', neo4j_session, common_job_parameters)
609
+ run_cleanup_job(
610
+ "aws_import_rds_instances_cleanup.json",
611
+ neo4j_session,
612
+ common_job_parameters,
613
+ )
504
614
 
505
615
 
506
616
  @timeit
507
- def cleanup_rds_clusters(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
617
+ def cleanup_rds_clusters(
618
+ neo4j_session: neo4j.Session,
619
+ common_job_parameters: Dict,
620
+ ) -> None:
508
621
  """
509
622
  Remove RDS cluster graph nodes
510
623
  """
511
- run_cleanup_job('aws_import_rds_clusters_cleanup.json', neo4j_session, common_job_parameters)
624
+ run_cleanup_job(
625
+ "aws_import_rds_clusters_cleanup.json",
626
+ neo4j_session,
627
+ common_job_parameters,
628
+ )
512
629
 
513
630
 
514
631
  @timeit
515
- def cleanup_rds_snapshots(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
632
+ def cleanup_rds_snapshots(
633
+ neo4j_session: neo4j.Session,
634
+ common_job_parameters: Dict,
635
+ ) -> None:
516
636
  """
517
637
  Remove RDS snapshots graph nodes
518
638
  """
519
- run_cleanup_job('aws_import_rds_snapshots_cleanup.json', neo4j_session, common_job_parameters)
639
+ run_cleanup_job(
640
+ "aws_import_rds_snapshots_cleanup.json",
641
+ neo4j_session,
642
+ common_job_parameters,
643
+ )
520
644
 
521
645
 
522
646
  @timeit
523
647
  def sync_rds_clusters(
524
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
525
- update_tag: int, common_job_parameters: Dict,
648
+ neo4j_session: neo4j.Session,
649
+ boto3_session: boto3.session.Session,
650
+ regions: List[str],
651
+ current_aws_account_id: str,
652
+ update_tag: int,
653
+ common_job_parameters: Dict,
526
654
  ) -> None:
527
655
  """
528
656
  Grab RDS instance data from AWS, ingest to neo4j, and run the cleanup job.
529
657
  """
530
658
  for region in regions:
531
- logger.info("Syncing RDS for region '%s' in account '%s'.", region, current_aws_account_id)
659
+ logger.info(
660
+ "Syncing RDS for region '%s' in account '%s'.",
661
+ region,
662
+ current_aws_account_id,
663
+ )
532
664
  data = get_rds_cluster_data(boto3_session, region)
533
665
  load_rds_clusters(neo4j_session, data, region, current_aws_account_id, update_tag) # type: ignore
534
666
  cleanup_rds_clusters(neo4j_session, common_job_parameters)
@@ -536,14 +668,22 @@ def sync_rds_clusters(
536
668
 
537
669
  @timeit
538
670
  def sync_rds_instances(
539
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
540
- update_tag: int, common_job_parameters: Dict,
671
+ neo4j_session: neo4j.Session,
672
+ boto3_session: boto3.session.Session,
673
+ regions: List[str],
674
+ current_aws_account_id: str,
675
+ update_tag: int,
676
+ common_job_parameters: Dict,
541
677
  ) -> None:
542
678
  """
543
679
  Grab RDS instance data from AWS, ingest to neo4j, and run the cleanup job.
544
680
  """
545
681
  for region in regions:
546
- logger.info("Syncing RDS for region '%s' in account '%s'.", region, current_aws_account_id)
682
+ logger.info(
683
+ "Syncing RDS for region '%s' in account '%s'.",
684
+ region,
685
+ current_aws_account_id,
686
+ )
547
687
  data = get_rds_instance_data(boto3_session, region)
548
688
  load_rds_instances(neo4j_session, data, region, current_aws_account_id, update_tag) # type: ignore
549
689
  cleanup_rds_instances_and_db_subnet_groups(neo4j_session, common_job_parameters)
@@ -551,14 +691,22 @@ def sync_rds_instances(
551
691
 
552
692
  @timeit
553
693
  def sync_rds_snapshots(
554
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
555
- update_tag: int, common_job_parameters: Dict,
694
+ neo4j_session: neo4j.Session,
695
+ boto3_session: boto3.session.Session,
696
+ regions: List[str],
697
+ current_aws_account_id: str,
698
+ update_tag: int,
699
+ common_job_parameters: Dict,
556
700
  ) -> None:
557
701
  """
558
702
  Grab RDS snapshot data from AWS, ingest to neo4j, and run the cleanup job.
559
703
  """
560
704
  for region in regions:
561
- logger.info("Syncing RDS for region '%s' in account '%s'.", region, current_aws_account_id)
705
+ logger.info(
706
+ "Syncing RDS for region '%s' in account '%s'.",
707
+ region,
708
+ current_aws_account_id,
709
+ )
562
710
  data = get_rds_snapshot_data(boto3_session, region)
563
711
  load_rds_snapshots(neo4j_session, data, region, current_aws_account_id, update_tag) # type: ignore
564
712
  cleanup_rds_snapshots(neo4j_session, common_job_parameters)
@@ -566,26 +714,42 @@ def sync_rds_snapshots(
566
714
 
567
715
  @timeit
568
716
  def sync(
569
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
570
- update_tag: int, common_job_parameters: Dict,
717
+ neo4j_session: neo4j.Session,
718
+ boto3_session: boto3.session.Session,
719
+ regions: List[str],
720
+ current_aws_account_id: str,
721
+ update_tag: int,
722
+ common_job_parameters: Dict,
571
723
  ) -> None:
572
724
  sync_rds_clusters(
573
- neo4j_session, boto3_session, regions, current_aws_account_id, update_tag,
725
+ neo4j_session,
726
+ boto3_session,
727
+ regions,
728
+ current_aws_account_id,
729
+ update_tag,
574
730
  common_job_parameters,
575
731
  )
576
732
  sync_rds_instances(
577
- neo4j_session, boto3_session, regions, current_aws_account_id, update_tag,
733
+ neo4j_session,
734
+ boto3_session,
735
+ regions,
736
+ current_aws_account_id,
737
+ update_tag,
578
738
  common_job_parameters,
579
739
  )
580
740
  sync_rds_snapshots(
581
- neo4j_session, boto3_session, regions, current_aws_account_id, update_tag,
741
+ neo4j_session,
742
+ boto3_session,
743
+ regions,
744
+ current_aws_account_id,
745
+ update_tag,
582
746
  common_job_parameters,
583
747
  )
584
748
  merge_module_sync_metadata(
585
749
  neo4j_session,
586
- group_type='AWSAccount',
750
+ group_type="AWSAccount",
587
751
  group_id=current_aws_account_id,
588
- synced_type='RDSCluster',
752
+ synced_type="RDSCluster",
589
753
  update_tag=update_tag,
590
754
  stat_handler=stat_handler,
591
755
  )