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
@@ -1,11 +1,16 @@
1
+ import logging
1
2
  from datetime import datetime
2
- from typing import List
3
- from typing import Union
3
+ from typing import Any
4
+ from typing import Callable
4
5
 
5
6
  from kubernetes import config
6
7
  from kubernetes.client import ApiClient
7
8
  from kubernetes.client import CoreV1Api
8
9
  from kubernetes.client import NetworkingV1Api
10
+ from kubernetes.client import VersionApi
11
+ from kubernetes.client.exceptions import ApiException
12
+
13
+ logger = logging.getLogger(__name__)
9
14
 
10
15
 
11
16
  class KubernetesContextNotFound(Exception):
@@ -13,39 +18,145 @@ class KubernetesContextNotFound(Exception):
13
18
 
14
19
 
15
20
  class K8CoreApiClient(CoreV1Api):
16
- def __init__(self, name: str, api_client: ApiClient = None) -> None:
21
+ def __init__(
22
+ self,
23
+ name: str,
24
+ config_file: str,
25
+ api_client: ApiClient | None = None,
26
+ ) -> None:
17
27
  self.name = name
18
28
  if not api_client:
19
- api_client = config.new_client_from_config(context=name)
29
+ api_client = config.new_client_from_config(
30
+ context=name, config_file=config_file
31
+ )
20
32
  super().__init__(api_client=api_client)
21
33
 
22
34
 
23
35
  class K8NetworkingApiClient(NetworkingV1Api):
24
- def __init__(self, name: str, api_client: ApiClient = None) -> None:
36
+ def __init__(
37
+ self,
38
+ name: str,
39
+ config_file: str,
40
+ api_client: ApiClient | None = None,
41
+ ) -> None:
42
+ self.name = name
43
+ if not api_client:
44
+ api_client = config.new_client_from_config(
45
+ context=name, config_file=config_file
46
+ )
47
+ super().__init__(api_client=api_client)
48
+
49
+
50
+ class K8VersionApiClient(VersionApi):
51
+ def __init__(
52
+ self,
53
+ name: str,
54
+ config_file: str,
55
+ api_client: ApiClient | None = None,
56
+ ) -> None:
25
57
  self.name = name
26
58
  if not api_client:
27
- api_client = config.new_client_from_config(context=name)
59
+ api_client = config.new_client_from_config(
60
+ context=name, config_file=config_file
61
+ )
28
62
  super().__init__(api_client=api_client)
29
63
 
30
64
 
31
65
  class K8sClient:
32
- def __init__(self, name: str) -> None:
66
+ def __init__(
67
+ self,
68
+ name: str,
69
+ config_file: str,
70
+ external_id: str | None = None,
71
+ ) -> None:
33
72
  self.name = name
34
- self.core = K8CoreApiClient(self.name)
35
- self.networking = K8NetworkingApiClient(self.name)
73
+ self.config_file = config_file
74
+ self.external_id = external_id
75
+ self.core = K8CoreApiClient(self.name, self.config_file)
76
+ self.networking = K8NetworkingApiClient(self.name, self.config_file)
77
+ self.version = K8VersionApiClient(self.name, self.config_file)
36
78
 
37
79
 
38
- def get_k8s_clients(kubeconfig: str) -> List[K8sClient]:
80
+ def get_k8s_clients(kubeconfig: str) -> list[K8sClient]:
81
+ # returns a tuple of (all contexts, current context)
39
82
  contexts, _ = config.list_kube_config_contexts(kubeconfig)
40
83
  if not contexts:
41
84
  raise KubernetesContextNotFound("No context found in kubeconfig.")
42
- clients = list()
85
+
86
+ clients = []
43
87
  for context in contexts:
44
- clients.append(K8sClient(context["name"]))
88
+ clients.append(
89
+ K8sClient(
90
+ context["name"],
91
+ kubeconfig,
92
+ external_id=context["context"].get("cluster"),
93
+ ),
94
+ )
45
95
  return clients
46
96
 
47
97
 
48
- def get_epoch(date: datetime) -> Union[int, None]:
98
+ def get_epoch(date: datetime | None) -> int | None:
49
99
  if date:
50
- return int(date.strftime("%s"))
100
+ return int(date.timestamp())
51
101
  return None
102
+
103
+
104
+ def k8s_paginate(
105
+ list_func: Callable,
106
+ **kwargs: Any,
107
+ ) -> list[dict[str, Any]]:
108
+ """
109
+ Handles pagination for a Kubernetes API call.
110
+
111
+ :param list_func: The list function to call (e.g. client.core.list_pod_for_all_namespaces)
112
+ :param kwargs: Keyword arguments to pass to the list function (e.g. limit=100)
113
+ :return: A list of all resources returned by the list function
114
+ """
115
+ all_resources = []
116
+ continue_token = None
117
+ limit = kwargs.pop("limit", 100)
118
+ function_name = list_func.__name__
119
+
120
+ logger.debug(f"Starting pagination for {function_name} with limit {limit}.")
121
+
122
+ while True:
123
+ try:
124
+ if continue_token:
125
+ response = list_func(limit=limit, _continue=continue_token, **kwargs)
126
+ else:
127
+ response = list_func(limit=limit, **kwargs)
128
+
129
+ # Check if items exists on the response
130
+ if not hasattr(response, "items"):
131
+ logger.warning(
132
+ f"Response from {function_name} does not contain 'items' attribute."
133
+ )
134
+ break
135
+
136
+ items_count = len(response.items)
137
+ all_resources.extend(response.items)
138
+
139
+ logger.debug(f"Retrieved {items_count} {function_name} resources")
140
+
141
+ # Check if metadata exists on the response
142
+ if not hasattr(response, "metadata"):
143
+ logger.warning(
144
+ f"Response from {function_name} does not contain 'metadata' attribute."
145
+ )
146
+ break
147
+
148
+ continue_token = response.metadata._continue
149
+ if not continue_token:
150
+ logger.debug(f"No more {function_name} resources to retrieve.")
151
+ break
152
+
153
+ except ApiException as e:
154
+ logger.error(
155
+ f"Kubernetes API error retrieving {function_name} resources. {e}: {e.status} - {e.reason}"
156
+ )
157
+ break
158
+
159
+ logger.debug(
160
+ f"Completed pagination for {function_name}: retrieved {len(all_resources)} resources"
161
+ )
162
+ return all_resources
@@ -0,0 +1,127 @@
1
+ import logging
2
+
3
+ import neo4j
4
+ import scaleway
5
+
6
+ import cartography.intel.scaleway.iam.apikeys
7
+ import cartography.intel.scaleway.iam.applications
8
+ import cartography.intel.scaleway.iam.groups
9
+ import cartography.intel.scaleway.iam.users
10
+ import cartography.intel.scaleway.instances.flexibleips
11
+ import cartography.intel.scaleway.instances.instances
12
+ import cartography.intel.scaleway.projects
13
+ import cartography.intel.scaleway.storage.snapshots
14
+ import cartography.intel.scaleway.storage.volumes
15
+ from cartography.config import Config
16
+ from cartography.util import timeit
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @timeit
22
+ def start_scaleway_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
23
+ """
24
+ If this module is configured, perform ingestion of Scaleway data. Otherwise warn and exit
25
+ :param neo4j_session: Neo4J session for database interface
26
+ :param config: A cartography.config object
27
+ :return: None
28
+ """
29
+
30
+ if (
31
+ not config.scaleway_access_key
32
+ or not config.scaleway_secret_key
33
+ or not config.scaleway_org
34
+ ):
35
+ logger.info(
36
+ "Tailscale import is not configured - skipping this module. "
37
+ "See docs to configure.",
38
+ )
39
+ return
40
+
41
+ # Create client
42
+ client = scaleway.Client(
43
+ access_key=config.scaleway_access_key,
44
+ secret_key=config.scaleway_secret_key,
45
+ )
46
+
47
+ common_job_parameters = {
48
+ "UPDATE_TAG": config.update_tag,
49
+ "ORG_ID": config.scaleway_org,
50
+ }
51
+
52
+ # Organization level
53
+ projects = cartography.intel.scaleway.projects.sync(
54
+ neo4j_session,
55
+ client,
56
+ common_job_parameters,
57
+ org_id=config.scaleway_org,
58
+ update_tag=config.update_tag,
59
+ )
60
+ projects_id = [project["id"] for project in projects]
61
+ cartography.intel.scaleway.iam.users.sync(
62
+ neo4j_session,
63
+ client,
64
+ common_job_parameters,
65
+ org_id=config.scaleway_org,
66
+ update_tag=config.update_tag,
67
+ )
68
+ cartography.intel.scaleway.iam.applications.sync(
69
+ neo4j_session,
70
+ client,
71
+ common_job_parameters,
72
+ org_id=config.scaleway_org,
73
+ update_tag=config.update_tag,
74
+ )
75
+ cartography.intel.scaleway.iam.groups.sync(
76
+ neo4j_session,
77
+ client,
78
+ common_job_parameters,
79
+ org_id=config.scaleway_org,
80
+ update_tag=config.update_tag,
81
+ )
82
+ cartography.intel.scaleway.iam.apikeys.sync(
83
+ neo4j_session,
84
+ client,
85
+ common_job_parameters,
86
+ org_id=config.scaleway_org,
87
+ update_tag=config.update_tag,
88
+ )
89
+
90
+ # Storage
91
+ cartography.intel.scaleway.storage.volumes.sync(
92
+ neo4j_session,
93
+ client,
94
+ common_job_parameters,
95
+ org_id=config.scaleway_org,
96
+ projects_id=projects_id,
97
+ update_tag=config.update_tag,
98
+ )
99
+ cartography.intel.scaleway.storage.snapshots.sync(
100
+ neo4j_session,
101
+ client,
102
+ common_job_parameters,
103
+ org_id=config.scaleway_org,
104
+ projects_id=projects_id,
105
+ update_tag=config.update_tag,
106
+ )
107
+
108
+ # Instances
109
+ # DISABLED due to https://github.com/scaleway/scaleway-sdk-python/issues/1040
110
+ """
111
+ cartography.intel.scaleway.instances.flexibleips.sync(
112
+ neo4j_session,
113
+ client,
114
+ common_job_parameters,
115
+ org_id=config.scaleway_org,
116
+ projects_id=projects_id,
117
+ update_tag=config.update_tag,
118
+ )
119
+ """
120
+ cartography.intel.scaleway.instances.instances.sync(
121
+ neo4j_session,
122
+ client,
123
+ common_job_parameters,
124
+ org_id=config.scaleway_org,
125
+ projects_id=projects_id,
126
+ update_tag=config.update_tag,
127
+ )
File without changes
@@ -0,0 +1,71 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+ import scaleway
6
+ from scaleway.iam.v1alpha1 import APIKey
7
+ from scaleway.iam.v1alpha1 import IamV1Alpha1API
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.intel.scaleway.utils import scaleway_obj_to_dict
12
+ from cartography.models.scaleway.iam.apikey import ScalewayApiKeySchema
13
+ from cartography.util import timeit
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @timeit
19
+ def sync(
20
+ neo4j_session: neo4j.Session,
21
+ client: scaleway.Client,
22
+ common_job_parameters: dict[str, Any],
23
+ org_id: str,
24
+ update_tag: int,
25
+ ) -> None:
26
+ apikeys = get(client, org_id)
27
+ formatted_apikeys = transform_apikeys(apikeys)
28
+ load_apikeys(neo4j_session, formatted_apikeys, org_id, update_tag)
29
+ cleanup(neo4j_session, common_job_parameters)
30
+
31
+
32
+ @timeit
33
+ def get(
34
+ client: scaleway.Client,
35
+ org_id: str,
36
+ ) -> list[APIKey]:
37
+ api = IamV1Alpha1API(client)
38
+ return api.list_api_keys_all(organization_id=org_id)
39
+
40
+
41
+ def transform_apikeys(apikeys: list[APIKey]) -> list[dict[str, Any]]:
42
+ formatted_apikeys = []
43
+ for apikey in apikeys:
44
+ formatted_apikeys.append(scaleway_obj_to_dict(apikey))
45
+ return formatted_apikeys
46
+
47
+
48
+ @timeit
49
+ def load_apikeys(
50
+ neo4j_session: neo4j.Session,
51
+ data: list[dict[str, Any]],
52
+ org_id: str,
53
+ update_tag: int,
54
+ ) -> None:
55
+ logger.info("Loading %d Scaleway ApiKeys into Neo4j.", len(data))
56
+ load(
57
+ neo4j_session,
58
+ ScalewayApiKeySchema(),
59
+ data,
60
+ lastupdated=update_tag,
61
+ ORG_ID=org_id,
62
+ )
63
+
64
+
65
+ @timeit
66
+ def cleanup(
67
+ neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
68
+ ) -> None:
69
+ GraphJob.from_node_schema(ScalewayApiKeySchema(), common_job_parameters).run(
70
+ neo4j_session
71
+ )
@@ -0,0 +1,71 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+ import scaleway
6
+ from scaleway.iam.v1alpha1 import Application
7
+ from scaleway.iam.v1alpha1 import IamV1Alpha1API
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.intel.scaleway.utils import scaleway_obj_to_dict
12
+ from cartography.models.scaleway.iam.application import ScalewayApplicationSchema
13
+ from cartography.util import timeit
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @timeit
19
+ def sync(
20
+ neo4j_session: neo4j.Session,
21
+ client: scaleway.Client,
22
+ common_job_parameters: dict[str, Any],
23
+ org_id: str,
24
+ update_tag: int,
25
+ ) -> None:
26
+ applications = get(client, org_id)
27
+ formatted_applications = transform_applications(applications)
28
+ load_applications(neo4j_session, formatted_applications, org_id, update_tag)
29
+ cleanup(neo4j_session, common_job_parameters)
30
+
31
+
32
+ @timeit
33
+ def get(
34
+ client: scaleway.Client,
35
+ org_id: str,
36
+ ) -> list[Application]:
37
+ api = IamV1Alpha1API(client)
38
+ return api.list_applications_all(organization_id=org_id)
39
+
40
+
41
+ def transform_applications(applications: list[Application]) -> list[dict[str, Any]]:
42
+ formatted_applications = []
43
+ for application in applications:
44
+ formatted_applications.append(scaleway_obj_to_dict(application))
45
+ return formatted_applications
46
+
47
+
48
+ @timeit
49
+ def load_applications(
50
+ neo4j_session: neo4j.Session,
51
+ data: list[dict[str, Any]],
52
+ org_id: str,
53
+ update_tag: int,
54
+ ) -> None:
55
+ logger.info("Loading %d Scaleway Applications into Neo4j.", len(data))
56
+ load(
57
+ neo4j_session,
58
+ ScalewayApplicationSchema(),
59
+ data,
60
+ lastupdated=update_tag,
61
+ ORG_ID=org_id,
62
+ )
63
+
64
+
65
+ @timeit
66
+ def cleanup(
67
+ neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
68
+ ) -> None:
69
+ GraphJob.from_node_schema(ScalewayApplicationSchema(), common_job_parameters).run(
70
+ neo4j_session
71
+ )
@@ -0,0 +1,71 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+ import scaleway
6
+ from scaleway.iam.v1alpha1 import Group
7
+ from scaleway.iam.v1alpha1 import IamV1Alpha1API
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.intel.scaleway.utils import scaleway_obj_to_dict
12
+ from cartography.models.scaleway.iam.group import ScalewayGroupSchema
13
+ from cartography.util import timeit
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @timeit
19
+ def sync(
20
+ neo4j_session: neo4j.Session,
21
+ client: scaleway.Client,
22
+ common_job_parameters: dict[str, Any],
23
+ org_id: str,
24
+ update_tag: int,
25
+ ) -> None:
26
+ groups = get(client, org_id)
27
+ formatted_groups = transform_groups(groups)
28
+ load_groups(neo4j_session, formatted_groups, org_id, update_tag)
29
+ cleanup(neo4j_session, common_job_parameters)
30
+
31
+
32
+ @timeit
33
+ def get(
34
+ client: scaleway.Client,
35
+ org_id: str,
36
+ ) -> list[Group]:
37
+ api = IamV1Alpha1API(client)
38
+ return api.list_groups_all(organization_id=org_id)
39
+
40
+
41
+ def transform_groups(groups: list[Group]) -> list[dict[str, Any]]:
42
+ formatted_groups = []
43
+ for group in groups:
44
+ formatted_groups.append(scaleway_obj_to_dict(group))
45
+ return formatted_groups
46
+
47
+
48
+ @timeit
49
+ def load_groups(
50
+ neo4j_session: neo4j.Session,
51
+ data: list[dict[str, Any]],
52
+ org_id: str,
53
+ update_tag: int,
54
+ ) -> None:
55
+ logger.info("Loading %d Scaleway Groups into Neo4j.", len(data))
56
+ load(
57
+ neo4j_session,
58
+ ScalewayGroupSchema(),
59
+ data,
60
+ lastupdated=update_tag,
61
+ ORG_ID=org_id,
62
+ )
63
+
64
+
65
+ @timeit
66
+ def cleanup(
67
+ neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
68
+ ) -> None:
69
+ GraphJob.from_node_schema(ScalewayGroupSchema(), common_job_parameters).run(
70
+ neo4j_session
71
+ )
@@ -0,0 +1,71 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+ import scaleway
6
+ from scaleway.iam.v1alpha1 import IamV1Alpha1API
7
+ from scaleway.iam.v1alpha1 import User
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.intel.scaleway.utils import scaleway_obj_to_dict
12
+ from cartography.models.scaleway.iam.user import ScalewayUserSchema
13
+ from cartography.util import timeit
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @timeit
19
+ def sync(
20
+ neo4j_session: neo4j.Session,
21
+ client: scaleway.Client,
22
+ common_job_parameters: dict[str, Any],
23
+ org_id: str,
24
+ update_tag: int,
25
+ ) -> None:
26
+ users = get(client, org_id)
27
+ formatted_users = transform_users(users)
28
+ load_users(neo4j_session, formatted_users, org_id, update_tag)
29
+ cleanup(neo4j_session, common_job_parameters)
30
+
31
+
32
+ @timeit
33
+ def get(
34
+ client: scaleway.Client,
35
+ org_id: str,
36
+ ) -> list[User]:
37
+ api = IamV1Alpha1API(client)
38
+ return api.list_users_all(organization_id=org_id)
39
+
40
+
41
+ def transform_users(users: list[User]) -> list[dict[str, Any]]:
42
+ formatted_users = []
43
+ for user in users:
44
+ formatted_users.append(scaleway_obj_to_dict(user))
45
+ return formatted_users
46
+
47
+
48
+ @timeit
49
+ def load_users(
50
+ neo4j_session: neo4j.Session,
51
+ data: list[dict[str, Any]],
52
+ org_id: str,
53
+ update_tag: int,
54
+ ) -> None:
55
+ logger.info("Loading %d Scaleway Users into Neo4j.", len(data))
56
+ load(
57
+ neo4j_session,
58
+ ScalewayUserSchema(),
59
+ data,
60
+ lastupdated=update_tag,
61
+ ORG_ID=org_id,
62
+ )
63
+
64
+
65
+ @timeit
66
+ def cleanup(
67
+ neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
68
+ ) -> None:
69
+ GraphJob.from_node_schema(ScalewayUserSchema(), common_job_parameters).run(
70
+ neo4j_session
71
+ )
File without changes
@@ -0,0 +1,86 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+ import scaleway
6
+ from scaleway.instance.v1 import InstanceV1API
7
+ from scaleway.instance.v1 import Ip
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.intel.scaleway.utils import DEFAULT_ZONE
12
+ from cartography.intel.scaleway.utils import scaleway_obj_to_dict
13
+ from cartography.models.scaleway.instance.flexibleip import ScalewayFlexibleIpSchema
14
+ from cartography.util import timeit
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ @timeit
20
+ def sync(
21
+ neo4j_session: neo4j.Session,
22
+ client: scaleway.Client,
23
+ common_job_parameters: dict[str, Any],
24
+ org_id: str,
25
+ projects_id: list[str],
26
+ update_tag: int,
27
+ ) -> None:
28
+ flexibleips = get(client, org_id)
29
+ flexibleips_by_project = transform_flexibleips(flexibleips)
30
+ load_flexibleips(neo4j_session, flexibleips_by_project, update_tag)
31
+ cleanup(neo4j_session, projects_id, common_job_parameters)
32
+
33
+
34
+ @timeit
35
+ def get(
36
+ client: scaleway.Client,
37
+ org_id: str,
38
+ ) -> list[Ip]:
39
+ api = InstanceV1API(client)
40
+ return api.list_ips_all(organization=org_id, zone=DEFAULT_ZONE)
41
+
42
+
43
+ def transform_flexibleips(
44
+ flexibleips: list[Ip],
45
+ ) -> dict[str, list[dict[str, Any]]]:
46
+ result: dict[str, list[dict[str, Any]]] = {}
47
+ for flexibleip in flexibleips:
48
+ project_id = flexibleip.project
49
+ formatted_flexibleip = scaleway_obj_to_dict(flexibleip)
50
+ result.setdefault(project_id, []).append(formatted_flexibleip)
51
+ return result
52
+
53
+
54
+ @timeit
55
+ def load_flexibleips(
56
+ neo4j_session: neo4j.Session,
57
+ data: dict[str, list[dict[str, Any]]],
58
+ update_tag: int,
59
+ ) -> None:
60
+ for project_id, flexibleips in data.items():
61
+ logger.info(
62
+ "Loading %d Scaleway Flexible IPs in project '%s' into Neo4j.",
63
+ len(flexibleips),
64
+ project_id,
65
+ )
66
+ load(
67
+ neo4j_session,
68
+ ScalewayFlexibleIpSchema(),
69
+ flexibleips,
70
+ lastupdated=update_tag,
71
+ PROJECT_ID=project_id,
72
+ )
73
+
74
+
75
+ @timeit
76
+ def cleanup(
77
+ neo4j_session: neo4j.Session,
78
+ projects_id: list[str],
79
+ common_job_parameters: dict[str, Any],
80
+ ) -> None:
81
+ for project_id in projects_id:
82
+ scopped_job_parameters = common_job_parameters.copy()
83
+ scopped_job_parameters["PROJECT_ID"] = project_id
84
+ GraphJob.from_node_schema(
85
+ ScalewayFlexibleIpSchema(), scopped_job_parameters
86
+ ).run(neo4j_session)