infrahub-server 1.2.0b1__py3-none-any.whl → 1.2.1__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.
Files changed (297) hide show
  1. infrahub/api/dependencies.py +6 -6
  2. infrahub/api/diff/validation_models.py +7 -7
  3. infrahub/api/schema.py +1 -1
  4. infrahub/artifacts/models.py +1 -3
  5. infrahub/artifacts/tasks.py +1 -3
  6. infrahub/cli/__init__.py +13 -9
  7. infrahub/cli/constants.py +3 -0
  8. infrahub/cli/db.py +165 -183
  9. infrahub/cli/upgrade.py +146 -0
  10. infrahub/computed_attribute/gather.py +185 -0
  11. infrahub/computed_attribute/models.py +239 -11
  12. infrahub/computed_attribute/tasks.py +77 -442
  13. infrahub/computed_attribute/triggers.py +11 -45
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +57 -57
  18. infrahub/core/branch/tasks.py +12 -9
  19. infrahub/core/changelog/diff.py +16 -8
  20. infrahub/core/changelog/models.py +189 -26
  21. infrahub/core/constants/__init__.py +5 -1
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constraint/node/runner.py +9 -8
  24. infrahub/core/diff/branch_differ.py +10 -10
  25. infrahub/core/diff/ipam_diff_parser.py +4 -5
  26. infrahub/core/diff/model/diff.py +27 -27
  27. infrahub/core/diff/model/path.py +3 -3
  28. infrahub/core/diff/query/merge.py +20 -17
  29. infrahub/core/diff/query_parser.py +4 -4
  30. infrahub/core/graph/__init__.py +1 -1
  31. infrahub/core/initialization.py +1 -10
  32. infrahub/core/ipam/constants.py +3 -4
  33. infrahub/core/ipam/reconciler.py +12 -12
  34. infrahub/core/ipam/utilization.py +10 -13
  35. infrahub/core/manager.py +34 -34
  36. infrahub/core/merge.py +7 -7
  37. infrahub/core/migrations/__init__.py +2 -3
  38. infrahub/core/migrations/graph/__init__.py +9 -4
  39. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  40. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  41. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  42. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  43. infrahub/core/migrations/graph/{m020_add_generate_template_attr.py → m022_add_generate_template_attr.py} +3 -3
  44. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  45. infrahub/core/migrations/query/attribute_add.py +2 -2
  46. infrahub/core/migrations/query/node_duplicate.py +18 -21
  47. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  48. infrahub/core/migrations/schema/models.py +19 -4
  49. infrahub/core/migrations/schema/tasks.py +2 -2
  50. infrahub/core/migrations/shared.py +16 -16
  51. infrahub/core/models.py +15 -6
  52. infrahub/core/node/__init__.py +29 -28
  53. infrahub/core/node/base.py +2 -4
  54. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  55. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  56. infrahub/core/node/constraints/interface.py +1 -2
  57. infrahub/core/node/delete_validator.py +3 -5
  58. infrahub/core/node/ipam.py +4 -4
  59. infrahub/core/node/permissions.py +7 -7
  60. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  61. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  62. infrahub/core/node/resource_manager/number_pool.py +3 -3
  63. infrahub/core/path.py +12 -12
  64. infrahub/core/property.py +11 -11
  65. infrahub/core/protocols.py +5 -0
  66. infrahub/core/protocols_base.py +21 -21
  67. infrahub/core/query/__init__.py +33 -33
  68. infrahub/core/query/attribute.py +6 -4
  69. infrahub/core/query/diff.py +3 -3
  70. infrahub/core/query/node.py +82 -32
  71. infrahub/core/query/relationship.py +24 -24
  72. infrahub/core/query/resource_manager.py +2 -0
  73. infrahub/core/query/standard_node.py +3 -3
  74. infrahub/core/query/subquery.py +9 -9
  75. infrahub/core/registry.py +13 -15
  76. infrahub/core/relationship/constraints/count.py +3 -4
  77. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  78. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  79. infrahub/core/relationship/model.py +40 -46
  80. infrahub/core/schema/attribute_schema.py +9 -9
  81. infrahub/core/schema/basenode_schema.py +93 -44
  82. infrahub/core/schema/computed_attribute.py +3 -3
  83. infrahub/core/schema/definitions/core/__init__.py +13 -19
  84. infrahub/core/schema/definitions/core/account.py +151 -148
  85. infrahub/core/schema/definitions/core/artifact.py +122 -113
  86. infrahub/core/schema/definitions/core/builtin.py +19 -16
  87. infrahub/core/schema/definitions/core/check.py +61 -53
  88. infrahub/core/schema/definitions/core/core.py +17 -0
  89. infrahub/core/schema/definitions/core/generator.py +89 -85
  90. infrahub/core/schema/definitions/core/graphql_query.py +72 -70
  91. infrahub/core/schema/definitions/core/group.py +96 -93
  92. infrahub/core/schema/definitions/core/ipam.py +176 -235
  93. infrahub/core/schema/definitions/core/lineage.py +18 -16
  94. infrahub/core/schema/definitions/core/menu.py +42 -40
  95. infrahub/core/schema/definitions/core/permission.py +144 -142
  96. infrahub/core/schema/definitions/core/profile.py +16 -27
  97. infrahub/core/schema/definitions/core/propose_change.py +88 -79
  98. infrahub/core/schema/definitions/core/propose_change_comment.py +170 -165
  99. infrahub/core/schema/definitions/core/propose_change_validator.py +290 -288
  100. infrahub/core/schema/definitions/core/repository.py +231 -225
  101. infrahub/core/schema/definitions/core/resource_pool.py +156 -166
  102. infrahub/core/schema/definitions/core/template.py +27 -12
  103. infrahub/core/schema/definitions/core/transform.py +85 -76
  104. infrahub/core/schema/definitions/core/webhook.py +127 -101
  105. infrahub/core/schema/definitions/internal.py +16 -16
  106. infrahub/core/schema/dropdown.py +3 -4
  107. infrahub/core/schema/generated/attribute_schema.py +15 -18
  108. infrahub/core/schema/generated/base_node_schema.py +12 -14
  109. infrahub/core/schema/generated/node_schema.py +3 -5
  110. infrahub/core/schema/generated/relationship_schema.py +9 -11
  111. infrahub/core/schema/generic_schema.py +2 -2
  112. infrahub/core/schema/manager.py +20 -9
  113. infrahub/core/schema/node_schema.py +4 -2
  114. infrahub/core/schema/relationship_schema.py +7 -7
  115. infrahub/core/schema/schema_branch.py +276 -138
  116. infrahub/core/schema/schema_branch_computed.py +41 -4
  117. infrahub/core/task/task.py +3 -3
  118. infrahub/core/task/user_task.py +15 -15
  119. infrahub/core/utils.py +20 -18
  120. infrahub/core/validators/__init__.py +1 -3
  121. infrahub/core/validators/aggregated_checker.py +2 -2
  122. infrahub/core/validators/attribute/choices.py +2 -2
  123. infrahub/core/validators/attribute/enum.py +2 -2
  124. infrahub/core/validators/attribute/kind.py +2 -2
  125. infrahub/core/validators/attribute/length.py +2 -2
  126. infrahub/core/validators/attribute/optional.py +2 -2
  127. infrahub/core/validators/attribute/regex.py +2 -2
  128. infrahub/core/validators/attribute/unique.py +2 -2
  129. infrahub/core/validators/checks_runner.py +25 -2
  130. infrahub/core/validators/determiner.py +1 -3
  131. infrahub/core/validators/interface.py +6 -2
  132. infrahub/core/validators/model.py +22 -3
  133. infrahub/core/validators/models/validate_migration.py +17 -4
  134. infrahub/core/validators/node/attribute.py +2 -2
  135. infrahub/core/validators/node/generate_profile.py +2 -2
  136. infrahub/core/validators/node/hierarchy.py +3 -5
  137. infrahub/core/validators/node/inherit_from.py +27 -5
  138. infrahub/core/validators/node/relationship.py +2 -2
  139. infrahub/core/validators/relationship/count.py +4 -4
  140. infrahub/core/validators/relationship/optional.py +2 -2
  141. infrahub/core/validators/relationship/peer.py +2 -2
  142. infrahub/core/validators/shared.py +2 -2
  143. infrahub/core/validators/tasks.py +8 -0
  144. infrahub/core/validators/uniqueness/checker.py +22 -21
  145. infrahub/core/validators/uniqueness/index.py +2 -2
  146. infrahub/core/validators/uniqueness/model.py +11 -11
  147. infrahub/database/__init__.py +26 -22
  148. infrahub/database/metrics.py +7 -1
  149. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  150. infrahub/dependencies/component/registry.py +2 -2
  151. infrahub/events/__init__.py +25 -2
  152. infrahub/events/artifact_action.py +13 -25
  153. infrahub/events/branch_action.py +26 -18
  154. infrahub/events/generator.py +71 -0
  155. infrahub/events/group_action.py +10 -24
  156. infrahub/events/models.py +10 -16
  157. infrahub/events/node_action.py +87 -32
  158. infrahub/events/repository_action.py +5 -18
  159. infrahub/events/schema_action.py +4 -9
  160. infrahub/events/utils.py +16 -0
  161. infrahub/events/validator_action.py +55 -0
  162. infrahub/exceptions.py +23 -24
  163. infrahub/generators/models.py +1 -3
  164. infrahub/git/base.py +7 -7
  165. infrahub/git/integrator.py +26 -25
  166. infrahub/git/models.py +22 -9
  167. infrahub/git/repository.py +3 -3
  168. infrahub/git/tasks.py +67 -49
  169. infrahub/git/utils.py +48 -0
  170. infrahub/git/worktree.py +1 -2
  171. infrahub/git_credential/askpass.py +1 -2
  172. infrahub/graphql/analyzer.py +12 -0
  173. infrahub/graphql/app.py +13 -15
  174. infrahub/graphql/context.py +6 -0
  175. infrahub/graphql/initialization.py +3 -0
  176. infrahub/graphql/loaders/node.py +2 -12
  177. infrahub/graphql/loaders/peers.py +77 -0
  178. infrahub/graphql/loaders/shared.py +13 -0
  179. infrahub/graphql/manager.py +13 -10
  180. infrahub/graphql/mutations/artifact_definition.py +5 -5
  181. infrahub/graphql/mutations/computed_attribute.py +4 -5
  182. infrahub/graphql/mutations/graphql_query.py +5 -5
  183. infrahub/graphql/mutations/ipam.py +50 -70
  184. infrahub/graphql/mutations/main.py +164 -141
  185. infrahub/graphql/mutations/menu.py +5 -5
  186. infrahub/graphql/mutations/models.py +2 -4
  187. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  188. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  189. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  190. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  191. infrahub/graphql/mutations/proposed_change.py +7 -7
  192. infrahub/graphql/mutations/relationship.py +67 -35
  193. infrahub/graphql/mutations/repository.py +8 -8
  194. infrahub/graphql/mutations/resource_manager.py +3 -3
  195. infrahub/graphql/mutations/schema.py +4 -4
  196. infrahub/graphql/mutations/webhook.py +137 -0
  197. infrahub/graphql/parser.py +4 -4
  198. infrahub/graphql/queries/diff/tree.py +4 -4
  199. infrahub/graphql/queries/ipam.py +2 -2
  200. infrahub/graphql/queries/relationship.py +2 -2
  201. infrahub/graphql/queries/search.py +2 -2
  202. infrahub/graphql/resolvers/many_relationship.py +264 -0
  203. infrahub/graphql/resolvers/resolver.py +13 -110
  204. infrahub/graphql/subscription/graphql_query.py +2 -0
  205. infrahub/graphql/types/event.py +20 -11
  206. infrahub/graphql/types/node.py +2 -2
  207. infrahub/graphql/utils.py +2 -2
  208. infrahub/groups/ancestors.py +29 -0
  209. infrahub/groups/parsers.py +107 -0
  210. infrahub/menu/generator.py +7 -7
  211. infrahub/menu/menu.py +0 -10
  212. infrahub/menu/models.py +117 -16
  213. infrahub/menu/repository.py +111 -0
  214. infrahub/menu/utils.py +5 -8
  215. infrahub/message_bus/messages/__init__.py +1 -11
  216. infrahub/message_bus/messages/check_generator_run.py +2 -0
  217. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  218. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  219. infrahub/message_bus/operations/__init__.py +0 -2
  220. infrahub/message_bus/operations/check/generator.py +1 -0
  221. infrahub/message_bus/operations/event/__init__.py +2 -2
  222. infrahub/message_bus/operations/finalize/validator.py +51 -1
  223. infrahub/message_bus/operations/requests/generator_definition.py +19 -19
  224. infrahub/message_bus/operations/requests/proposed_change.py +3 -1
  225. infrahub/pools/number.py +2 -4
  226. infrahub/proposed_change/tasks.py +37 -28
  227. infrahub/pytest_plugin.py +13 -10
  228. infrahub/server.py +1 -2
  229. infrahub/services/adapters/event/__init__.py +1 -1
  230. infrahub/task_manager/event.py +23 -9
  231. infrahub/tasks/artifact.py +2 -4
  232. infrahub/telemetry/__init__.py +0 -0
  233. infrahub/telemetry/constants.py +9 -0
  234. infrahub/telemetry/database.py +86 -0
  235. infrahub/telemetry/models.py +65 -0
  236. infrahub/telemetry/task_manager.py +77 -0
  237. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  238. infrahub/telemetry/utils.py +11 -0
  239. infrahub/trace.py +4 -4
  240. infrahub/transformations/tasks.py +2 -2
  241. infrahub/trigger/catalogue.py +2 -5
  242. infrahub/trigger/constants.py +0 -8
  243. infrahub/trigger/models.py +14 -1
  244. infrahub/trigger/setup.py +90 -0
  245. infrahub/trigger/tasks.py +35 -90
  246. infrahub/utils.py +11 -1
  247. infrahub/validators/__init__.py +0 -0
  248. infrahub/validators/events.py +42 -0
  249. infrahub/validators/tasks.py +41 -0
  250. infrahub/webhook/gather.py +17 -0
  251. infrahub/webhook/models.py +22 -5
  252. infrahub/webhook/tasks.py +44 -19
  253. infrahub/webhook/triggers.py +22 -5
  254. infrahub/workers/infrahub_async.py +2 -2
  255. infrahub/workers/utils.py +2 -2
  256. infrahub/workflows/catalogue.py +28 -20
  257. infrahub/workflows/initialization.py +1 -3
  258. infrahub/workflows/models.py +1 -1
  259. infrahub/workflows/utils.py +10 -1
  260. infrahub_sdk/client.py +27 -8
  261. infrahub_sdk/config.py +3 -0
  262. infrahub_sdk/context.py +13 -0
  263. infrahub_sdk/exceptions.py +6 -0
  264. infrahub_sdk/generator.py +4 -1
  265. infrahub_sdk/graphql.py +45 -13
  266. infrahub_sdk/node.py +69 -20
  267. infrahub_sdk/protocols_base.py +32 -11
  268. infrahub_sdk/query_groups.py +6 -35
  269. infrahub_sdk/schema/__init__.py +55 -26
  270. infrahub_sdk/schema/main.py +8 -0
  271. infrahub_sdk/task/__init__.py +10 -0
  272. infrahub_sdk/task/manager.py +12 -6
  273. infrahub_sdk/testing/schemas/animal.py +9 -0
  274. infrahub_sdk/timestamp.py +12 -4
  275. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +3 -2
  276. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +289 -260
  277. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
  278. infrahub_testcontainers/constants.py +2 -0
  279. infrahub_testcontainers/container.py +157 -12
  280. infrahub_testcontainers/docker-compose.test.yml +31 -6
  281. infrahub_testcontainers/helpers.py +18 -73
  282. infrahub_testcontainers/host.py +41 -0
  283. infrahub_testcontainers/measurements.py +93 -0
  284. infrahub_testcontainers/models.py +38 -0
  285. infrahub_testcontainers/performance_test.py +166 -0
  286. infrahub_testcontainers/plugin.py +136 -0
  287. infrahub_testcontainers/prometheus.yml +30 -0
  288. infrahub/message_bus/messages/event_branch_create.py +0 -11
  289. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  290. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  291. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  292. infrahub/message_bus/messages/event_schema_update.py +0 -9
  293. infrahub/message_bus/operations/event/node.py +0 -20
  294. infrahub/message_bus/operations/event/schema.py +0 -17
  295. infrahub/webhook/constants.py +0 -1
  296. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
  297. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,166 @@
1
+ import hashlib
2
+ import json
3
+ from datetime import UTC, datetime
4
+ from types import TracebackType
5
+ from typing import Any
6
+
7
+ import httpx
8
+ import pytest
9
+ from typing_extensions import Self
10
+
11
+ from .constants import PERFORMANCE_TEST_KIND, PERFORMANCE_TEST_VERSION
12
+ from .helpers import InfrahubDockerCompose
13
+ from .host import get_system_stats
14
+ from .models import (
15
+ ContextUnit,
16
+ InfrahubActiveMeasurementItem,
17
+ InfrahubMeasurementItem,
18
+ InfrahubResultContext,
19
+ MeasurementDefinition,
20
+ )
21
+
22
+
23
+ class InfrahubPerformanceTest:
24
+ context: dict[str, InfrahubResultContext]
25
+ measurements: list[InfrahubMeasurementItem]
26
+ active_measurements: InfrahubActiveMeasurementItem | None = None
27
+
28
+ def __init__(self, results_url: str) -> None:
29
+ self.name: str | None = None
30
+ self.infrahub_version: str | None = None
31
+ self.context = {}
32
+ self.measurements = []
33
+ self.metrics = {}
34
+ self.host = get_system_stats()
35
+ self.env_vars = {}
36
+ self.project_name = ""
37
+ self.test_info = {}
38
+ self.start_time = datetime.now(UTC)
39
+ self.end_time: datetime | None = None
40
+ self.results_url = results_url
41
+ self.scraper_endpoint = ""
42
+ self.initialized = False
43
+
44
+ def initialize(
45
+ self,
46
+ name: str,
47
+ compose: InfrahubDockerCompose | None = None,
48
+ client: Any | None = None, # noqa: ANN401
49
+ ) -> None:
50
+ self.name = name
51
+ if client:
52
+ self.infrahub_version = client.get_version()
53
+ if compose:
54
+ self.extract_compose_information(compose)
55
+
56
+ self.initialized = True
57
+
58
+ def finalize(self, session: pytest.Session) -> None:
59
+ if self.initialized:
60
+ self.end_time = datetime.now(UTC)
61
+ self.extract_test_session_information(session)
62
+ self.send_results()
63
+
64
+ def extract_compose_information(self, compose: InfrahubDockerCompose) -> None:
65
+ self.env_vars = compose.env_vars
66
+ self.project_name = compose.project_name
67
+ self.scraper_endpoint = (
68
+ f"http://127.0.0.1:{compose.get_service_host_and_port(service_name='scraper')[1]}/api/v1/export"
69
+ )
70
+
71
+ def extract_test_session_information(self, session: pytest.Session) -> None:
72
+ self.test_info = {
73
+ "summary": {
74
+ "exitstatus": session.exitstatus,
75
+ "nbr_tests": session.testscollected,
76
+ "nbr_errors": session.testsfailed,
77
+ }
78
+ }
79
+
80
+ def add_context(self, name: str, value: float | str = 0, unit: ContextUnit = ContextUnit.COUNT) -> None:
81
+ self.context[name] = InfrahubResultContext(name=name, value=value, unit=unit)
82
+
83
+ def add_measurement(
84
+ self,
85
+ definition: MeasurementDefinition,
86
+ value: float | str,
87
+ **kwargs: str | float,
88
+ ) -> None:
89
+ self.measurements.append(
90
+ InfrahubMeasurementItem(
91
+ name=definition.name,
92
+ value=value,
93
+ unit=definition.unit,
94
+ context=kwargs or {},
95
+ )
96
+ )
97
+
98
+ def start_measurement(self, definition: MeasurementDefinition, **kwargs: str | float) -> Self:
99
+ self.active_measurements = InfrahubActiveMeasurementItem(definition=definition, context=kwargs or {})
100
+ return self
101
+
102
+ def fetch_metrics(self) -> None:
103
+ with httpx.Client() as client:
104
+ # Get Infrahub metrics
105
+ response = client.post(
106
+ url=self.scraper_endpoint,
107
+ content='match[]={__name__=~"infrahub.*"}',
108
+ headers={"Content-Type": "application/x-www-form-urlencoded"},
109
+ )
110
+ self.metrics = [json.loads(line) for line in response.text.splitlines()]
111
+
112
+ # Get system metrics, filter by docker project name
113
+ response = client.post(
114
+ url=self.scraper_endpoint,
115
+ content=f'match[]={{__name__=~"container.*", container_label_com_docker_compose_project="{self.project_name}"}}',
116
+ headers={"Content-Type": "application/x-www-form-urlencoded"},
117
+ )
118
+ self.metrics += [json.loads(line) for line in response.text.splitlines()]
119
+
120
+ def __enter__(self) -> Self:
121
+ return self
122
+
123
+ def __exit__(
124
+ self,
125
+ exc_type: type[BaseException] | None,
126
+ exc_value: BaseException | None,
127
+ traceback: TracebackType | None,
128
+ ) -> None:
129
+ if not exc_type and self.active_measurements:
130
+ self.add_measurement(
131
+ definition=self.active_measurements.definition,
132
+ value=(datetime.now(UTC) - self.active_measurements.start_time).total_seconds() * 1000,
133
+ context=self.active_measurements.context,
134
+ )
135
+
136
+ # Don't record the measurement if the test failed
137
+ self.active_measurements = None
138
+
139
+ def _get_payload(self) -> dict[str, Any]:
140
+ return {
141
+ "name": self.name,
142
+ "infrahub_version": self.infrahub_version,
143
+ "start_time": self.start_time.isoformat(),
144
+ "end_time": self.end_time.isoformat() if self.end_time else None,
145
+ "duration": (self.end_time - self.start_time).total_seconds() * 1000 if self.end_time else None,
146
+ "context": [item.model_dump() for item in self.context.values()],
147
+ "measurements": [item.model_dump() for item in self.measurements],
148
+ "metrics": self.metrics,
149
+ "host": self.host,
150
+ "env_vars": self.env_vars,
151
+ "test_info": self.test_info,
152
+ }
153
+
154
+ def send_results(self) -> None:
155
+ data = self._get_payload()
156
+
157
+ payload = {
158
+ "kind": PERFORMANCE_TEST_KIND,
159
+ "payload_format": PERFORMANCE_TEST_VERSION,
160
+ "data": data,
161
+ "checksum": hashlib.sha256(json.dumps(data).encode()).hexdigest(),
162
+ }
163
+
164
+ with httpx.Client() as client:
165
+ response = client.post(self.results_url, json=payload)
166
+ response.raise_for_status()
@@ -0,0 +1,136 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ import pytest
6
+
7
+ from .performance_test import InfrahubPerformanceTest
8
+
9
+ if TYPE_CHECKING:
10
+ import _pytest
11
+
12
+
13
+ def pytest_addoption(parser: pytest.Parser) -> None:
14
+ group = parser.getgroup("infrahub-performance-test")
15
+
16
+ group.addoption(
17
+ "--performance-result-address",
18
+ action="store",
19
+ dest="infrahub_performance_test_result_address",
20
+ default="https://webhook.site/25802839-4b34-433e-9dc4-59623cd73c80",
21
+ metavar="INFRAHUB_PERFORMANCE_TEST_RESULT_ADDRESS",
22
+ help="Address to send the results of the performance test (default: %(default)s)",
23
+ )
24
+ group.addoption(
25
+ "--performance-backup",
26
+ action="store",
27
+ dest="infrahub_performance_backup",
28
+ default="neo4j_database.db",
29
+ metavar="INFRAHUB_PERFORMANCE_BACKUP",
30
+ help="Name of the backup to use (default: %(default)s)",
31
+ )
32
+ group.addoption(
33
+ "--performance-backup-location",
34
+ action="store",
35
+ dest="infrahub_performance_backup_location",
36
+ metavar="INFRAHUB_PERFORMANCE_BACKUP_LOCATION",
37
+ help="Location of the backup to use (default: %(default)s)",
38
+ )
39
+ group.addoption(
40
+ "--performance-create-backup",
41
+ action="store_true",
42
+ default=False,
43
+ dest="infrahub_performance_create_backup",
44
+ help="Generate a backup of the database (default: %(default)s)",
45
+ )
46
+ group.addoption(
47
+ "--performance-use-backup",
48
+ action="store_true",
49
+ default=False,
50
+ dest="infrahub_performance_use_backup",
51
+ help="Use a backup of the database and skip all tests that creates data (default: %(default)s)",
52
+ )
53
+ group.addoption(
54
+ "--performance-report",
55
+ action="store_true",
56
+ dest="infrahub_performance_report",
57
+ default=False,
58
+ help="Display performance report at the end of the test run",
59
+ )
60
+
61
+
62
+ def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
63
+ use_backup_skip = pytest.mark.skip(reason="load data from backup")
64
+ no_create_backup_skip = pytest.mark.skip(reason="no need to create a backup")
65
+ no_load_backup_skip = pytest.mark.skip(reason="no need to load a backup")
66
+
67
+ use_backup = config.getoption("infrahub_performance_use_backup")
68
+ create_backup = config.getoption("infrahub_performance_create_backup")
69
+
70
+ for item in items:
71
+ has_create_backup_marker = bool(
72
+ [True for marker in item.own_markers if marker.name == "performance_create_backup"]
73
+ )
74
+ has_load_backup_marker = bool([True for marker in item.own_markers if marker.name == "performance_load_backup"])
75
+ has_load_data_marker = bool([True for marker in item.own_markers if marker.name == "performance_load_data"])
76
+
77
+ if has_create_backup_marker and not create_backup:
78
+ item.add_marker(no_create_backup_skip)
79
+ if has_load_backup_marker and not use_backup:
80
+ item.add_marker(no_load_backup_skip)
81
+ if has_load_data_marker and use_backup:
82
+ item.add_marker(use_backup_skip)
83
+
84
+
85
+ def pytest_sessionstart(session: pytest.Session) -> None:
86
+ session.infrahub_performance_test = InfrahubPerformanceTest(
87
+ results_url=session.config.getoption("infrahub_performance_test_result_address")
88
+ )
89
+
90
+
91
+ def pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None: # noqa: ARG001
92
+ """whole test run finishes."""
93
+ if not session.config.getoption("infrahub_performance_report"):
94
+ return
95
+
96
+ session.infrahub_performance_test.finalize(session=session)
97
+
98
+
99
+ def pytest_runtest_teardown(item: pytest.Item, nextitem: pytest.Item | None) -> None: # noqa: ARG001
100
+ """Fetch metrics at each test teardown because there's no better hook...
101
+ pytest_sessionfinish() is executed after fixtures has been finalized and pytest_fixture_post_finalizer() is too late"""
102
+ if not item.config.getoption("infrahub_performance_report"):
103
+ return
104
+
105
+ item.session.infrahub_performance_test.fetch_metrics()
106
+
107
+
108
+ def pytest_configure(config: pytest.Config) -> None:
109
+ if config.getoption("infrahub_performance_use_backup") and config.getoption("infrahub_performance_create_backup"):
110
+ raise pytest.UsageError("--performance-use-backup and --performance-create-backup are mutually exclusive")
111
+
112
+ config.addinivalue_line("markers", "performance_create_backup: Create a backup of the database")
113
+ config.addinivalue_line("markers", "performance_load_backup: Load the backup of the database")
114
+ config.addinivalue_line("markers", "performance_load_data: Load initial data into the database")
115
+
116
+
117
+ def pytest_terminal_summary(
118
+ terminalreporter: _pytest.terminal.TerminalReporter,
119
+ exitstatus: int, # noqa: ARG001
120
+ config: pytest.Config,
121
+ ) -> None:
122
+ if not config.getoption("infrahub_performance_report"):
123
+ return
124
+
125
+ performance_test = terminalreporter._session.infrahub_performance_test
126
+
127
+ report = [
128
+ f"{measurement.name}: {measurement.value} {measurement.unit.value}"
129
+ for measurement in performance_test.measurements
130
+ ]
131
+ terminalreporter.write("\n" + "\n".join(report) + "\n")
132
+
133
+
134
+ @pytest.fixture(scope="session")
135
+ def perf_test(request: pytest.FixtureRequest) -> InfrahubPerformanceTest:
136
+ return request.session.infrahub_performance_test
@@ -0,0 +1,30 @@
1
+ ---
2
+ global:
3
+ scrape_interval: 15s
4
+
5
+ scrape_configs:
6
+ - job_name: 'infrahub-server'
7
+ dns_sd_configs:
8
+ - names:
9
+ - server
10
+ type: A
11
+ port: 8000
12
+
13
+ - job_name: 'infrahub-worker'
14
+ dns_sd_configs:
15
+ - names:
16
+ - task-worker
17
+ type: A
18
+ port: 8000
19
+
20
+ - job_name: 'cadvisor'
21
+ dns_sd_configs:
22
+ - names:
23
+ - cadvisor
24
+ type: A
25
+ port: 8080
26
+ metric_relabel_configs:
27
+ - source_labels: [container_label_namespace]
28
+ target_label: namespace
29
+ - source_labels: [container_label_pod]
30
+ target_label: pod
@@ -1,11 +0,0 @@
1
- from pydantic import Field
2
-
3
- from infrahub.message_bus import InfrahubMessage
4
-
5
-
6
- class EventBranchCreate(InfrahubMessage):
7
- """Sent a new branch is created."""
8
-
9
- branch: str = Field(..., description="The branch that was created")
10
- branch_id: str = Field(..., description="The unique ID of the branch")
11
- sync_with_git: bool = Field(..., description="Indicates if Infrahub should extend this branch to git.")
@@ -1,11 +0,0 @@
1
- from pydantic import Field
2
-
3
- from infrahub.message_bus import InfrahubMessage
4
-
5
-
6
- class EventBranchDelete(InfrahubMessage):
7
- """Sent when a branch has been deleted."""
8
-
9
- branch: str = Field(..., description="The branch that was deleted")
10
- branch_id: str = Field(..., description="The unique ID of the branch")
11
- sync_with_git: bool = Field(..., description="Indicates if the branch was extended to Git")
@@ -1,9 +0,0 @@
1
- from pydantic import Field
2
-
3
- from infrahub.message_bus import InfrahubMessage
4
-
5
-
6
- class EventBranchRebased(InfrahubMessage):
7
- """Sent when a branch has been rebased."""
8
-
9
- branch: str = Field(..., description="The branch that was rebased")
@@ -1,15 +0,0 @@
1
- from typing import Any
2
-
3
- from pydantic import Field
4
-
5
- from infrahub.message_bus import InfrahubMessage
6
-
7
-
8
- class EventNodeMutated(InfrahubMessage):
9
- """Sent when a node has been mutated"""
10
-
11
- branch: str = Field(..., description="The branch that was created")
12
- kind: str = Field(..., description="The type of object modified")
13
- node_id: str = Field(..., description="The ID of the mutated node")
14
- action: str = Field(..., description="The action taken on the node")
15
- data: dict[str, Any] = Field(..., description="Data on modified object")
@@ -1,9 +0,0 @@
1
- from pydantic import Field
2
-
3
- from infrahub.message_bus import InfrahubMessage
4
-
5
-
6
- class EventSchemaUpdate(InfrahubMessage):
7
- """Sent when the schema on a branch has been updated."""
8
-
9
- branch: str = Field(..., description="The branch where the update occurred")
@@ -1,20 +0,0 @@
1
- from infrahub.message_bus import messages
2
- from infrahub.services import InfrahubServices
3
-
4
-
5
- async def mutated(
6
- message: messages.EventNodeMutated,
7
- service: InfrahubServices,
8
- ) -> None:
9
- """Event posted when a node is mutated"""
10
- # Note for now this is only kept to facilitate publishing to other queues in the future
11
- # This operation doesn't have a flow defined to avoid having the workers need to register
12
- # the results in Prefect when they don't actually do anything aside from add noise.
13
- service.log.debug(
14
- "Mutation on node",
15
- branch=message.branch,
16
- node_id=message.node_id,
17
- action=message.action,
18
- kind=message.kind,
19
- data=message.data,
20
- )
@@ -1,17 +0,0 @@
1
- from prefect import flow
2
-
3
- from infrahub.log import get_logger
4
- from infrahub.message_bus import messages
5
- from infrahub.services import InfrahubServices
6
-
7
- log = get_logger()
8
-
9
-
10
- @flow(name="event-schema-update")
11
- async def update(message: messages.EventSchemaUpdate, service: InfrahubServices) -> None:
12
- log.info("run_message", branch=message.branch)
13
-
14
- msg = messages.RefreshRegistryBranches()
15
-
16
- msg.assign_meta(parent=message)
17
- await service.message_bus.send(message=msg)
@@ -1 +0,0 @@
1
- AUTOMATION_NAME_RUN = "Trigger-webhook-execution"