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
@@ -19,7 +19,11 @@ logger = logging.getLogger(__name__)
19
19
 
20
20
 
21
21
  @timeit
22
- def get_images_in_use(neo4j_session: neo4j.Session, region: str, current_aws_account_id: str) -> List[str]:
22
+ def get_images_in_use(
23
+ neo4j_session: neo4j.Session,
24
+ region: str,
25
+ current_aws_account_id: str,
26
+ ) -> List[str]:
23
27
  get_images_query = """
24
28
  CALL {
25
29
  MATCH (:AWSAccount{id: $AWS_ACCOUNT_ID})-[:RESOURCE]->(i:EC2Instance)
@@ -37,8 +41,10 @@ def get_images_in_use(neo4j_session: neo4j.Session, region: str, current_aws_acc
37
41
  RETURN DISTINCT image;
38
42
  """
39
43
  result = read_list_of_values_tx(
40
- neo4j_session, get_images_query,
41
- AWS_ACCOUNT_ID=current_aws_account_id, Region=region,
44
+ neo4j_session,
45
+ get_images_query,
46
+ AWS_ACCOUNT_ID=current_aws_account_id,
47
+ Region=region,
42
48
  )
43
49
  images = [str(image) for image in result]
44
50
  return images
@@ -46,40 +52,52 @@ def get_images_in_use(neo4j_session: neo4j.Session, region: str, current_aws_acc
46
52
 
47
53
  @timeit
48
54
  @aws_handle_regions
49
- def get_images(boto3_session: boto3.session.Session, region: str, image_ids: List[str]) -> List[Dict]:
50
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
55
+ def get_images(
56
+ boto3_session: boto3.session.Session,
57
+ region: str,
58
+ image_ids: List[str],
59
+ ) -> List[Dict]:
60
+ client = boto3_session.client(
61
+ "ec2",
62
+ region_name=region,
63
+ config=get_botocore_config(),
64
+ )
51
65
  images = []
52
66
  self_images = []
53
67
  try:
54
- self_images = client.describe_images(Owners=['self'])['Images']
68
+ self_images = client.describe_images(Owners=["self"])["Images"]
55
69
  except ClientError as e:
56
- logger.warning(f"Failed retrieve self owned images for region - {region}. Error - {e}")
70
+ logger.warning(
71
+ f"Failed retrieve self owned images for region - {region}. Error - {e}"
72
+ )
57
73
  images.extend(self_images)
58
74
  if image_ids:
59
- self_image_ids = {image['ImageId'] for image in images}
75
+ self_image_ids = {image["ImageId"] for image in images}
60
76
  # Go one by one to avoid losing all images if one fails
61
77
  for image in image_ids:
62
78
  if image in self_image_ids:
63
79
  continue
64
80
  try:
65
- public_images = client.describe_images(ImageIds=[image])['Images']
81
+ public_images = client.describe_images(ImageIds=[image])["Images"]
66
82
  images.extend(public_images)
67
83
  except ClientError as e:
68
- logger.warning(f"Failed retrieve image id {image} for region - {region}. Error - {e}")
84
+ logger.warning(
85
+ f"Failed retrieve image id {image} for region - {region}. Error - {e}"
86
+ )
69
87
  return images
70
88
 
71
89
 
72
90
  @timeit
73
91
  def load_images(
74
- neo4j_session: neo4j.Session,
75
- data: List[Dict[str, Any]],
76
- region: str,
77
- current_aws_account_id: str,
78
- update_tag: int,
92
+ neo4j_session: neo4j.Session,
93
+ data: List[Dict[str, Any]],
94
+ region: str,
95
+ current_aws_account_id: str,
96
+ update_tag: int,
79
97
  ) -> None:
80
98
  # AMI IDs are unique to each AWS Region. Hence we make an 'ID' string that is a combo of ImageId and region
81
99
  for image in data:
82
- image['ID'] = image['ImageId'] + '|' + region
100
+ image["ID"] = image["ImageId"] + "|" + region
83
101
  load(
84
102
  neo4j_session,
85
103
  EC2ImageSchema(),
@@ -91,18 +109,29 @@ def load_images(
91
109
 
92
110
 
93
111
  @timeit
94
- def cleanup_images(neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]) -> None:
112
+ def cleanup_images(
113
+ neo4j_session: neo4j.Session,
114
+ common_job_parameters: Dict[str, Any],
115
+ ) -> None:
95
116
  cleanup_job = GraphJob.from_node_schema(EC2ImageSchema(), common_job_parameters)
96
117
  cleanup_job.run(neo4j_session)
97
118
 
98
119
 
99
120
  @timeit
100
121
  def sync_ec2_images(
101
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str],
102
- current_aws_account_id: str, update_tag: int, common_job_parameters: Dict,
122
+ neo4j_session: neo4j.Session,
123
+ boto3_session: boto3.session.Session,
124
+ regions: List[str],
125
+ current_aws_account_id: str,
126
+ update_tag: int,
127
+ common_job_parameters: Dict,
103
128
  ) -> None:
104
129
  for region in regions:
105
- logger.info("Syncing images for region '%s' in account '%s'.", region, current_aws_account_id)
130
+ logger.info(
131
+ "Syncing images for region '%s' in account '%s'.",
132
+ region,
133
+ current_aws_account_id,
134
+ )
106
135
  images_in_use = get_images_in_use(neo4j_session, region, current_aws_account_id)
107
136
  data = get_images(boto3_session, region, images_in_use)
108
137
  load_images(neo4j_session, data, region, current_aws_account_id, update_tag)
@@ -11,12 +11,18 @@ import neo4j
11
11
  from cartography.client.core.tx import load
12
12
  from cartography.graph.job import GraphJob
13
13
  from cartography.intel.aws.ec2.util import get_botocore_config
14
- from cartography.models.aws.ec2.auto_scaling_groups import EC2InstanceAutoScalingGroupSchema
14
+ from cartography.models.aws.ec2.auto_scaling_groups import (
15
+ EC2InstanceAutoScalingGroupSchema,
16
+ )
15
17
  from cartography.models.aws.ec2.instances import EC2InstanceSchema
16
18
  from cartography.models.aws.ec2.keypair_instance import EC2KeyPairInstanceSchema
17
- from cartography.models.aws.ec2.networkinterface_instance import EC2NetworkInterfaceInstanceSchema
19
+ from cartography.models.aws.ec2.networkinterface_instance import (
20
+ EC2NetworkInterfaceInstanceSchema,
21
+ )
18
22
  from cartography.models.aws.ec2.reservations import EC2ReservationSchema
19
- from cartography.models.aws.ec2.securitygroup_instance import EC2SecurityGroupInstanceSchema
23
+ from cartography.models.aws.ec2.securitygroup_instance import (
24
+ EC2SecurityGroupInstanceSchema,
25
+ )
20
26
  from cartography.models.aws.ec2.subnet_instance import EC2SubnetInstanceSchema
21
27
  from cartography.models.aws.ec2.volumes import EBSVolumeInstanceSchema
22
28
  from cartography.util import aws_handle_regions
@@ -25,7 +31,8 @@ from cartography.util import timeit
25
31
  logger = logging.getLogger(__name__)
26
32
 
27
33
  Ec2Data = namedtuple(
28
- 'Ec2Data', [
34
+ "Ec2Data",
35
+ [
29
36
  "reservation_list",
30
37
  "instance_list",
31
38
  "subnet_list",
@@ -40,15 +47,23 @@ Ec2Data = namedtuple(
40
47
  @timeit
41
48
  @aws_handle_regions
42
49
  def get_ec2_instances(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
43
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
44
- paginator = client.get_paginator('describe_instances')
50
+ client = boto3_session.client(
51
+ "ec2",
52
+ region_name=region,
53
+ config=get_botocore_config(),
54
+ )
55
+ paginator = client.get_paginator("describe_instances")
45
56
  reservations: List[Dict[str, Any]] = []
46
57
  for page in paginator.paginate():
47
- reservations.extend(page['Reservations'])
58
+ reservations.extend(page["Reservations"])
48
59
  return reservations
49
60
 
50
61
 
51
- def transform_ec2_instances(reservations: List[Dict[str, Any]], region: str, current_aws_account_id: str) -> Ec2Data:
62
+ def transform_ec2_instances(
63
+ reservations: List[Dict[str, Any]],
64
+ region: str,
65
+ current_aws_account_id: str,
66
+ ) -> Ec2Data:
52
67
  reservation_list = []
53
68
  instance_list = []
54
69
  subnet_list = []
@@ -58,92 +73,119 @@ def transform_ec2_instances(reservations: List[Dict[str, Any]], region: str, cur
58
73
  instance_ebs_volumes_list = []
59
74
 
60
75
  for reservation in reservations:
61
- reservation_id = reservation['ReservationId']
62
- reservation_list.append({
63
- 'RequesterId': reservation.get('RequesterId'),
64
- 'ReservationId': reservation['ReservationId'],
65
- 'OwnerId': reservation['OwnerId'],
66
- })
67
- for instance in reservation['Instances']:
68
- instance_id = instance['InstanceId']
76
+ reservation_id = reservation["ReservationId"]
77
+ reservation_list.append(
78
+ {
79
+ "RequesterId": reservation.get("RequesterId"),
80
+ "ReservationId": reservation["ReservationId"],
81
+ "OwnerId": reservation["OwnerId"],
82
+ },
83
+ )
84
+ for instance in reservation["Instances"]:
85
+ instance_id = instance["InstanceId"]
69
86
  launch_time = instance.get("LaunchTime")
70
- launch_time_unix = str(time.mktime(launch_time.timetuple())) if launch_time else None
87
+ launch_time_unix = (
88
+ str(time.mktime(launch_time.timetuple())) if launch_time else None
89
+ )
71
90
  instance_list.append(
72
91
  {
73
- 'InstanceId': instance_id,
74
- 'ReservationId': reservation_id,
75
- 'PublicDnsName': instance.get("PublicDnsName"),
76
- 'PublicIpAddress': instance.get("PublicIpAddress"),
77
- 'PrivateIpAddress': instance.get("PrivateIpAddress"),
78
- 'ImageId': instance.get("ImageId"),
79
- 'InstanceType': instance.get("InstanceType"),
80
- 'IamInstanceProfile': instance.get("IamInstanceProfile", {}).get("Arn"),
81
- 'MonitoringState': instance.get("Monitoring", {}).get("State"),
82
- 'LaunchTime': instance.get("LaunchTime"),
83
- 'LaunchTimeUnix': launch_time_unix,
84
- 'State': instance.get("State", {}).get("Name"),
85
- 'AvailabilityZone': instance.get("Placement", {}).get("AvailabilityZone"),
86
- 'Tenancy': instance.get("Placement", {}).get("Tenancy"),
87
- 'HostResourceGroupArn': instance.get("Placement", {}).get("HostResourceGroupArn"),
88
- 'Platform': instance.get("Platform"),
89
- 'Architecture': instance.get("Architecture"),
90
- 'EbsOptimized': instance.get("EbsOptimized"),
91
- 'BootMode': instance.get("BootMode"),
92
- 'InstanceLifecycle': instance.get("InstanceLifecycle"),
93
- 'HibernationOptions': instance.get("HibernationOptions", {}).get("Configured"),
92
+ "InstanceId": instance_id,
93
+ "ReservationId": reservation_id,
94
+ "PublicDnsName": instance.get("PublicDnsName"),
95
+ "PublicIpAddress": instance.get("PublicIpAddress"),
96
+ "PrivateIpAddress": instance.get("PrivateIpAddress"),
97
+ "ImageId": instance.get("ImageId"),
98
+ "InstanceType": instance.get("InstanceType"),
99
+ "IamInstanceProfile": instance.get("IamInstanceProfile", {}).get(
100
+ "Arn",
101
+ ),
102
+ "MonitoringState": instance.get("Monitoring", {}).get("State"),
103
+ "LaunchTime": instance.get("LaunchTime"),
104
+ "LaunchTimeUnix": launch_time_unix,
105
+ "State": instance.get("State", {}).get("Name"),
106
+ "AvailabilityZone": instance.get("Placement", {}).get(
107
+ "AvailabilityZone",
108
+ ),
109
+ "Tenancy": instance.get("Placement", {}).get("Tenancy"),
110
+ "HostResourceGroupArn": instance.get("Placement", {}).get(
111
+ "HostResourceGroupArn",
112
+ ),
113
+ "Platform": instance.get("Platform"),
114
+ "Architecture": instance.get("Architecture"),
115
+ "EbsOptimized": instance.get("EbsOptimized"),
116
+ "BootMode": instance.get("BootMode"),
117
+ "InstanceLifecycle": instance.get("InstanceLifecycle"),
118
+ "HibernationOptions": instance.get("HibernationOptions", {}).get(
119
+ "Configured",
120
+ ),
94
121
  },
95
122
  )
96
123
 
97
- subnet_id = instance.get('SubnetId')
124
+ subnet_id = instance.get("SubnetId")
98
125
  if subnet_id:
99
126
  subnet_list.append(
100
127
  {
101
- 'SubnetId': subnet_id,
102
- 'InstanceId': instance_id,
128
+ "SubnetId": subnet_id,
129
+ "InstanceId": instance_id,
103
130
  },
104
131
  )
105
132
 
106
133
  if instance.get("KeyName"):
107
134
  key_name = instance["KeyName"]
108
- key_pair_arn = f'arn:aws:ec2:{region}:{current_aws_account_id}:key-pair/{key_name}'
109
- keypair_list.append({
110
- 'KeyPairArn': key_pair_arn,
111
- 'KeyName': key_name,
112
- 'InstanceId': instance_id,
113
- })
135
+ key_pair_arn = (
136
+ f"arn:aws:ec2:{region}:{current_aws_account_id}:key-pair/{key_name}"
137
+ )
138
+ keypair_list.append(
139
+ {
140
+ "KeyPairArn": key_pair_arn,
141
+ "KeyName": key_name,
142
+ "InstanceId": instance_id,
143
+ },
144
+ )
114
145
 
115
146
  if instance.get("SecurityGroups"):
116
147
  for group in instance["SecurityGroups"]:
117
148
  sg_list.append(
118
149
  {
119
- 'GroupId': group['GroupId'],
120
- 'InstanceId': instance_id,
150
+ "GroupId": group["GroupId"],
151
+ "InstanceId": instance_id,
121
152
  },
122
153
  )
123
154
 
124
- for network_interface in instance['NetworkInterfaces']:
125
- for security_group in network_interface.get('Groups', []):
126
- network_interface_list.append({
127
- 'NetworkInterfaceId': network_interface['NetworkInterfaceId'],
128
- 'Status': network_interface['Status'],
129
- 'MacAddress': network_interface['MacAddress'],
130
- 'Description': network_interface['Description'],
131
- 'PrivateDnsName': network_interface.get('PrivateDnsName'),
132
- 'PrivateIpAddress': network_interface['PrivateIpAddress'],
133
- 'InstanceId': instance_id,
134
- 'SubnetId': subnet_id,
135
- 'GroupId': security_group['GroupId'],
136
- })
137
-
138
- if 'BlockDeviceMappings' in instance and len(instance['BlockDeviceMappings']) > 0:
139
- for mapping in instance['BlockDeviceMappings']:
140
- if 'VolumeId' in mapping['Ebs']:
141
- instance_ebs_volumes_list.append({
142
- 'InstanceId': instance_id,
143
- 'VolumeId': mapping['Ebs']['VolumeId'],
144
- 'DeleteOnTermination': mapping['Ebs']['DeleteOnTermination'],
145
- # 'SnapshotId': mapping['Ebs']['SnapshotId'], # TODO check on this
146
- })
155
+ for network_interface in instance["NetworkInterfaces"]:
156
+ for security_group in network_interface.get("Groups", []):
157
+ network_interface_list.append(
158
+ {
159
+ "NetworkInterfaceId": network_interface[
160
+ "NetworkInterfaceId"
161
+ ],
162
+ "Status": network_interface["Status"],
163
+ "MacAddress": network_interface["MacAddress"],
164
+ "Description": network_interface["Description"],
165
+ "PrivateDnsName": network_interface.get("PrivateDnsName"),
166
+ "PrivateIpAddress": network_interface["PrivateIpAddress"],
167
+ "InstanceId": instance_id,
168
+ "SubnetId": subnet_id,
169
+ "GroupId": security_group["GroupId"],
170
+ },
171
+ )
172
+
173
+ if (
174
+ "BlockDeviceMappings" in instance
175
+ and len(instance["BlockDeviceMappings"]) > 0
176
+ ):
177
+ for mapping in instance["BlockDeviceMappings"]:
178
+ if "VolumeId" in mapping["Ebs"]:
179
+ instance_ebs_volumes_list.append(
180
+ {
181
+ "InstanceId": instance_id,
182
+ "VolumeId": mapping["Ebs"]["VolumeId"],
183
+ "DeleteOnTermination": mapping["Ebs"][
184
+ "DeleteOnTermination"
185
+ ],
186
+ # 'SnapshotId': mapping['Ebs']['SnapshotId'], # TODO check on this
187
+ },
188
+ )
147
189
 
148
190
  return Ec2Data(
149
191
  reservation_list=reservation_list,
@@ -158,11 +200,11 @@ def transform_ec2_instances(reservations: List[Dict[str, Any]], region: str, cur
158
200
 
159
201
  @timeit
160
202
  def load_ec2_reservations(
161
- neo4j_session: neo4j.Session,
162
- reservation_list: List[Dict[str, Any]],
163
- region: str,
164
- current_aws_account_id: str,
165
- update_tag: int,
203
+ neo4j_session: neo4j.Session,
204
+ reservation_list: List[Dict[str, Any]],
205
+ region: str,
206
+ current_aws_account_id: str,
207
+ update_tag: int,
166
208
  ) -> None:
167
209
  load(
168
210
  neo4j_session,
@@ -176,11 +218,11 @@ def load_ec2_reservations(
176
218
 
177
219
  @timeit
178
220
  def load_ec2_subnets(
179
- neo4j_session: neo4j.Session,
180
- subnet_list: List[Dict[str, Any]],
181
- region: str,
182
- current_aws_account_id: str,
183
- update_tag: int,
221
+ neo4j_session: neo4j.Session,
222
+ subnet_list: List[Dict[str, Any]],
223
+ region: str,
224
+ current_aws_account_id: str,
225
+ update_tag: int,
184
226
  ) -> None:
185
227
  load(
186
228
  neo4j_session,
@@ -194,11 +236,11 @@ def load_ec2_subnets(
194
236
 
195
237
  @timeit
196
238
  def load_ec2_keypair_instances(
197
- neo4j_session: neo4j.Session,
198
- key_pair_list: List[Dict[str, Any]],
199
- region: str,
200
- current_aws_account_id: str,
201
- update_tag: int,
239
+ neo4j_session: neo4j.Session,
240
+ key_pair_list: List[Dict[str, Any]],
241
+ region: str,
242
+ current_aws_account_id: str,
243
+ update_tag: int,
202
244
  ) -> None:
203
245
  # Load EC2 keypairs as known by describe-instances.
204
246
  load(
@@ -213,11 +255,11 @@ def load_ec2_keypair_instances(
213
255
 
214
256
  @timeit
215
257
  def load_ec2_security_groups(
216
- neo4j_session: neo4j.Session,
217
- sg_list: List[Dict[str, Any]],
218
- region: str,
219
- current_aws_account_id: str,
220
- update_tag: int,
258
+ neo4j_session: neo4j.Session,
259
+ sg_list: List[Dict[str, Any]],
260
+ region: str,
261
+ current_aws_account_id: str,
262
+ update_tag: int,
221
263
  ) -> None:
222
264
  load(
223
265
  neo4j_session,
@@ -231,11 +273,11 @@ def load_ec2_security_groups(
231
273
 
232
274
  @timeit
233
275
  def load_ec2_network_interfaces(
234
- neo4j_session: neo4j.Session,
235
- network_interface_list: List[Dict[str, Any]],
236
- region: str,
237
- current_aws_account_id: str,
238
- update_tag: int,
276
+ neo4j_session: neo4j.Session,
277
+ network_interface_list: List[Dict[str, Any]],
278
+ region: str,
279
+ current_aws_account_id: str,
280
+ update_tag: int,
239
281
  ) -> None:
240
282
  load(
241
283
  neo4j_session,
@@ -249,11 +291,11 @@ def load_ec2_network_interfaces(
249
291
 
250
292
  @timeit
251
293
  def load_ec2_instance_nodes(
252
- neo4j_session: neo4j.Session,
253
- data: List[Dict],
254
- region: str,
255
- current_aws_account_id: str,
256
- update_tag: int,
294
+ neo4j_session: neo4j.Session,
295
+ data: List[Dict],
296
+ region: str,
297
+ current_aws_account_id: str,
298
+ update_tag: int,
257
299
  ) -> None:
258
300
  load(
259
301
  neo4j_session,
@@ -267,11 +309,11 @@ def load_ec2_instance_nodes(
267
309
 
268
310
  @timeit
269
311
  def load_ec2_instance_ebs_volumes(
270
- neo4j_session: neo4j.Session,
271
- ebs_data: List[Dict[str, Any]],
272
- region: str,
273
- current_aws_account_id: str,
274
- update_tag: int,
312
+ neo4j_session: neo4j.Session,
313
+ ebs_data: List[Dict[str, Any]],
314
+ region: str,
315
+ current_aws_account_id: str,
316
+ update_tag: int,
275
317
  ) -> None:
276
318
  load(
277
319
  neo4j_session,
@@ -284,46 +326,102 @@ def load_ec2_instance_ebs_volumes(
284
326
 
285
327
 
286
328
  def load_ec2_instance_data(
287
- neo4j_session: neo4j.Session,
288
- region: str,
289
- current_aws_account_id: str,
290
- update_tag: int,
291
- reservation_list: List[Dict[str, Any]],
292
- instance_list: List[Dict[str, Any]],
293
- subnet_list: List[Dict[str, Any]],
294
- sg_list: List[Dict[str, Any]],
295
- key_pair_list: List[Dict[str, Any]],
296
- nic_list: List[Dict[str, Any]],
297
- ebs_volumes_list: List[Dict[str, Any]],
329
+ neo4j_session: neo4j.Session,
330
+ region: str,
331
+ current_aws_account_id: str,
332
+ update_tag: int,
333
+ reservation_list: List[Dict[str, Any]],
334
+ instance_list: List[Dict[str, Any]],
335
+ subnet_list: List[Dict[str, Any]],
336
+ sg_list: List[Dict[str, Any]],
337
+ key_pair_list: List[Dict[str, Any]],
338
+ nic_list: List[Dict[str, Any]],
339
+ ebs_volumes_list: List[Dict[str, Any]],
298
340
  ) -> None:
299
- load_ec2_reservations(neo4j_session, reservation_list, region, current_aws_account_id, update_tag)
300
- load_ec2_instance_nodes(neo4j_session, instance_list, region, current_aws_account_id, update_tag)
301
- load_ec2_subnets(neo4j_session, subnet_list, region, current_aws_account_id, update_tag)
302
- load_ec2_security_groups(neo4j_session, sg_list, region, current_aws_account_id, update_tag)
303
- load_ec2_keypair_instances(neo4j_session, key_pair_list, region, current_aws_account_id, update_tag)
304
- load_ec2_network_interfaces(neo4j_session, nic_list, region, current_aws_account_id, update_tag)
305
- load_ec2_instance_ebs_volumes(neo4j_session, ebs_volumes_list, region, current_aws_account_id, update_tag)
341
+ load_ec2_reservations(
342
+ neo4j_session,
343
+ reservation_list,
344
+ region,
345
+ current_aws_account_id,
346
+ update_tag,
347
+ )
348
+ load_ec2_instance_nodes(
349
+ neo4j_session,
350
+ instance_list,
351
+ region,
352
+ current_aws_account_id,
353
+ update_tag,
354
+ )
355
+ load_ec2_subnets(
356
+ neo4j_session,
357
+ subnet_list,
358
+ region,
359
+ current_aws_account_id,
360
+ update_tag,
361
+ )
362
+ load_ec2_security_groups(
363
+ neo4j_session,
364
+ sg_list,
365
+ region,
366
+ current_aws_account_id,
367
+ update_tag,
368
+ )
369
+ load_ec2_keypair_instances(
370
+ neo4j_session,
371
+ key_pair_list,
372
+ region,
373
+ current_aws_account_id,
374
+ update_tag,
375
+ )
376
+ load_ec2_network_interfaces(
377
+ neo4j_session,
378
+ nic_list,
379
+ region,
380
+ current_aws_account_id,
381
+ update_tag,
382
+ )
383
+ load_ec2_instance_ebs_volumes(
384
+ neo4j_session,
385
+ ebs_volumes_list,
386
+ region,
387
+ current_aws_account_id,
388
+ update_tag,
389
+ )
306
390
 
307
391
 
308
392
  @timeit
309
- def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]) -> None:
393
+ def cleanup(
394
+ neo4j_session: neo4j.Session,
395
+ common_job_parameters: Dict[str, Any],
396
+ ) -> None:
310
397
  logger.debug("Running EC2 instance cleanup")
311
- GraphJob.from_node_schema(EC2ReservationSchema(), common_job_parameters).run(neo4j_session)
312
- GraphJob.from_node_schema(EC2InstanceSchema(), common_job_parameters).run(neo4j_session)
313
- GraphJob.from_node_schema(EC2InstanceAutoScalingGroupSchema(), common_job_parameters).run(neo4j_session)
398
+ GraphJob.from_node_schema(EC2ReservationSchema(), common_job_parameters).run(
399
+ neo4j_session,
400
+ )
401
+ GraphJob.from_node_schema(EC2InstanceSchema(), common_job_parameters).run(
402
+ neo4j_session,
403
+ )
404
+ GraphJob.from_node_schema(
405
+ EC2InstanceAutoScalingGroupSchema(),
406
+ common_job_parameters,
407
+ ).run(neo4j_session)
314
408
 
315
409
 
316
410
  @timeit
317
411
  def sync_ec2_instances(
318
- neo4j_session: neo4j.Session,
319
- boto3_session: boto3.session.Session,
320
- regions: List[str],
321
- current_aws_account_id: str,
322
- update_tag: int,
323
- common_job_parameters: Dict[str, Any],
412
+ neo4j_session: neo4j.Session,
413
+ boto3_session: boto3.session.Session,
414
+ regions: List[str],
415
+ current_aws_account_id: str,
416
+ update_tag: int,
417
+ common_job_parameters: Dict[str, Any],
324
418
  ) -> None:
325
419
  for region in regions:
326
- logger.info("Syncing EC2 instances for region '%s' in account '%s'.", region, current_aws_account_id)
420
+ logger.info(
421
+ "Syncing EC2 instances for region '%s' in account '%s'.",
422
+ region,
423
+ current_aws_account_id,
424
+ )
327
425
  reservations = get_ec2_instances(boto3_session, region)
328
426
  ec2_data = transform_ec2_instances(reservations, region, current_aws_account_id)
329
427
  load_ec2_instance_data(