cartography 0.104.0rc3__py3-none-any.whl → 0.106.0__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 (134) hide show
  1. cartography/_version.py +2 -2
  2. cartography/cli.py +104 -3
  3. cartography/client/aws/__init__.py +19 -0
  4. cartography/client/aws/ecr.py +51 -0
  5. cartography/client/core/tx.py +62 -0
  6. cartography/config.py +32 -0
  7. cartography/data/indexes.cypher +0 -37
  8. cartography/data/jobs/cleanup/aws_import_lambda_cleanup.json +1 -1
  9. cartography/driftdetect/cli.py +3 -2
  10. cartography/graph/cleanupbuilder.py +198 -41
  11. cartography/graph/job.py +42 -0
  12. cartography/graph/querybuilder.py +136 -2
  13. cartography/graph/statement.py +1 -1
  14. cartography/intel/airbyte/__init__.py +105 -0
  15. cartography/intel/airbyte/connections.py +120 -0
  16. cartography/intel/airbyte/destinations.py +81 -0
  17. cartography/intel/airbyte/organizations.py +59 -0
  18. cartography/intel/airbyte/sources.py +78 -0
  19. cartography/intel/airbyte/tags.py +64 -0
  20. cartography/intel/airbyte/users.py +106 -0
  21. cartography/intel/airbyte/util.py +122 -0
  22. cartography/intel/airbyte/workspaces.py +63 -0
  23. cartography/intel/aws/acm.py +124 -0
  24. cartography/intel/aws/cloudtrail.py +3 -38
  25. cartography/intel/aws/codebuild.py +132 -0
  26. cartography/intel/aws/ecr.py +8 -2
  27. cartography/intel/aws/ecs.py +228 -380
  28. cartography/intel/aws/efs.py +179 -11
  29. cartography/intel/aws/iam.py +1 -1
  30. cartography/intel/aws/identitycenter.py +14 -3
  31. cartography/intel/aws/inspector.py +96 -53
  32. cartography/intel/aws/lambda_function.py +1 -1
  33. cartography/intel/aws/rds.py +2 -1
  34. cartography/intel/aws/resources.py +4 -0
  35. cartography/intel/aws/s3.py +195 -4
  36. cartography/intel/aws/sqs.py +36 -90
  37. cartography/intel/entra/__init__.py +22 -0
  38. cartography/intel/entra/applications.py +366 -0
  39. cartography/intel/entra/groups.py +151 -0
  40. cartography/intel/entra/ou.py +21 -5
  41. cartography/intel/entra/users.py +84 -42
  42. cartography/intel/kubernetes/__init__.py +30 -14
  43. cartography/intel/kubernetes/clusters.py +86 -0
  44. cartography/intel/kubernetes/namespaces.py +59 -57
  45. cartography/intel/kubernetes/pods.py +140 -77
  46. cartography/intel/kubernetes/secrets.py +95 -45
  47. cartography/intel/kubernetes/services.py +131 -67
  48. cartography/intel/kubernetes/util.py +125 -14
  49. cartography/intel/scaleway/__init__.py +127 -0
  50. cartography/intel/scaleway/iam/__init__.py +0 -0
  51. cartography/intel/scaleway/iam/apikeys.py +71 -0
  52. cartography/intel/scaleway/iam/applications.py +71 -0
  53. cartography/intel/scaleway/iam/groups.py +71 -0
  54. cartography/intel/scaleway/iam/users.py +71 -0
  55. cartography/intel/scaleway/instances/__init__.py +0 -0
  56. cartography/intel/scaleway/instances/flexibleips.py +86 -0
  57. cartography/intel/scaleway/instances/instances.py +92 -0
  58. cartography/intel/scaleway/projects.py +79 -0
  59. cartography/intel/scaleway/storage/__init__.py +0 -0
  60. cartography/intel/scaleway/storage/snapshots.py +86 -0
  61. cartography/intel/scaleway/storage/volumes.py +84 -0
  62. cartography/intel/scaleway/utils.py +37 -0
  63. cartography/intel/trivy/__init__.py +161 -0
  64. cartography/intel/trivy/scanner.py +363 -0
  65. cartography/models/airbyte/__init__.py +0 -0
  66. cartography/models/airbyte/connection.py +138 -0
  67. cartography/models/airbyte/destination.py +75 -0
  68. cartography/models/airbyte/organization.py +19 -0
  69. cartography/models/airbyte/source.py +75 -0
  70. cartography/models/airbyte/stream.py +74 -0
  71. cartography/models/airbyte/tag.py +69 -0
  72. cartography/models/airbyte/user.py +111 -0
  73. cartography/models/airbyte/workspace.py +46 -0
  74. cartography/models/aws/acm/__init__.py +0 -0
  75. cartography/models/aws/acm/certificate.py +75 -0
  76. cartography/models/aws/cloudtrail/trail.py +24 -0
  77. cartography/models/aws/codebuild/__init__.py +0 -0
  78. cartography/models/aws/codebuild/project.py +49 -0
  79. cartography/models/aws/ecs/__init__.py +0 -0
  80. cartography/models/aws/ecs/clusters.py +64 -0
  81. cartography/models/aws/ecs/container_definitions.py +93 -0
  82. cartography/models/aws/ecs/container_instances.py +84 -0
  83. cartography/models/aws/ecs/containers.py +99 -0
  84. cartography/models/aws/ecs/services.py +117 -0
  85. cartography/models/aws/ecs/task_definitions.py +135 -0
  86. cartography/models/aws/ecs/tasks.py +110 -0
  87. cartography/models/aws/efs/access_point.py +77 -0
  88. cartography/models/aws/efs/file_system.py +60 -0
  89. cartography/models/aws/efs/mount_target.py +29 -2
  90. cartography/models/aws/s3/notification.py +24 -0
  91. cartography/models/aws/secretsmanager/secret_version.py +0 -2
  92. cartography/models/aws/sqs/__init__.py +0 -0
  93. cartography/models/aws/sqs/queue.py +89 -0
  94. cartography/models/core/common.py +1 -0
  95. cartography/models/core/nodes.py +15 -2
  96. cartography/models/core/relationships.py +44 -0
  97. cartography/models/entra/app_role_assignment.py +115 -0
  98. cartography/models/entra/application.py +47 -0
  99. cartography/models/entra/group.py +91 -0
  100. cartography/models/entra/user.py +17 -51
  101. cartography/models/kubernetes/__init__.py +0 -0
  102. cartography/models/kubernetes/clusters.py +26 -0
  103. cartography/models/kubernetes/containers.py +108 -0
  104. cartography/models/kubernetes/namespaces.py +51 -0
  105. cartography/models/kubernetes/pods.py +80 -0
  106. cartography/models/kubernetes/secrets.py +79 -0
  107. cartography/models/kubernetes/services.py +108 -0
  108. cartography/models/scaleway/__init__.py +0 -0
  109. cartography/models/scaleway/iam/__init__.py +0 -0
  110. cartography/models/scaleway/iam/apikey.py +96 -0
  111. cartography/models/scaleway/iam/application.py +52 -0
  112. cartography/models/scaleway/iam/group.py +95 -0
  113. cartography/models/scaleway/iam/user.py +60 -0
  114. cartography/models/scaleway/instance/__init__.py +0 -0
  115. cartography/models/scaleway/instance/flexibleip.py +52 -0
  116. cartography/models/scaleway/instance/instance.py +118 -0
  117. cartography/models/scaleway/organization.py +19 -0
  118. cartography/models/scaleway/project.py +48 -0
  119. cartography/models/scaleway/storage/__init__.py +0 -0
  120. cartography/models/scaleway/storage/snapshot.py +78 -0
  121. cartography/models/scaleway/storage/volume.py +51 -0
  122. cartography/models/trivy/__init__.py +0 -0
  123. cartography/models/trivy/findings.py +66 -0
  124. cartography/models/trivy/fix.py +66 -0
  125. cartography/models/trivy/package.py +71 -0
  126. cartography/sync.py +10 -4
  127. cartography/util.py +15 -10
  128. {cartography-0.104.0rc3.dist-info → cartography-0.106.0.dist-info}/METADATA +6 -2
  129. {cartography-0.104.0rc3.dist-info → cartography-0.106.0.dist-info}/RECORD +133 -49
  130. cartography/data/jobs/cleanup/kubernetes_import_cleanup.json +0 -70
  131. {cartography-0.104.0rc3.dist-info → cartography-0.106.0.dist-info}/WHEEL +0 -0
  132. {cartography-0.104.0rc3.dist-info → cartography-0.106.0.dist-info}/entry_points.txt +0 -0
  133. {cartography-0.104.0rc3.dist-info → cartography-0.106.0.dist-info}/licenses/LICENSE +0 -0
  134. {cartography-0.104.0rc3.dist-info → cartography-0.106.0.dist-info}/top_level.txt +0 -0
@@ -6,10 +6,18 @@ from typing import List
6
6
  import boto3
7
7
  import neo4j
8
8
 
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.aws.ecs.clusters import ECSClusterSchema
12
+ from cartography.models.aws.ecs.container_definitions import (
13
+ ECSContainerDefinitionSchema,
14
+ )
15
+ from cartography.models.aws.ecs.container_instances import ECSContainerInstanceSchema
16
+ from cartography.models.aws.ecs.containers import ECSContainerSchema
17
+ from cartography.models.aws.ecs.services import ECSServiceSchema
18
+ from cartography.models.aws.ecs.task_definitions import ECSTaskDefinitionSchema
19
+ from cartography.models.aws.ecs.tasks import ECSTaskSchema
9
20
  from cartography.util import aws_handle_regions
10
- from cartography.util import camel_to_snake
11
- from cartography.util import dict_date_to_epoch
12
- from cartography.util import run_cleanup_job
13
21
  from cartography.util import timeit
14
22
 
15
23
  logger = logging.getLogger(__name__)
@@ -118,6 +126,19 @@ def get_ecs_task_definitions(
118
126
  return task_definitions
119
127
 
120
128
 
129
+ def _get_container_defs_from_task_definitions(
130
+ definitions: list[dict[str, Any]],
131
+ ) -> list[dict[str, Any]]:
132
+ container_defs: list[dict[str, Any]] = []
133
+ for td in definitions:
134
+ for container in td.get("containerDefinitions", []):
135
+ c = container.copy()
136
+ c["_taskDefinitionArn"] = td["taskDefinitionArn"]
137
+ c["id"] = f"{td['taskDefinitionArn']}-{c['name']}"
138
+ container_defs.append(c)
139
+ return container_defs
140
+
141
+
121
142
  @timeit
122
143
  @aws_handle_regions
123
144
  def get_ecs_tasks(
@@ -141,6 +162,13 @@ def get_ecs_tasks(
141
162
  return tasks
142
163
 
143
164
 
165
+ def _get_containers_from_tasks(tasks: list[dict[str, Any]]) -> list[dict[str, Any]]:
166
+ containers: list[dict[str, Any]] = []
167
+ for task in tasks:
168
+ containers.extend(task.get("containers", []))
169
+ return containers
170
+
171
+
144
172
  @timeit
145
173
  def load_ecs_clusters(
146
174
  neo4j_session: neo4j.Session,
@@ -149,43 +177,13 @@ def load_ecs_clusters(
149
177
  current_aws_account_id: str,
150
178
  aws_update_tag: int,
151
179
  ) -> None:
152
- ingest_clusters = """
153
- UNWIND $Clusters AS cluster
154
- MERGE (c:ECSCluster{id: cluster.clusterArn})
155
- ON CREATE SET c.firstseen = timestamp()
156
- SET c.name = cluster.clusterName, c.region = $Region,
157
- c.arn = cluster.clusterArn,
158
- c.ecc_kms_key_id = cluster.configuration.executeCommandConfiguration.kmsKeyId,
159
- c.ecc_logging = cluster.configuration.executeCommandConfiguration.logging,
160
- c.ecc_log_configuration_cloud_watch_log_group_name = cluster.configuration.executeCommandConfiguration.logConfiguration.cloudWatchLogGroupName,
161
- c.ecc_log_configuration_cloud_watch_encryption_enabled = cluster.configuration.executeCommandConfiguration.logConfiguration.cloudWatchEncryptionEnabled,
162
- c.ecc_log_configuration_s3_bucket_name = cluster.configuration.executeCommandConfiguration.logConfiguration.s3BucketName,
163
- c.ecc_log_configuration_s3_encryption_enabled = cluster.configuration.executeCommandConfiguration.logConfiguration.s3EncryptionEnabled,
164
- c.ecc_log_configuration_s3_key_prefix = cluster.configuration.executeCommandConfiguration.logConfiguration.s3KeyPrefix,
165
- c.status = cluster.status,
166
- c.settings_container_insights = cluster.settings_container_insights,
167
- c.capacity_providers = cluster.capacityProviders,
168
- c.attachments_status = cluster.attachmentsStatus,
169
- c.lastupdated = $aws_update_tag
170
- WITH c
171
- MATCH (owner:AWSAccount{id: $AWS_ACCOUNT_ID})
172
- MERGE (owner)-[r:RESOURCE]->(c)
173
- ON CREATE SET r.firstseen = timestamp()
174
- SET r.lastupdated = $aws_update_tag
175
- """ # noqa:E501
176
- clusters: List[Dict[str, Any]] = []
177
- for cluster in data:
178
- for setting in cluster.get("settings", []):
179
- setting_name = camel_to_snake(setting["name"])
180
- cluster[f"settings_{setting_name}"] = setting["value"]
181
- clusters.append(cluster)
182
-
183
- neo4j_session.run(
184
- ingest_clusters,
185
- Clusters=clusters,
180
+ load(
181
+ neo4j_session,
182
+ ECSClusterSchema(),
183
+ data,
186
184
  Region=region,
187
- AWS_ACCOUNT_ID=current_aws_account_id,
188
- aws_update_tag=aws_update_tag,
185
+ AWS_ID=current_aws_account_id,
186
+ lastupdated=aws_update_tag,
189
187
  )
190
188
 
191
189
 
@@ -198,41 +196,14 @@ def load_ecs_container_instances(
198
196
  current_aws_account_id: str,
199
197
  aws_update_tag: int,
200
198
  ) -> None:
201
- ingest_instances = """
202
- UNWIND $Instances AS instance
203
- MERGE (i:ECSContainerInstance{id: instance.containerInstanceArn})
204
- ON CREATE SET i.firstseen = timestamp()
205
- SET i.ec2_instance_id = instance.ec2InstanceId, i.region = $Region,
206
- i.arn = instance.containerInstanceArn,
207
- i.capacity_provider_name = instance.capacityProviderName,
208
- i.version = instance.version,
209
- i.version_info_agent_version = instance.versionInfo.agentVersion,
210
- i.version_info_agent_hash = instance.versionInfo.agentHash,
211
- i.version_info_agent_docker_version = instance.versionInfo.dockerVersion,
212
- i.status = instance.status,
213
- i.status_reason = instance.statusReason,
214
- i.agent_connected = instance.agentConnected,
215
- i.agent_update_status = instance.agentUpdateStatus,
216
- i.registered_at = instance.registeredAt,
217
- i.lastupdated = $aws_update_tag
218
- WITH i
219
- MATCH (c:ECSCluster{id: $ClusterARN})
220
- MERGE (c)-[r:HAS_CONTAINER_INSTANCE]->(i)
221
- ON CREATE SET r.firstseen = timestamp()
222
- SET r.lastupdated = $aws_update_tag
223
- """
224
- instances: List[Dict[str, Any]] = []
225
- for instance in data:
226
- instance["registeredAt"] = dict_date_to_epoch(instance, "registeredAt")
227
- instances.append(instance)
228
-
229
- neo4j_session.run(
230
- ingest_instances,
231
- ClusterARN=cluster_arn,
232
- Instances=instances,
199
+ load(
200
+ neo4j_session,
201
+ ECSContainerInstanceSchema(),
202
+ data,
203
+ ClusterArn=cluster_arn,
233
204
  Region=region,
234
- AWS_ACCOUNT_ID=current_aws_account_id,
235
- aws_update_tag=aws_update_tag,
205
+ AWS_ID=current_aws_account_id,
206
+ lastupdated=aws_update_tag,
236
207
  )
237
208
 
238
209
 
@@ -245,135 +216,32 @@ def load_ecs_services(
245
216
  current_aws_account_id: str,
246
217
  aws_update_tag: int,
247
218
  ) -> None:
248
- ingest_services = """
249
- UNWIND $Services AS service
250
- MERGE (s:ECSService{id: service.serviceArn})
251
- ON CREATE SET s.firstseen = timestamp()
252
- SET s.name = service.serviceName, s.region = $Region,
253
- s.arn = service.serviceArn,
254
- s.cluster_arn = service.clusterArn,
255
- s.status = service.status,
256
- s.desired_count = service.desiredCount,
257
- s.running_count = service.runningCount,
258
- s.pending_count = service.pendingCount,
259
- s.launch_type = service.launchType,
260
- s.platform_version = service.platformVersion,
261
- s.platform_family = service.platformFamily,
262
- s.task_definition = service.taskDefinition,
263
- s.deployment_config_circuit_breaker_enable = service.deploymentConfiguration.deploymentCircuitBreaker.enable,
264
- s.deployment_config_circuit_breaker_rollback = service.deploymentConfiguration.deploymentCircuitBreaker.rollback,
265
- s.deployment_config_maximum_percent = service.deploymentConfiguration.maximumPercent,
266
- s.deployment_config_minimum_healthy_percent = service.deploymentConfiguration.minimumHealthyPercent,
267
- s.role_arn = service.roleArn,
268
- s.created_at = service.createdAt,
269
- s.health_check_grace_period_seconds = service.healthCheckGracePeriodSeconds,
270
- s.created_by = service.createdBy,
271
- s.enable_ecs_managed_tags = service.enableECSManagedTags,
272
- s.propagate_tags = service.propagateTags,
273
- s.enable_execute_command = service.enableExecuteCommand,
274
- s.lastupdated = $aws_update_tag
275
- WITH s
276
- MATCH (c:ECSCluster{id: $ClusterARN})
277
- MERGE (c)-[r:HAS_SERVICE]->(s)
278
- ON CREATE SET r.firstseen = timestamp()
279
- SET r.lastupdated = $aws_update_tag
280
- WITH s
281
- MATCH (d:ECSTaskDefinition{id: s.task_definition})
282
- MERGE (s)-[r2:HAS_TASK_DEFINITION]->(d)
283
- ON CREATE SET r2.firstseen = timestamp()
284
- SET r2.lastupdated = $aws_update_tag
285
- """ # noqa:E501
286
- services: List[Dict[str, Any]] = []
287
- for service in data:
288
- service["createdAt"] = dict_date_to_epoch(service, "createdAt")
289
- services.append(service)
290
-
291
- neo4j_session.run(
292
- ingest_services,
293
- ClusterARN=cluster_arn,
294
- Services=services,
219
+ load(
220
+ neo4j_session,
221
+ ECSServiceSchema(),
222
+ data,
223
+ ClusterArn=cluster_arn,
295
224
  Region=region,
296
- AWS_ACCOUNT_ID=current_aws_account_id,
297
- aws_update_tag=aws_update_tag,
225
+ AWS_ID=current_aws_account_id,
226
+ lastupdated=aws_update_tag,
298
227
  )
299
228
 
300
229
 
301
230
  @timeit
302
231
  def load_ecs_task_definitions(
303
232
  neo4j_session: neo4j.Session,
304
- data: List[Dict[str, Any]],
233
+ data: list[dict[str, Any]],
305
234
  region: str,
306
235
  current_aws_account_id: str,
307
236
  aws_update_tag: int,
308
237
  ) -> None:
309
- ingest_task_definitions = """
310
- UNWIND $Definitions AS def
311
- MERGE (d:ECSTaskDefinition{id: def.taskDefinitionArn})
312
- ON CREATE SET d.firstseen = timestamp()
313
- SET d.arn = def.taskDefinitionArn,
314
- d.region = $Region,
315
- d.family = def.family,
316
- d.task_role_arn = def.taskRoleArn,
317
- d.execution_role_arn = def.executionRoleArn,
318
- d.network_mode = def.networkMode,
319
- d.revision = def.revision,
320
- d.status = def.status,
321
- d.compatibilities = def.compatibilities,
322
- d.runtime_platform_cpu_architecture = def.runtimePlatform.cpuArchitecture,
323
- d.runtime_platform_operating_system_family = def.runtimePlatform.operatingSystemFamily,
324
- d.requires_compatibilities = def.requiresCompatibilities,
325
- d.cpu = def.cpu,
326
- d.memory = def.memory,
327
- d.pid_mode = def.pidMode,
328
- d.ipc_mode = def.ipcMode,
329
- d.proxy_configuration_type = def.proxyConfiguration.type,
330
- d.proxy_configuration_container_name = def.proxyConfiguration.containerName,
331
- d.registered_at = def.registeredAt,
332
- d.deregistered_at = def.deregisteredAt,
333
- d.registered_by = def.registeredBy,
334
- d.ephemeral_storage_size_in_gib = def.ephemeralStorage.sizeInGiB,
335
- d.lastupdated = $aws_update_tag
336
- WITH d
337
- MATCH (task:ECSTask{task_definition_arn: d.arn})
338
- MERGE (task)-[r:HAS_TASK_DEFINITION]->(d)
339
- ON CREATE SET r.firstseen = timestamp()
340
- SET r.lastupdated = $aws_update_tag
341
- WITH d
342
- MATCH (owner:AWSAccount{id: $AWS_ACCOUNT_ID})
343
- MERGE (owner)-[r:RESOURCE]->(d)
344
- ON CREATE SET r.firstseen = timestamp()
345
- SET r.lastupdated = $aws_update_tag
346
- """
347
- container_definitions: List[Dict[str, Any]] = []
348
- task_definitions: List[Dict[str, Any]] = []
349
- for task_definition in data:
350
- task_definition["registeredAt"] = dict_date_to_epoch(
351
- task_definition,
352
- "registeredAt",
353
- )
354
- task_definition["deregisteredAt"] = dict_date_to_epoch(
355
- task_definition,
356
- "deregisteredAt",
357
- )
358
- for container in task_definition.get("containerDefinitions", []):
359
- container["_taskDefinitionArn"] = task_definition["taskDefinitionArn"]
360
- container_definitions.append(container)
361
- task_definitions.append(task_definition)
362
-
363
- neo4j_session.run(
364
- ingest_task_definitions,
365
- Definitions=task_definitions,
366
- Region=region,
367
- AWS_ACCOUNT_ID=current_aws_account_id,
368
- aws_update_tag=aws_update_tag,
369
- )
370
-
371
- load_ecs_container_definitions(
238
+ load(
372
239
  neo4j_session,
373
- container_definitions,
374
- region,
375
- current_aws_account_id,
376
- aws_update_tag,
240
+ ECSTaskDefinitionSchema(),
241
+ data,
242
+ Region=region,
243
+ AWS_ID=current_aws_account_id,
244
+ lastupdated=aws_update_tag,
377
245
  )
378
246
 
379
247
 
@@ -386,86 +254,14 @@ def load_ecs_tasks(
386
254
  current_aws_account_id: str,
387
255
  aws_update_tag: int,
388
256
  ) -> None:
389
- ingest_tasks = """
390
- UNWIND $Tasks AS task
391
- MERGE (t:ECSTask{id: task.taskArn})
392
- ON CREATE SET t.firstseen = timestamp()
393
- SET t.arn = task.taskArn, t.region = $Region,
394
- t.availability_zone = task.availabilityZone,
395
- t.capacity_provider_name = task.capacityProviderName,
396
- t.cluster_arn = task.clusterArn,
397
- t.connectivity = task.connectivity,
398
- t.connectivity_at = task.connectivityAt,
399
- t.container_instance_arn = task.containerInstanceArn,
400
- t.cpu = task.cpu,
401
- t.created_at = task.createdAt,
402
- t.desired_status = task.desiredStatus,
403
- t.enable_execute_command = task.enableExecuteCommand,
404
- t.execution_stopped_at = task.executionStoppedAt,
405
- t.group = task.group,
406
- t.health_status = task.healthStatus,
407
- t.last_status = task.lastStatus,
408
- t.launch_type = task.launchType,
409
- t.memory = task.memory,
410
- t.platform_version = task.platformVersion,
411
- t.platform_family = task.platformFamily,
412
- t.pull_started_at = task.pullStartedAt,
413
- t.pull_stopped_at = task.pullStoppedAt,
414
- t.started_at = task.startedAt,
415
- t.started_by = task.startedBy,
416
- t.stop_code = task.stopCode,
417
- t.stopped_at = task.stoppedAt,
418
- t.stopped_reason = task.stoppedReason,
419
- t.stopping_at = task.stoppingAt,
420
- t.task_definition_arn = task.taskDefinitionArn,
421
- t.version = task.version,
422
- t.ephemeral_storage_size_in_gib = task.ephemeralStorage.sizeInGiB,
423
- t.lastupdated = $aws_update_tag
424
- WITH t
425
- MATCH (c:ECSCluster{id: $ClusterARN})
426
- MERGE (c)-[r:HAS_TASK]->(t)
427
- ON CREATE SET r.firstseen = timestamp()
428
- SET r.lastupdated = $aws_update_tag
429
- WITH t
430
- MATCH (td:ECSTaskDefinition{id: t.task_definition_arn})
431
- MERGE (t)-[r2:HAS_TASK_DEFINITION]->(td)
432
- ON CREATE SET r2.firstseen = timestamp()
433
- SET r2.lastupdated = $aws_update_tag
434
- WITH t
435
- MATCH (ci:ECSContainerInstance{id: t.container_instance_arn})
436
- MERGE (ci)-[r3:HAS_TASK]->(t)
437
- ON CREATE SET r3.firstseen = timestamp()
438
- SET r3.lastupdated = $aws_update_tag
439
- """
440
- containers: List[Dict[str, Any]] = []
441
- tasks: List[Dict[str, Any]] = []
442
- for task in data:
443
- task["connectivityAt"] = dict_date_to_epoch(task, "connectivityAt")
444
- task["createdAt"] = dict_date_to_epoch(task, "createdAt")
445
- task["executionStoppedAt"] = dict_date_to_epoch(task, "executionStoppedAt")
446
- task["pullStartedAt"] = dict_date_to_epoch(task, "pullStartedAt")
447
- task["pullStoppedAt"] = dict_date_to_epoch(task, "pullStoppedAt")
448
- task["startedAt"] = dict_date_to_epoch(task, "startedAt")
449
- task["stoppedAt"] = dict_date_to_epoch(task, "stoppedAt")
450
- task["stoppingAt"] = dict_date_to_epoch(task, "stoppingAt")
451
- containers.extend(task["containers"])
452
- tasks.append(task)
453
-
454
- neo4j_session.run(
455
- ingest_tasks,
456
- ClusterARN=cluster_arn,
457
- Tasks=tasks,
458
- Region=region,
459
- AWS_ACCOUNT_ID=current_aws_account_id,
460
- aws_update_tag=aws_update_tag,
461
- )
462
-
463
- load_ecs_containers(
257
+ load(
464
258
  neo4j_session,
465
- containers,
466
- region,
467
- current_aws_account_id,
468
- aws_update_tag,
259
+ ECSTaskSchema(),
260
+ data,
261
+ ClusterArn=cluster_arn,
262
+ Region=region,
263
+ AWS_ID=current_aws_account_id,
264
+ lastupdated=aws_update_tag,
469
265
  )
470
266
 
471
267
 
@@ -477,46 +273,13 @@ def load_ecs_container_definitions(
477
273
  current_aws_account_id: str,
478
274
  aws_update_tag: int,
479
275
  ) -> None:
480
- ingest_definitions = """
481
- UNWIND $Definitions AS def
482
- MERGE (d:ECSContainerDefinition{id: def._taskDefinitionArn + "-" + def.name})
483
- ON CREATE SET d.firstseen = timestamp()
484
- SET d.task_definition_arn = def._taskDefinitionArn, d.region = $Region,
485
- d.name = def.name,
486
- d.image = def.image,
487
- d.cpu = def.cpu,
488
- d.memory = def.memory,
489
- d.memory_reservation = def.memoryReservation,
490
- d.links = def.links,
491
- d.essential = def.essential,
492
- d.entry_point = def.entryPoint,
493
- d.command = def.command,
494
- d.start_timeout = def.startTimeout,
495
- d.stop_timeout = def.stop_timeout,
496
- d.hostname = def.hostname,
497
- d.user = def.user,
498
- d.working_directory = def.workingDirectory,
499
- d.disable_networking = def.disableNetworking,
500
- d.privileged = def.privileged,
501
- d.readonly_root_filesystem = def.readonlyRootFilesystem,
502
- d.dns_servers = def.dnsServers,
503
- d.dns_search_domains = def.dnsSearchDomains,
504
- d.docker_security_options = def.dockerSecurityOptions,
505
- d.interactive = def.interactive,
506
- d.pseudo_terminal = def.pseudoTerminal,
507
- d.lastupdated = $aws_update_tag
508
- WITH d
509
- MATCH (td:ECSTaskDefinition{id: d.task_definition_arn})
510
- MERGE (td)-[r:HAS_CONTAINER_DEFINITION]->(d)
511
- ON CREATE SET r.firstseen = timestamp()
512
- SET r.lastupdated = $aws_update_tag
513
- """
514
- neo4j_session.run(
515
- ingest_definitions,
516
- Definitions=data,
276
+ load(
277
+ neo4j_session,
278
+ ECSContainerDefinitionSchema(),
279
+ data,
517
280
  Region=region,
518
- AWS_ACCOUNT_ID=current_aws_account_id,
519
- aws_update_tag=aws_update_tag,
281
+ AWS_ID=current_aws_account_id,
282
+ lastupdated=aws_update_tag,
520
283
  )
521
284
 
522
285
 
@@ -528,43 +291,159 @@ def load_ecs_containers(
528
291
  current_aws_account_id: str,
529
292
  aws_update_tag: int,
530
293
  ) -> None:
531
- ingest_containers = """
532
- UNWIND $Containers AS container
533
- MERGE (c:ECSContainer{id: container.containerArn})
534
- ON CREATE SET c.firstseen = timestamp()
535
- SET c.arn = container.containerArn, c.region = $Region,
536
- c.task_arn = container.taskArn,
537
- c.name = container.name,
538
- c.image = container.image,
539
- c.image_digest = container.imageDigest,
540
- c.runtime_id = container.runtimeId,
541
- c.last_status = container.lastStatus,
542
- c.exit_code = container.exitCode,
543
- c.reason = container.reason,
544
- c.health_status = container.healthStatus,
545
- c.cpu = container.cpu,
546
- c.memory = container.memory,
547
- c.memory_reservation = container.memoryReservation,
548
- c.gpu_ids = container.gpuIds,
549
- c.lastupdated = $aws_update_tag
550
- WITH c
551
- MATCH (t:ECSTask{id: c.task_arn})
552
- MERGE (t)-[r:HAS_CONTAINER]->(c)
553
- ON CREATE SET r.firstseen = timestamp()
554
- SET r.lastupdated = $aws_update_tag
555
- """
556
- neo4j_session.run(
557
- ingest_containers,
558
- Containers=data,
294
+ load(
295
+ neo4j_session,
296
+ ECSContainerSchema(),
297
+ data,
559
298
  Region=region,
560
- AWS_ACCOUNT_ID=current_aws_account_id,
561
- aws_update_tag=aws_update_tag,
299
+ AWS_ID=current_aws_account_id,
300
+ lastupdated=aws_update_tag,
562
301
  )
563
302
 
564
303
 
565
304
  @timeit
566
305
  def cleanup_ecs(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
567
- run_cleanup_job("aws_import_ecs_cleanup.json", neo4j_session, common_job_parameters)
306
+ GraphJob.from_node_schema(ECSContainerSchema(), common_job_parameters).run(
307
+ neo4j_session
308
+ )
309
+ GraphJob.from_node_schema(ECSTaskSchema(), common_job_parameters).run(neo4j_session)
310
+ GraphJob.from_node_schema(ECSContainerInstanceSchema(), common_job_parameters).run(
311
+ neo4j_session
312
+ )
313
+ GraphJob.from_node_schema(ECSServiceSchema(), common_job_parameters).run(
314
+ neo4j_session
315
+ )
316
+ GraphJob.from_node_schema(
317
+ ECSContainerDefinitionSchema(), common_job_parameters
318
+ ).run(neo4j_session)
319
+ GraphJob.from_node_schema(ECSTaskDefinitionSchema(), common_job_parameters).run(
320
+ neo4j_session
321
+ )
322
+ GraphJob.from_node_schema(ECSClusterSchema(), common_job_parameters).run(
323
+ neo4j_session
324
+ )
325
+
326
+
327
+ @timeit
328
+ def _sync_ecs_cluster_arns(
329
+ neo4j_session: neo4j.Session,
330
+ boto3_session: boto3.session.Session,
331
+ cluster_arns: List[str],
332
+ region: str,
333
+ current_aws_account_id: str,
334
+ update_tag: int,
335
+ ) -> None:
336
+ clusters = get_ecs_clusters(boto3_session, region, cluster_arns)
337
+ if len(clusters) == 0:
338
+ return
339
+ load_ecs_clusters(
340
+ neo4j_session,
341
+ clusters,
342
+ region,
343
+ current_aws_account_id,
344
+ update_tag,
345
+ )
346
+
347
+
348
+ @timeit
349
+ def _sync_ecs_container_instances(
350
+ neo4j_session: neo4j.Session,
351
+ boto3_session: boto3.session.Session,
352
+ cluster_arn: str,
353
+ region: str,
354
+ current_aws_account_id: str,
355
+ update_tag: int,
356
+ ) -> None:
357
+ cluster_instances = get_ecs_container_instances(
358
+ cluster_arn,
359
+ boto3_session,
360
+ region,
361
+ )
362
+ load_ecs_container_instances(
363
+ neo4j_session,
364
+ cluster_arn,
365
+ cluster_instances,
366
+ region,
367
+ current_aws_account_id,
368
+ update_tag,
369
+ )
370
+
371
+
372
+ @timeit
373
+ def _sync_ecs_services(
374
+ neo4j_session: neo4j.Session,
375
+ boto3_session: boto3.session.Session,
376
+ cluster_arn: str,
377
+ region: str,
378
+ current_aws_account_id: str,
379
+ update_tag: int,
380
+ ) -> None:
381
+ services = get_ecs_services(
382
+ cluster_arn,
383
+ boto3_session,
384
+ region,
385
+ )
386
+ load_ecs_services(
387
+ neo4j_session,
388
+ cluster_arn,
389
+ services,
390
+ region,
391
+ current_aws_account_id,
392
+ update_tag,
393
+ )
394
+
395
+
396
+ @timeit
397
+ def _sync_ecs_task_and_container_defns(
398
+ neo4j_session: neo4j.Session,
399
+ boto3_session: boto3.session.Session,
400
+ cluster_arn: str,
401
+ region: str,
402
+ current_aws_account_id: str,
403
+ update_tag: int,
404
+ ) -> None:
405
+ tasks = get_ecs_tasks(
406
+ cluster_arn,
407
+ boto3_session,
408
+ region,
409
+ )
410
+ containers = _get_containers_from_tasks(tasks)
411
+ load_ecs_tasks(
412
+ neo4j_session,
413
+ cluster_arn,
414
+ tasks,
415
+ region,
416
+ current_aws_account_id,
417
+ update_tag,
418
+ )
419
+ load_ecs_containers(
420
+ neo4j_session,
421
+ containers,
422
+ region,
423
+ current_aws_account_id,
424
+ update_tag,
425
+ )
426
+
427
+ task_definitions = get_ecs_task_definitions(
428
+ boto3_session,
429
+ region,
430
+ tasks,
431
+ )
432
+ container_defs = _get_container_defs_from_task_definitions(task_definitions)
433
+ load_ecs_task_definitions(
434
+ neo4j_session,
435
+ task_definitions,
436
+ region,
437
+ current_aws_account_id,
438
+ update_tag,
439
+ )
440
+ load_ecs_container_definitions(
441
+ neo4j_session,
442
+ container_defs,
443
+ region,
444
+ current_aws_account_id,
445
+ update_tag,
446
+ )
568
447
 
569
448
 
570
449
  @timeit
@@ -578,69 +457,38 @@ def sync(
578
457
  ) -> None:
579
458
  for region in regions:
580
459
  logger.info(
581
- "Syncing ECS for region '%s' in account '%s'.",
582
- region,
583
- current_aws_account_id,
460
+ f"Syncing ECS for region '{region}' in account '{current_aws_account_id}'.",
584
461
  )
585
462
  cluster_arns = get_ecs_cluster_arns(boto3_session, region)
586
- clusters = get_ecs_clusters(boto3_session, region, cluster_arns)
587
- if len(clusters) == 0:
588
- continue
589
- load_ecs_clusters(
463
+ _sync_ecs_cluster_arns(
590
464
  neo4j_session,
591
- clusters,
465
+ boto3_session,
466
+ cluster_arns,
592
467
  region,
593
468
  current_aws_account_id,
594
469
  update_tag,
595
470
  )
596
471
  for cluster_arn in cluster_arns:
597
- cluster_instances = get_ecs_container_instances(
598
- cluster_arn,
599
- boto3_session,
600
- region,
601
- )
602
- load_ecs_container_instances(
472
+ _sync_ecs_container_instances(
603
473
  neo4j_session,
604
- cluster_arn,
605
- cluster_instances,
606
- region,
607
- current_aws_account_id,
608
- update_tag,
609
- )
610
- services = get_ecs_services(
611
- cluster_arn,
612
474
  boto3_session,
613
- region,
614
- )
615
- load_ecs_services(
616
- neo4j_session,
617
475
  cluster_arn,
618
- services,
619
476
  region,
620
477
  current_aws_account_id,
621
478
  update_tag,
622
479
  )
623
- tasks = get_ecs_tasks(
624
- cluster_arn,
625
- boto3_session,
626
- region,
627
- )
628
- load_ecs_tasks(
480
+ _sync_ecs_task_and_container_defns(
629
481
  neo4j_session,
482
+ boto3_session,
630
483
  cluster_arn,
631
- tasks,
632
484
  region,
633
485
  current_aws_account_id,
634
486
  update_tag,
635
487
  )
636
- task_definitions = get_ecs_task_definitions(
637
- boto3_session,
638
- region,
639
- tasks,
640
- )
641
- load_ecs_task_definitions(
488
+ _sync_ecs_services(
642
489
  neo4j_session,
643
- task_definitions,
490
+ boto3_session,
491
+ cluster_arn,
644
492
  region,
645
493
  current_aws_account_id,
646
494
  update_tag,