infrahub-server 1.2.0rc0__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 (365) 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 +5 -3
  5. infrahub/artifacts/tasks.py +3 -5
  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 +240 -12
  12. infrahub/computed_attribute/tasks.py +77 -441
  13. infrahub/computed_attribute/triggers.py +13 -47
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +58 -58
  18. infrahub/core/branch/tasks.py +74 -22
  19. infrahub/core/changelog/diff.py +95 -36
  20. infrahub/core/changelog/models.py +217 -43
  21. infrahub/core/constants/__init__.py +28 -0
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constants/schema.py +2 -0
  24. infrahub/core/constraint/node/runner.py +9 -8
  25. infrahub/core/diff/branch_differ.py +10 -10
  26. infrahub/core/diff/enricher/cardinality_one.py +5 -0
  27. infrahub/core/diff/enricher/hierarchy.py +17 -4
  28. infrahub/core/diff/enricher/labels.py +5 -0
  29. infrahub/core/diff/enricher/path_identifier.py +4 -0
  30. infrahub/core/diff/ipam_diff_parser.py +4 -5
  31. infrahub/core/diff/model/diff.py +27 -27
  32. infrahub/core/diff/model/path.py +32 -9
  33. infrahub/core/diff/parent_node_adder.py +78 -0
  34. infrahub/core/diff/payload_builder.py +13 -2
  35. infrahub/core/diff/query/filters.py +2 -2
  36. infrahub/core/diff/query/merge.py +20 -17
  37. infrahub/core/diff/query/save.py +188 -182
  38. infrahub/core/diff/query/summary_counts_enricher.py +51 -4
  39. infrahub/core/diff/query_parser.py +4 -4
  40. infrahub/core/diff/repository/deserializer.py +8 -3
  41. infrahub/core/diff/repository/repository.py +156 -38
  42. infrahub/core/diff/tasks.py +4 -4
  43. infrahub/core/graph/__init__.py +1 -1
  44. infrahub/core/graph/index.py +3 -0
  45. infrahub/core/initialization.py +1 -10
  46. infrahub/core/ipam/constants.py +3 -4
  47. infrahub/core/ipam/reconciler.py +12 -12
  48. infrahub/core/ipam/utilization.py +10 -13
  49. infrahub/core/manager.py +36 -36
  50. infrahub/core/merge.py +7 -7
  51. infrahub/core/migrations/__init__.py +2 -3
  52. infrahub/core/migrations/graph/__init__.py +12 -3
  53. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  54. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  55. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  56. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  57. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  58. infrahub/core/migrations/graph/m022_add_generate_template_attr.py +48 -0
  59. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  60. infrahub/core/migrations/query/attribute_add.py +2 -2
  61. infrahub/core/migrations/query/node_duplicate.py +43 -26
  62. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  63. infrahub/core/migrations/schema/models.py +19 -4
  64. infrahub/core/migrations/schema/node_remove.py +26 -12
  65. infrahub/core/migrations/schema/tasks.py +2 -2
  66. infrahub/core/migrations/shared.py +16 -16
  67. infrahub/core/models.py +15 -6
  68. infrahub/core/node/__init__.py +43 -39
  69. infrahub/core/node/base.py +2 -4
  70. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  71. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  72. infrahub/core/node/constraints/interface.py +1 -2
  73. infrahub/core/node/delete_validator.py +3 -5
  74. infrahub/core/node/ipam.py +4 -4
  75. infrahub/core/node/permissions.py +7 -7
  76. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  77. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  78. infrahub/core/node/resource_manager/number_pool.py +3 -3
  79. infrahub/core/path.py +12 -12
  80. infrahub/core/property.py +11 -11
  81. infrahub/core/protocols.py +7 -0
  82. infrahub/core/protocols_base.py +21 -21
  83. infrahub/core/query/__init__.py +33 -33
  84. infrahub/core/query/attribute.py +6 -4
  85. infrahub/core/query/diff.py +3 -3
  86. infrahub/core/query/node.py +82 -32
  87. infrahub/core/query/relationship.py +228 -40
  88. infrahub/core/query/resource_manager.py +2 -0
  89. infrahub/core/query/standard_node.py +3 -3
  90. infrahub/core/query/subquery.py +9 -9
  91. infrahub/core/registry.py +13 -15
  92. infrahub/core/relationship/constraints/count.py +3 -4
  93. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  94. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  95. infrahub/core/relationship/model.py +51 -59
  96. infrahub/core/schema/attribute_schema.py +16 -8
  97. infrahub/core/schema/basenode_schema.py +105 -44
  98. infrahub/core/schema/computed_attribute.py +3 -3
  99. infrahub/core/schema/definitions/core/__init__.py +147 -0
  100. infrahub/core/schema/definitions/core/account.py +171 -0
  101. infrahub/core/schema/definitions/core/artifact.py +136 -0
  102. infrahub/core/schema/definitions/core/builtin.py +24 -0
  103. infrahub/core/schema/definitions/core/check.py +68 -0
  104. infrahub/core/schema/definitions/core/core.py +17 -0
  105. infrahub/core/schema/definitions/core/generator.py +100 -0
  106. infrahub/core/schema/definitions/core/graphql_query.py +79 -0
  107. infrahub/core/schema/definitions/core/group.py +108 -0
  108. infrahub/core/schema/definitions/core/ipam.py +193 -0
  109. infrahub/core/schema/definitions/core/lineage.py +19 -0
  110. infrahub/core/schema/definitions/core/menu.py +48 -0
  111. infrahub/core/schema/definitions/core/permission.py +163 -0
  112. infrahub/core/schema/definitions/core/profile.py +18 -0
  113. infrahub/core/schema/definitions/core/propose_change.py +97 -0
  114. infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
  115. infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
  116. infrahub/core/schema/definitions/core/repository.py +286 -0
  117. infrahub/core/schema/definitions/core/resource_pool.py +170 -0
  118. infrahub/core/schema/definitions/core/template.py +27 -0
  119. infrahub/core/schema/definitions/core/transform.py +96 -0
  120. infrahub/core/schema/definitions/core/webhook.py +134 -0
  121. infrahub/core/schema/definitions/internal.py +16 -16
  122. infrahub/core/schema/dropdown.py +3 -4
  123. infrahub/core/schema/generated/attribute_schema.py +15 -18
  124. infrahub/core/schema/generated/base_node_schema.py +12 -14
  125. infrahub/core/schema/generated/node_schema.py +3 -5
  126. infrahub/core/schema/generated/relationship_schema.py +9 -11
  127. infrahub/core/schema/generic_schema.py +2 -2
  128. infrahub/core/schema/manager.py +20 -9
  129. infrahub/core/schema/node_schema.py +4 -2
  130. infrahub/core/schema/relationship_schema.py +14 -6
  131. infrahub/core/schema/schema_branch.py +292 -144
  132. infrahub/core/schema/schema_branch_computed.py +41 -4
  133. infrahub/core/task/task.py +3 -3
  134. infrahub/core/task/user_task.py +15 -15
  135. infrahub/core/timestamp.py +3 -3
  136. infrahub/core/utils.py +20 -18
  137. infrahub/core/validators/__init__.py +1 -3
  138. infrahub/core/validators/aggregated_checker.py +2 -2
  139. infrahub/core/validators/attribute/choices.py +2 -2
  140. infrahub/core/validators/attribute/enum.py +2 -2
  141. infrahub/core/validators/attribute/kind.py +2 -2
  142. infrahub/core/validators/attribute/length.py +2 -2
  143. infrahub/core/validators/attribute/optional.py +2 -2
  144. infrahub/core/validators/attribute/regex.py +2 -2
  145. infrahub/core/validators/attribute/unique.py +2 -2
  146. infrahub/core/validators/checks_runner.py +25 -2
  147. infrahub/core/validators/determiner.py +1 -3
  148. infrahub/core/validators/interface.py +6 -2
  149. infrahub/core/validators/model.py +22 -3
  150. infrahub/core/validators/models/validate_migration.py +17 -4
  151. infrahub/core/validators/node/attribute.py +2 -2
  152. infrahub/core/validators/node/generate_profile.py +2 -2
  153. infrahub/core/validators/node/hierarchy.py +3 -5
  154. infrahub/core/validators/node/inherit_from.py +27 -5
  155. infrahub/core/validators/node/relationship.py +2 -2
  156. infrahub/core/validators/relationship/count.py +4 -4
  157. infrahub/core/validators/relationship/optional.py +2 -2
  158. infrahub/core/validators/relationship/peer.py +2 -2
  159. infrahub/core/validators/shared.py +2 -2
  160. infrahub/core/validators/tasks.py +8 -0
  161. infrahub/core/validators/uniqueness/checker.py +22 -21
  162. infrahub/core/validators/uniqueness/index.py +2 -2
  163. infrahub/core/validators/uniqueness/model.py +11 -11
  164. infrahub/database/__init__.py +27 -22
  165. infrahub/database/metrics.py +7 -1
  166. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  167. infrahub/dependencies/builder/diff/deserializer.py +3 -1
  168. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  169. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  170. infrahub/dependencies/component/registry.py +2 -2
  171. infrahub/events/__init__.py +25 -2
  172. infrahub/events/artifact_action.py +64 -0
  173. infrahub/events/branch_action.py +33 -22
  174. infrahub/events/generator.py +71 -0
  175. infrahub/events/group_action.py +51 -21
  176. infrahub/events/models.py +18 -19
  177. infrahub/events/node_action.py +88 -37
  178. infrahub/events/repository_action.py +5 -18
  179. infrahub/events/schema_action.py +4 -9
  180. infrahub/events/utils.py +16 -0
  181. infrahub/events/validator_action.py +55 -0
  182. infrahub/exceptions.py +32 -24
  183. infrahub/generators/models.py +2 -3
  184. infrahub/generators/tasks.py +24 -4
  185. infrahub/git/base.py +7 -7
  186. infrahub/git/integrator.py +48 -24
  187. infrahub/git/models.py +101 -9
  188. infrahub/git/repository.py +3 -3
  189. infrahub/git/tasks.py +408 -6
  190. infrahub/git/utils.py +48 -0
  191. infrahub/git/worktree.py +1 -2
  192. infrahub/git_credential/askpass.py +1 -2
  193. infrahub/graphql/analyzer.py +12 -0
  194. infrahub/graphql/app.py +13 -15
  195. infrahub/graphql/context.py +39 -0
  196. infrahub/graphql/initialization.py +3 -0
  197. infrahub/graphql/loaders/node.py +2 -12
  198. infrahub/graphql/loaders/peers.py +77 -0
  199. infrahub/graphql/loaders/shared.py +13 -0
  200. infrahub/graphql/manager.py +17 -19
  201. infrahub/graphql/mutations/artifact_definition.py +5 -5
  202. infrahub/graphql/mutations/branch.py +26 -1
  203. infrahub/graphql/mutations/computed_attribute.py +9 -5
  204. infrahub/graphql/mutations/diff.py +23 -11
  205. infrahub/graphql/mutations/diff_conflict.py +5 -0
  206. infrahub/graphql/mutations/generator.py +83 -0
  207. infrahub/graphql/mutations/graphql_query.py +5 -5
  208. infrahub/graphql/mutations/ipam.py +54 -74
  209. infrahub/graphql/mutations/main.py +195 -132
  210. infrahub/graphql/mutations/menu.py +7 -7
  211. infrahub/graphql/mutations/models.py +2 -4
  212. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  213. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  214. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  215. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  216. infrahub/graphql/mutations/proposed_change.py +7 -7
  217. infrahub/graphql/mutations/relationship.py +93 -19
  218. infrahub/graphql/mutations/repository.py +8 -8
  219. infrahub/graphql/mutations/resource_manager.py +3 -3
  220. infrahub/graphql/mutations/schema.py +19 -4
  221. infrahub/graphql/mutations/webhook.py +137 -0
  222. infrahub/graphql/parser.py +4 -4
  223. infrahub/graphql/permissions.py +1 -10
  224. infrahub/graphql/queries/diff/tree.py +19 -14
  225. infrahub/graphql/queries/event.py +5 -2
  226. infrahub/graphql/queries/ipam.py +2 -2
  227. infrahub/graphql/queries/relationship.py +2 -2
  228. infrahub/graphql/queries/search.py +2 -2
  229. infrahub/graphql/resolvers/many_relationship.py +264 -0
  230. infrahub/graphql/resolvers/resolver.py +13 -110
  231. infrahub/graphql/schema.py +2 -0
  232. infrahub/graphql/subscription/graphql_query.py +2 -0
  233. infrahub/graphql/types/context.py +12 -0
  234. infrahub/graphql/types/event.py +84 -17
  235. infrahub/graphql/types/node.py +2 -2
  236. infrahub/graphql/utils.py +2 -2
  237. infrahub/groups/ancestors.py +29 -0
  238. infrahub/groups/parsers.py +107 -0
  239. infrahub/lock.py +20 -20
  240. infrahub/menu/constants.py +0 -1
  241. infrahub/menu/generator.py +9 -21
  242. infrahub/menu/menu.py +17 -38
  243. infrahub/menu/models.py +117 -16
  244. infrahub/menu/repository.py +111 -0
  245. infrahub/menu/utils.py +5 -8
  246. infrahub/message_bus/__init__.py +11 -13
  247. infrahub/message_bus/messages/__init__.py +1 -21
  248. infrahub/message_bus/messages/check_generator_run.py +3 -3
  249. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  250. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  251. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  252. infrahub/message_bus/messages/send_echo_request.py +1 -1
  253. infrahub/message_bus/operations/__init__.py +1 -10
  254. infrahub/message_bus/operations/check/__init__.py +2 -2
  255. infrahub/message_bus/operations/check/generator.py +1 -0
  256. infrahub/message_bus/operations/event/__init__.py +2 -2
  257. infrahub/message_bus/operations/event/worker.py +0 -3
  258. infrahub/message_bus/operations/finalize/validator.py +51 -1
  259. infrahub/message_bus/operations/requests/__init__.py +0 -2
  260. infrahub/message_bus/operations/requests/generator_definition.py +21 -23
  261. infrahub/message_bus/operations/requests/proposed_change.py +14 -10
  262. infrahub/permissions/globals.py +15 -0
  263. infrahub/pools/number.py +2 -4
  264. infrahub/proposed_change/models.py +3 -0
  265. infrahub/proposed_change/tasks.py +58 -45
  266. infrahub/pytest_plugin.py +13 -10
  267. infrahub/server.py +2 -3
  268. infrahub/services/__init__.py +2 -2
  269. infrahub/services/adapters/cache/__init__.py +4 -6
  270. infrahub/services/adapters/cache/nats.py +4 -5
  271. infrahub/services/adapters/cache/redis.py +3 -7
  272. infrahub/services/adapters/event/__init__.py +1 -1
  273. infrahub/services/adapters/message_bus/__init__.py +3 -3
  274. infrahub/services/adapters/message_bus/local.py +2 -2
  275. infrahub/services/adapters/message_bus/nats.py +4 -4
  276. infrahub/services/adapters/message_bus/rabbitmq.py +4 -4
  277. infrahub/services/adapters/workflow/local.py +2 -2
  278. infrahub/services/component.py +5 -5
  279. infrahub/services/protocols.py +7 -7
  280. infrahub/services/scheduler.py +1 -3
  281. infrahub/task_manager/event.py +102 -9
  282. infrahub/task_manager/models.py +27 -7
  283. infrahub/tasks/artifact.py +7 -6
  284. infrahub/telemetry/__init__.py +0 -0
  285. infrahub/telemetry/constants.py +9 -0
  286. infrahub/telemetry/database.py +86 -0
  287. infrahub/telemetry/models.py +65 -0
  288. infrahub/telemetry/task_manager.py +77 -0
  289. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  290. infrahub/telemetry/utils.py +11 -0
  291. infrahub/trace.py +4 -4
  292. infrahub/transformations/tasks.py +2 -2
  293. infrahub/trigger/catalogue.py +4 -6
  294. infrahub/trigger/constants.py +0 -8
  295. infrahub/trigger/models.py +54 -5
  296. infrahub/trigger/setup.py +90 -0
  297. infrahub/trigger/tasks.py +35 -84
  298. infrahub/utils.py +11 -1
  299. infrahub/validators/__init__.py +0 -0
  300. infrahub/validators/events.py +42 -0
  301. infrahub/validators/tasks.py +41 -0
  302. infrahub/webhook/gather.py +17 -0
  303. infrahub/webhook/models.py +176 -44
  304. infrahub/webhook/tasks.py +154 -155
  305. infrahub/webhook/triggers.py +31 -7
  306. infrahub/workers/infrahub_async.py +2 -2
  307. infrahub/workers/utils.py +2 -2
  308. infrahub/workflows/catalogue.py +86 -35
  309. infrahub/workflows/initialization.py +8 -2
  310. infrahub/workflows/models.py +27 -1
  311. infrahub/workflows/utils.py +10 -1
  312. infrahub_sdk/client.py +35 -8
  313. infrahub_sdk/config.py +3 -0
  314. infrahub_sdk/context.py +13 -0
  315. infrahub_sdk/ctl/branch.py +3 -2
  316. infrahub_sdk/ctl/cli_commands.py +5 -1
  317. infrahub_sdk/ctl/utils.py +0 -16
  318. infrahub_sdk/exceptions.py +12 -0
  319. infrahub_sdk/generator.py +4 -1
  320. infrahub_sdk/graphql.py +45 -13
  321. infrahub_sdk/node.py +71 -22
  322. infrahub_sdk/protocols.py +21 -8
  323. infrahub_sdk/protocols_base.py +32 -11
  324. infrahub_sdk/query_groups.py +6 -35
  325. infrahub_sdk/schema/__init__.py +55 -26
  326. infrahub_sdk/schema/main.py +8 -0
  327. infrahub_sdk/task/__init__.py +11 -0
  328. infrahub_sdk/task/constants.py +3 -0
  329. infrahub_sdk/task/exceptions.py +25 -0
  330. infrahub_sdk/task/manager.py +551 -0
  331. infrahub_sdk/task/models.py +74 -0
  332. infrahub_sdk/testing/schemas/animal.py +9 -0
  333. infrahub_sdk/timestamp.py +142 -33
  334. infrahub_sdk/utils.py +29 -1
  335. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +8 -6
  336. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +349 -293
  337. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
  338. infrahub_testcontainers/constants.py +2 -0
  339. infrahub_testcontainers/container.py +157 -12
  340. infrahub_testcontainers/docker-compose.test.yml +31 -6
  341. infrahub_testcontainers/helpers.py +18 -73
  342. infrahub_testcontainers/host.py +41 -0
  343. infrahub_testcontainers/measurements.py +93 -0
  344. infrahub_testcontainers/models.py +38 -0
  345. infrahub_testcontainers/performance_test.py +166 -0
  346. infrahub_testcontainers/plugin.py +136 -0
  347. infrahub_testcontainers/prometheus.yml +30 -0
  348. infrahub/core/schema/definitions/core.py +0 -2286
  349. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  350. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  351. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  352. infrahub/message_bus/messages/event_branch_create.py +0 -11
  353. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  354. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  355. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  356. infrahub/message_bus/messages/event_schema_update.py +0 -9
  357. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  358. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  359. infrahub/message_bus/operations/check/repository.py +0 -293
  360. infrahub/message_bus/operations/event/node.py +0 -20
  361. infrahub/message_bus/operations/event/schema.py +0 -17
  362. infrahub/message_bus/operations/requests/repository.py +0 -133
  363. infrahub/webhook/constants.py +0 -1
  364. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
  365. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
@@ -9,4 +9,5 @@ infrahubasync=infrahub.workers.infrahub_async
9
9
 
10
10
  [pytest11]
11
11
  pytest-infrahub=infrahub_sdk.pytest_plugin.plugin
12
+ pytest-infrahub-performance-test=infrahub_testcontainers.plugin
12
13
 
@@ -0,0 +1,2 @@
1
+ PERFORMANCE_TEST_KIND: str = "end-2-end"
2
+ PERFORMANCE_TEST_VERSION: str = "v20250216"
@@ -1,10 +1,12 @@
1
1
  import os
2
+ import shutil
2
3
  import uuid
3
- from dataclasses import dataclass
4
+ from dataclasses import dataclass, field
4
5
  from functools import cached_property
5
6
  from pathlib import Path
6
7
 
7
8
  from testcontainers.compose import DockerCompose
9
+ from testcontainers.core.exceptions import ContainerIsNotRunning
8
10
  from typing_extensions import Self
9
11
 
10
12
  from infrahub_testcontainers import __version__ as infrahub_version
@@ -19,14 +21,21 @@ class ContainerService:
19
21
  INFRAHUB_SERVICES: dict[str, ContainerService] = {
20
22
  "server": ContainerService(container="infrahub-server-lb", port=8000),
21
23
  "task-manager": ContainerService(container="task-manager", port=4200),
24
+ "database": ContainerService(container="database", port=7687),
25
+ "scraper": ContainerService(container="scraper", port=8428),
26
+ "cadvisor": ContainerService(container="cadvisor", port=8080),
22
27
  }
23
28
 
24
29
  PROJECT_ENV_VARIABLES: dict[str, str] = {
30
+ "NEO4J_DOCKER_IMAGE": "neo4j:5.20.0-community",
31
+ "MESSAGE_QUEUE_DOCKER_IMAGE": "rabbitmq:3.13.7-management",
32
+ "CACHE_DOCKER_IMAGE": "redis:7.2.4",
25
33
  "INFRAHUB_TESTING_DOCKER_IMAGE": "registry.opsmill.io/opsmill/infrahub",
34
+ "INFRAHUB_TESTING_DOCKER_ENTRYPOINT": f"gunicorn --config backend/infrahub/serve/gunicorn_config.py -w {os.environ.get('INFRAHUB_TESTING_WEB_CONCURRENCY', 4)} --logger-class infrahub.serve.log.GunicornLogger infrahub.server:app", # noqa: E501
26
35
  "INFRAHUB_TESTING_IMAGE_VERSION": infrahub_version,
27
36
  "INFRAHUB_TESTING_PRODUCTION": "false",
28
37
  "INFRAHUB_TESTING_DB_ADDRESS": "database",
29
- "INFRAHUB_TESTING_LOG_LEVEL": "DEBUG",
38
+ "INFRAHUB_TESTING_LOG_LEVEL": "INFO",
30
39
  "INFRAHUB_TESTING_GIT_REPOSITORIES_DIRECTORY": "/opt/infrahub/git",
31
40
  "INFRAHUB_TESTING_API_TOKEN": "44af444d-3b26-410d-9546-b758657e026c",
32
41
  "INFRAHUB_TESTING_INITIAL_ADMIN_TOKEN": "06438eb2-8019-4776-878c-0941b1f1d1ec",
@@ -37,6 +46,7 @@ PROJECT_ENV_VARIABLES: dict[str, str] = {
37
46
  "INFRAHUB_TESTING_BROKER_ADDRESS": "message-queue",
38
47
  "INFRAHUB_TESTING_CACHE_ADDRESS": "cache",
39
48
  "INFRAHUB_TESTING_WORKFLOW_ADDRESS": "task-manager",
49
+ "INFRAHUB_TESTING_WORKFLOW_DEFAULT_WORKER_TYPE": "infrahubasync",
40
50
  "INFRAHUB_TESTING_TIMEOUT": "60",
41
51
  "INFRAHUB_TESTING_PREFECT_API": "http://task-manager:4200/api",
42
52
  "INFRAHUB_TESTING_LOCAL_REMOTE_GIT_DIRECTORY": "repos",
@@ -52,6 +62,7 @@ PROJECT_ENV_VARIABLES: dict[str, str] = {
52
62
  @dataclass
53
63
  class InfrahubDockerCompose(DockerCompose):
54
64
  project_name: str | None = None
65
+ env_vars: dict[str, str] = field(default_factory=dict)
55
66
 
56
67
  @classmethod
57
68
  def init(cls, directory: Path | None = None, version: str | None = None) -> Self:
@@ -65,43 +76,111 @@ class InfrahubDockerCompose(DockerCompose):
65
76
  if version == "local" and infrahub_image_version:
66
77
  version = infrahub_image_version
67
78
 
68
- cls.create_docker_file(directory=directory)
69
- cls.create_env_file(directory=directory, version=version)
79
+ compose = cls(project_name=cls.generate_project_name(), context=directory)
80
+ compose.create_docker_file(directory=directory)
81
+ compose.create_env_file(directory=directory, version=version)
70
82
 
71
- return cls(project_name=cls.generate_project_name(), context=directory)
83
+ return compose
84
+
85
+ def get_env_var(self, key: str) -> str:
86
+ if not self.env_vars:
87
+ raise ValueError("env_vars hasn't been initialized yet")
88
+ if key not in self.env_vars:
89
+ raise ValueError(f"{key} is not set in the environment variables")
90
+ return self.env_vars[key]
91
+
92
+ @property
93
+ def use_neo4j_enterprise(self) -> bool:
94
+ return "enterprise" in self.get_env_var("NEO4J_DOCKER_IMAGE")
95
+
96
+ @property
97
+ def internal_backup_dir(self) -> Path:
98
+ return Path(self.get_env_var("INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY"))
99
+
100
+ @property
101
+ def external_backup_dir(self) -> Path:
102
+ return Path(self.context) / Path(self.get_env_var("INFRAHUB_TESTING_LOCAL_DB_BACKUP_DIRECTORY"))
72
103
 
73
104
  @classmethod
74
105
  def generate_project_name(cls) -> str:
75
106
  project_id = str(uuid.uuid4())[:8]
76
107
  return f"infrahub-test-{project_id}"
77
108
 
78
- @classmethod
79
- def create_docker_file(cls, directory: Path) -> Path:
109
+ def create_docker_file(self, directory: Path) -> Path:
80
110
  current_directory = Path(__file__).resolve().parent
81
111
  compose_file = current_directory / "docker-compose.test.yml"
82
112
 
83
113
  test_compose_file = directory / "docker-compose.yml"
84
114
  test_compose_file.write_bytes(compose_file.read_bytes())
85
115
 
86
- haproxy_config_file = current_directory / "haproxy.cfg"
116
+ for file in ["haproxy.cfg", "prometheus.yml"]:
117
+ config_file = current_directory / file
87
118
 
88
- test_haproxy_config_file = directory / "haproxy.cfg"
89
- test_haproxy_config_file.write_bytes(haproxy_config_file.read_bytes())
119
+ test_config_file = directory / file
120
+ test_config_file.write_bytes(config_file.read_bytes())
90
121
 
91
122
  return test_compose_file
92
123
 
93
- @classmethod
94
- def create_env_file(cls, directory: Path, version: str) -> Path:
124
+ def create_env_file(self, directory: Path, version: str) -> Path:
95
125
  env_file = directory / ".env"
96
126
 
97
127
  PROJECT_ENV_VARIABLES.update({"INFRAHUB_TESTING_IMAGE_VERSION": version})
128
+ if os.environ.get("INFRAHUB_TESTING_ENTERPRISE"):
129
+ PROJECT_ENV_VARIABLES.update(
130
+ {
131
+ "INFRAHUB_TESTING_DOCKER_IMAGE": "registry.opsmill.io/opsmill/infrahub-enterprise",
132
+ "INFRAHUB_TESTING_DOCKER_ENTRYPOINT": f"gunicorn --config community/backend/infrahub/serve/gunicorn_config.py -w {os.environ.get('INFRAHUB_TESTING_WEB_CONCURRENCY', 4)} --logger-class infrahub.serve.log.GunicornLogger infrahub_enterprise.server:app", # noqa: E501
133
+ "INFRAHUB_TESTING_WORKFLOW_DEFAULT_WORKER_TYPE": "infrahubentasync",
134
+ "NEO4J_DOCKER_IMAGE": "neo4j:5.20.0-enterprise",
135
+ }
136
+ )
98
137
 
99
138
  with env_file.open(mode="w", encoding="utf-8") as file:
100
139
  for key, value in PROJECT_ENV_VARIABLES.items():
101
140
  env_var_value = os.environ.get(key, value)
102
141
  file.write(f"{key}={env_var_value}\n")
142
+ self.env_vars[key] = env_var_value
143
+
103
144
  return env_file.absolute()
104
145
 
146
+ def restart(self) -> None:
147
+ """
148
+ Restart the docker compose environment.
149
+
150
+ TODO Would be good to contribute this upstream
151
+ """
152
+ cmd = self.compose_command_property[:]
153
+ cmd += ["restart"]
154
+
155
+ if self.services:
156
+ cmd.extend(self.services)
157
+ self._run_command(cmd=cmd)
158
+
159
+ def start_container(self, service_name: str) -> None:
160
+ """
161
+ Starts a specific service of the docker compose environment.
162
+
163
+ TODO Would be good to contribute this upstream
164
+ """
165
+ base_cmd = self.compose_command_property or []
166
+
167
+ # pull means running a separate command before starting
168
+ if self.pull:
169
+ pull_cmd = [*base_cmd, "pull", service_name]
170
+ self._run_command(cmd=pull_cmd)
171
+
172
+ up_cmd = [*base_cmd, "up"]
173
+
174
+ # build means modifying the up command
175
+ if self.wait:
176
+ up_cmd.append("--wait")
177
+ else:
178
+ # we run in detached mode instead of blocking
179
+ up_cmd.append("--detach")
180
+
181
+ up_cmd.append(service_name)
182
+ self._run_command(cmd=up_cmd)
183
+
105
184
  # TODO would be good to the support for project_name upstream
106
185
  @cached_property
107
186
  def compose_command_property(self) -> list[str]:
@@ -120,3 +199,69 @@ class InfrahubDockerCompose(DockerCompose):
120
199
  service_name: int(self.get_service_port(service_name=service_data.container, port=service_data.port) or 0)
121
200
  for service_name, service_data in INFRAHUB_SERVICES.items()
122
201
  }
202
+
203
+ def database_create_backup(self, backup_name: str = "neo4j_database.backup", dest_dir: Path | None = None) -> None:
204
+ assert self.use_neo4j_enterprise
205
+
206
+ self.exec_in_container(
207
+ command=[
208
+ "neo4j-admin",
209
+ "database",
210
+ "backup",
211
+ "--compress=false",
212
+ "--to-path",
213
+ str(self.internal_backup_dir),
214
+ ],
215
+ service_name="database",
216
+ )
217
+
218
+ if dest_dir:
219
+ backup_files = list(self.external_backup_dir.glob("*.backup"))
220
+ if not backup_files:
221
+ raise FileNotFoundError(f"No .backup files found in {self.external_backup_dir}")
222
+
223
+ backup_file = backup_files[0]
224
+ shutil.copy(
225
+ backup_file,
226
+ dest_dir / backup_name,
227
+ )
228
+
229
+ def database_restore_backup(self, backup_file: Path) -> None:
230
+ assert self.use_neo4j_enterprise
231
+
232
+ shutil.copy(
233
+ str(backup_file),
234
+ str(self.external_backup_dir / backup_file.name),
235
+ )
236
+ service_name = "database"
237
+
238
+ # Ensure the database container is running otherwise start it
239
+ try:
240
+ self.get_container(service_name=service_name)
241
+ except ContainerIsNotRunning:
242
+ self.start_container(service_name=service_name)
243
+
244
+ self.exec_in_container(
245
+ command=["cypher-shell", "-u", "neo4j", "-p", "admin", "STOP DATABASE neo4j;"],
246
+ service_name=service_name,
247
+ )
248
+
249
+ self.exec_in_container(
250
+ command=[
251
+ "neo4j-admin",
252
+ "database",
253
+ "restore",
254
+ "--overwrite-destination",
255
+ "--from-path",
256
+ str(self.internal_backup_dir / backup_file.name),
257
+ ],
258
+ service_name=service_name,
259
+ )
260
+
261
+ self.exec_in_container(
262
+ command=["cypher-shell", "-d", "system", "-u", "neo4j", "-p", "admin", "START DATABASE neo4j;"],
263
+ service_name=service_name,
264
+ )
265
+
266
+ self.stop(down=False)
267
+ self.start()
@@ -102,11 +102,7 @@ services:
102
102
  mode: replicated
103
103
  replicas: ${INFRAHUB_TESTING_API_SERVER_COUNT}
104
104
  image: "${INFRAHUB_TESTING_DOCKER_IMAGE}:${INFRAHUB_TESTING_IMAGE_VERSION}"
105
- command: >
106
- gunicorn --config backend/infrahub/serve/gunicorn_config.py
107
- -w ${INFRAHUB_TESTING_WEB_CONCURRENCY}
108
- --logger-class infrahub.serve.log.GunicornLogger
109
- infrahub.server:app
105
+ command: ${INFRAHUB_TESTING_DOCKER_ENTRYPOINT}
110
106
  environment:
111
107
  INFRAHUB_PRODUCTION: ${INFRAHUB_TESTING_PRODUCTION}
112
108
  INFRAHUB_LOG_LEVEL: ${INFRAHUB_TESTING_LOG_LEVEL:-INFO}
@@ -114,6 +110,7 @@ services:
114
110
  INFRAHUB_CACHE_ADDRESS: ${INFRAHUB_TESTING_CACHE_ADDRESS}
115
111
  INFRAHUB_DB_ADDRESS: ${INFRAHUB_TESTING_DB_ADDRESS}
116
112
  INFRAHUB_WORKFLOW_ADDRESS: ${INFRAHUB_TESTING_WORKFLOW_ADDRESS}
113
+ INFRAHUB_WORKFLOW_DEFAULT_WORKER_TYPE: ${INFRAHUB_TESTING_WORKFLOW_DEFAULT_WORKER_TYPE}
117
114
  INFRAHUB_INITIAL_ADMIN_TOKEN: ${INFRAHUB_TESTING_INITIAL_ADMIN_TOKEN}
118
115
  INFRAHUB_INITIAL_AGENT_TOKEN: ${INFRAHUB_TESTING_INITIAL_AGENT_TOKEN}
119
116
  INFRAHUB_SECURITY_SECRET_KEY: ${INFRAHUB_TESTING_SECURITY_SECRET_KEY}
@@ -142,7 +139,7 @@ services:
142
139
  mode: replicated
143
140
  replicas: ${INFRAHUB_TESTING_TASK_WORKER_COUNT}
144
141
  image: "${INFRAHUB_TESTING_DOCKER_IMAGE}:${INFRAHUB_TESTING_IMAGE_VERSION}"
145
- command: prefect worker start --type infrahubasync --pool infrahub-worker --with-healthcheck
142
+ command: prefect worker start --type ${INFRAHUB_TESTING_WORKFLOW_DEFAULT_WORKER_TYPE} --pool infrahub-worker --with-healthcheck
146
143
  environment:
147
144
  INFRAHUB_PRODUCTION: ${INFRAHUB_TESTING_PRODUCTION}
148
145
  INFRAHUB_LOG_LEVEL: ${INFRAHUB_TESTING_LOG_LEVEL}
@@ -163,8 +160,36 @@ services:
163
160
  - "./${INFRAHUB_TESTING_LOCAL_REMOTE_GIT_DIRECTORY}:${INFRAHUB_TESTING_INTERNAL_REMOTE_GIT_DIRECTORY}"
164
161
  tty: true
165
162
 
163
+ cadvisor:
164
+ image: "${CADVISOR_DOCKER_IMAGE:-gcr.io/cadvisor/cadvisor:v0.51.0}"
165
+ command:
166
+ - -disable_root_cgroup_stats=true
167
+ - -docker_only=true
168
+ - -store_container_labels=false
169
+ - -whitelisted_container_labels=com.docker.compose.project
170
+ privileged: true
171
+ volumes:
172
+ - /:/rootfs:ro
173
+ - /var/run:/var/run:ro
174
+ - /sys:/sys:ro
175
+ - /var/lib/docker:/var/lib/docker:ro
176
+ - /dev/disk/:/dev/disk:ro
177
+ ports:
178
+ - "${INFRAHUB_TESTING_CADVISOR_PORT:-0}:8080"
179
+
180
+ scraper:
181
+ image: "${SCRAPER_DOCKER_IMAGE:-victoriametrics/victoria-metrics:v1.110.0}"
182
+ volumes:
183
+ - vmdata:/victoria-metrics-data
184
+ - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
185
+ command:
186
+ - "--promscrape.config=/etc/prometheus/prometheus.yml"
187
+ ports:
188
+ - ${INFRAHUB_TESTING_SCRAPER_PORT:-0}:8428
189
+
166
190
  volumes:
167
191
  database_data:
168
192
  database_logs:
169
193
  storage_data:
170
194
  workflow_db:
195
+ vmdata:
@@ -1,5 +1,4 @@
1
1
  import os
2
- import shutil
3
2
  import subprocess # noqa: S404
4
3
  from pathlib import Path
5
4
 
@@ -15,7 +14,8 @@ class TestInfrahubDocker:
15
14
  def infrahub_version(self) -> str:
16
15
  return infrahub_version
17
16
 
18
- def execute_ctl_run(self, address: str, script: str) -> str:
17
+ @staticmethod
18
+ def execute_ctl_run(address: str, script: str) -> str:
19
19
  env = os.environ.copy()
20
20
  env["INFRAHUB_ADDRESS"] = address
21
21
  env["INFRAHUB_API_TOKEN"] = PROJECT_ENV_VARIABLES["INFRAHUB_TESTING_INITIAL_ADMIN_TOKEN"]
@@ -25,6 +25,17 @@ class TestInfrahubDocker:
25
25
  )
26
26
  return result.stdout
27
27
 
28
+ @staticmethod
29
+ def execute_command(command: str, address: str, concurrent_execution: int = 10) -> subprocess.CompletedProcess[str]:
30
+ env = os.environ.copy()
31
+ env["INFRAHUB_ADDRESS"] = address
32
+ env["INFRAHUB_API_TOKEN"] = PROJECT_ENV_VARIABLES["INFRAHUB_TESTING_INITIAL_ADMIN_TOKEN"]
33
+ env["INFRAHUB_MAX_CONCURRENT_EXECUTION"] = f"{concurrent_execution}"
34
+ result = subprocess.run( # noqa: S602
35
+ command, shell=True, capture_output=True, text=True, env=env, check=False
36
+ )
37
+ return result
38
+
28
39
  @pytest.fixture(scope="class")
29
40
  def tmp_directory(self, tmpdir_factory: pytest.TempdirFactory) -> Path:
30
41
  directory = Path(str(tmpdir_factory.getbasetemp().strpath))
@@ -65,7 +76,11 @@ class TestInfrahubDocker:
65
76
 
66
77
  request.addfinalizer(cleanup)
67
78
 
68
- infrahub_compose.start()
79
+ try:
80
+ infrahub_compose.start()
81
+ except Exception as exc:
82
+ stdout, stderr = infrahub_compose.get_logs()
83
+ raise Exception(f"Failed to start docker compose:\nStdout:\n{stdout}\nStderr:\n{stderr}") from exc
69
84
 
70
85
  return infrahub_compose.get_services_port()
71
86
 
@@ -76,73 +91,3 @@ class TestInfrahubDocker:
76
91
  @pytest.fixture(scope="class")
77
92
  def task_manager_port(self, infrahub_app: dict[str, int]) -> int:
78
93
  return infrahub_app["task-manager"]
79
-
80
- def backup_database(self, request: pytest.FixtureRequest, dest_dir: Path | None = None) -> None:
81
- assert "enterprise" in os.environ.get("NEO4J_DOCKER_IMAGE", "")
82
-
83
- backup_dir: Path = request.getfixturevalue("remote_backups_dir")
84
- infrahub_compose: InfrahubDockerCompose = request.getfixturevalue("infrahub_compose")
85
-
86
- infrahub_compose.exec_in_container(
87
- command=[
88
- "neo4j-admin",
89
- "database",
90
- "backup",
91
- "--to-path",
92
- os.environ.get(
93
- "INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY",
94
- PROJECT_ENV_VARIABLES["INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY"],
95
- ),
96
- ],
97
- service_name="database",
98
- )
99
-
100
- if dest_dir:
101
- shutil.copytree(
102
- str(backup_dir),
103
- str(dest_dir),
104
- )
105
-
106
- def restore_database(self, request: pytest.FixtureRequest, backup_file: Path) -> None:
107
- assert "enterprise" in os.environ.get("NEO4J_DOCKER_IMAGE", "")
108
-
109
- backup_dir: Path = request.getfixturevalue("remote_backups_dir")
110
- infrahub_compose: InfrahubDockerCompose = request.getfixturevalue("infrahub_compose")
111
-
112
- shutil.copy(
113
- str(backup_file),
114
- str(backup_dir / backup_file.name),
115
- )
116
-
117
- infrahub_compose.exec_in_container(
118
- command=["cypher-shell", "-u", "neo4j", "-p", "admin", "STOP DATABASE neo4j;"],
119
- service_name="database",
120
- )
121
-
122
- infrahub_compose.exec_in_container(
123
- command=[
124
- "neo4j-admin",
125
- "database",
126
- "restore",
127
- "--overwrite-destination",
128
- "--from-path",
129
- str(
130
- Path(
131
- os.environ.get(
132
- "INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY",
133
- PROJECT_ENV_VARIABLES["INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY"],
134
- )
135
- )
136
- / backup_file.name
137
- ),
138
- ],
139
- service_name="database",
140
- )
141
-
142
- infrahub_compose.exec_in_container(
143
- command=["cypher-shell", "-d", "system", "-u", "neo4j", "-p", "admin", "START DATABASE neo4j;"],
144
- service_name="database",
145
- )
146
-
147
- infrahub_compose.stop(down=False)
148
- infrahub_compose.start()
@@ -0,0 +1,41 @@
1
+ import platform
2
+ from typing import Any
3
+
4
+ import psutil
5
+
6
+
7
+ def get_system_stats() -> dict[str, Any]:
8
+ """
9
+ Gather and return key system statistics about CPU, memory and platform
10
+ Returns a dictionary with system information
11
+ """
12
+ # CPU information
13
+ cpu_freq = psutil.cpu_freq()
14
+ cpu_stats = {
15
+ "cpu_count_physical": psutil.cpu_count(logical=False),
16
+ "cpu_count_logical": psutil.cpu_count(logical=True),
17
+ "cpu_freq_current": float(f"{cpu_freq.current:.2f}") if cpu_freq else None, # MHz
18
+ "cpu_freq_min": float(f"{cpu_freq.min:.2f}") if cpu_freq else None, # MHz
19
+ "cpu_freq_max": float(f"{cpu_freq.max:.2f}") if cpu_freq else None, # MHz
20
+ "cpu_percent": psutil.cpu_percent(interval=1, percpu=False),
21
+ }
22
+
23
+ # Memory information
24
+ memory = psutil.virtual_memory()
25
+ memory_stats = {
26
+ "total_memory": float(f"{memory.total / (1024**3):.2f}"), # GB
27
+ "available_memory": float(f"{memory.available / (1024**3):.2f}"), # GB
28
+ "memory_percent_used": memory.percent,
29
+ "memory_used": float(f"{memory.used / (1024**3):.2f}"), # GB
30
+ }
31
+
32
+ # Platform information
33
+ platform_stats = {
34
+ "system": platform.system(),
35
+ "platform_release": platform.release(),
36
+ "platform_version": platform.version(),
37
+ "architecture": platform.machine(),
38
+ "processor": platform.processor(),
39
+ }
40
+
41
+ return {"cpu": cpu_stats, "memory": memory_stats, "platform": platform_stats}
@@ -0,0 +1,93 @@
1
+ from .models import ContextUnit, MeasurementDefinition
2
+
3
+ NODE_QUERY_TIME = MeasurementDefinition(
4
+ name="node_query",
5
+ description="Query some nodes",
6
+ dimensions=["kind"],
7
+ unit=ContextUnit.TIME,
8
+ )
9
+
10
+ NODE_CREATE_TIME = MeasurementDefinition(
11
+ name="node_mutation_create",
12
+ description="Create a new node",
13
+ dimensions=["kind"],
14
+ unit=ContextUnit.TIME,
15
+ )
16
+
17
+ NODE_UPDATE_TIME = MeasurementDefinition(
18
+ name="node_mutation_update",
19
+ description="Update an existing node",
20
+ dimensions=["kind"],
21
+ unit=ContextUnit.TIME,
22
+ )
23
+
24
+ NODE_DELETE_TIME = MeasurementDefinition(
25
+ name="node_mutation_delete",
26
+ description="Delete a node",
27
+ dimensions=["kind"],
28
+ unit=ContextUnit.TIME,
29
+ )
30
+
31
+ SCHEMA_INITIAL_LOAD_TIME = MeasurementDefinition(
32
+ name="schema_initial_load",
33
+ description="Load the initial schema",
34
+ dimensions=["branch"],
35
+ unit=ContextUnit.TIME,
36
+ )
37
+
38
+ SCHEMA_UPDATE_TIME = MeasurementDefinition(
39
+ name="schema_update",
40
+ description="Update the schema",
41
+ dimensions=["branch"],
42
+ unit=ContextUnit.TIME,
43
+ )
44
+
45
+ DATABASE_SIZE = MeasurementDefinition(
46
+ name="database_size",
47
+ description="Size of the database",
48
+ unit=ContextUnit.DISK,
49
+ )
50
+
51
+ DIFF_CREATE_TIME = MeasurementDefinition(
52
+ name="diff_create",
53
+ description="Create a new diff",
54
+ unit=ContextUnit.TIME,
55
+ )
56
+
57
+ DIFF_APPLY_TIME = MeasurementDefinition(
58
+ name="diff_update",
59
+ description="Update an existing diff",
60
+ unit=ContextUnit.TIME,
61
+ )
62
+
63
+ BRANCH_CREATE_TIME = MeasurementDefinition(
64
+ name="branch_create",
65
+ description="Create a new branch",
66
+ unit=ContextUnit.TIME,
67
+ )
68
+
69
+ BRANCH_MERGE_TIME = MeasurementDefinition(
70
+ name="branch_merge",
71
+ description="Merge a branch",
72
+ unit=ContextUnit.TIME,
73
+ )
74
+
75
+ BRANCH_REBASE_TIME = MeasurementDefinition(
76
+ name="branch_rebase",
77
+ description="Rebase a branch",
78
+ unit=ContextUnit.TIME,
79
+ )
80
+
81
+ SCRIPT_EXECUTION_TIME = MeasurementDefinition(
82
+ name="script_execution",
83
+ description="Execute a script",
84
+ dimensions=["name"],
85
+ unit=ContextUnit.TIME,
86
+ )
87
+
88
+ GENERATOR_EXECUTION_TIME = MeasurementDefinition(
89
+ name="generator_execution",
90
+ description="Execute a generator",
91
+ dimensions=["name"],
92
+ unit=ContextUnit.TIME,
93
+ )
@@ -0,0 +1,38 @@
1
+ from datetime import UTC, datetime
2
+ from enum import Enum
3
+ from typing import Any
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class ContextUnit(str, Enum):
9
+ COUNT = "count"
10
+ TIME = "msec" # time in milliseconds
11
+ MEMORY = "memory" # memory in bytes
12
+ DISK = "disk" # disk in bytes
13
+
14
+
15
+ class MeasurementDefinition(BaseModel):
16
+ name: str
17
+ description: str
18
+ dimensions: list[str] = Field(default_factory=dict)
19
+ unit: ContextUnit
20
+
21
+
22
+ class InfrahubResultContext(BaseModel):
23
+ name: str
24
+ value: int | float | str
25
+ unit: ContextUnit
26
+
27
+
28
+ class InfrahubActiveMeasurementItem(BaseModel):
29
+ definition: MeasurementDefinition
30
+ start_time: datetime = datetime.now(UTC)
31
+ context: dict[str, Any] = Field(default_factory=dict)
32
+
33
+
34
+ class InfrahubMeasurementItem(BaseModel):
35
+ name: str
36
+ value: int | float | str
37
+ unit: ContextUnit
38
+ context: dict[str, Any] = Field(default_factory=dict)