infrahub-server 1.1.6__py3-none-any.whl → 1.2.0rc0__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 (346) hide show
  1. infrahub/api/artifact.py +16 -4
  2. infrahub/api/dependencies.py +8 -0
  3. infrahub/api/oauth2.py +0 -1
  4. infrahub/api/oidc.py +0 -1
  5. infrahub/api/query.py +18 -7
  6. infrahub/api/schema.py +32 -6
  7. infrahub/api/transformation.py +12 -5
  8. infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +2 -4
  9. infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +26 -25
  10. infrahub/cli/__init__.py +0 -2
  11. infrahub/cli/db.py +6 -7
  12. infrahub/cli/events.py +8 -3
  13. infrahub/cli/git_agent.py +9 -7
  14. infrahub/cli/tasks.py +4 -6
  15. infrahub/computed_attribute/tasks.py +63 -17
  16. infrahub/computed_attribute/triggers.py +90 -0
  17. infrahub/config.py +1 -1
  18. infrahub/context.py +39 -0
  19. infrahub/core/account.py +5 -8
  20. infrahub/core/attribute.py +53 -21
  21. infrahub/core/branch/models.py +4 -4
  22. infrahub/core/branch/tasks.py +89 -130
  23. infrahub/core/changelog/__init__.py +0 -0
  24. infrahub/core/changelog/diff.py +232 -0
  25. infrahub/core/changelog/models.py +488 -0
  26. infrahub/core/constants/__init__.py +19 -2
  27. infrahub/core/constants/infrahubkind.py +1 -0
  28. infrahub/core/diff/combiner.py +12 -8
  29. infrahub/core/diff/coordinator.py +49 -70
  30. infrahub/core/diff/data_check_synchronizer.py +86 -7
  31. infrahub/core/diff/enricher/aggregated.py +3 -3
  32. infrahub/core/diff/enricher/cardinality_one.py +2 -7
  33. infrahub/core/diff/enricher/hierarchy.py +5 -3
  34. infrahub/core/diff/enricher/labels.py +14 -4
  35. infrahub/core/diff/enricher/path_identifier.py +3 -9
  36. infrahub/core/diff/enricher/summary_counts.py +3 -1
  37. infrahub/core/diff/merger/merger.py +8 -4
  38. infrahub/core/diff/model/path.py +47 -29
  39. infrahub/core/diff/query/all_conflicts.py +6 -3
  40. infrahub/core/diff/query/artifact.py +1 -1
  41. infrahub/core/diff/query/delete_query.py +1 -1
  42. infrahub/core/diff/query/diff_get.py +3 -2
  43. infrahub/core/diff/query/diff_summary.py +1 -1
  44. infrahub/core/diff/query/field_specifiers.py +3 -1
  45. infrahub/core/diff/query/field_summary.py +3 -2
  46. infrahub/core/diff/query/filters.py +12 -1
  47. infrahub/core/diff/query/get_conflict_query.py +1 -1
  48. infrahub/core/diff/query/has_conflicts_query.py +6 -3
  49. infrahub/core/diff/query/merge.py +3 -3
  50. infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +4 -4
  51. infrahub/core/diff/query/roots_metadata.py +9 -2
  52. infrahub/core/diff/query/save.py +151 -66
  53. infrahub/core/diff/query/summary_counts_enricher.py +220 -0
  54. infrahub/core/diff/query/time_range_query.py +3 -2
  55. infrahub/core/diff/query/update_conflict_query.py +1 -1
  56. infrahub/core/diff/query_parser.py +49 -24
  57. infrahub/core/diff/repository/deserializer.py +24 -25
  58. infrahub/core/diff/repository/repository.py +76 -20
  59. infrahub/core/diff/tasks.py +9 -8
  60. infrahub/core/enums.py +1 -1
  61. infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
  62. infrahub/core/ipam/reconciler.py +1 -1
  63. infrahub/core/ipam/tasks.py +2 -3
  64. infrahub/core/manager.py +18 -13
  65. infrahub/core/merge.py +5 -2
  66. infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
  67. infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
  68. infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
  69. infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
  70. infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
  71. infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
  72. infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
  73. infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
  74. infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
  75. infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
  76. infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
  77. infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
  78. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
  79. infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
  80. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
  81. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
  82. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
  83. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
  84. infrahub/core/migrations/query/attribute_add.py +1 -1
  85. infrahub/core/migrations/query/attribute_rename.py +1 -1
  86. infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
  87. infrahub/core/migrations/query/node_duplicate.py +1 -1
  88. infrahub/core/migrations/query/relationship_duplicate.py +1 -1
  89. infrahub/core/migrations/query/schema_attribute_update.py +1 -1
  90. infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
  91. infrahub/core/migrations/schema/node_remove.py +1 -1
  92. infrahub/core/migrations/schema/tasks.py +5 -5
  93. infrahub/core/migrations/shared.py +4 -4
  94. infrahub/core/models.py +7 -8
  95. infrahub/core/node/__init__.py +161 -40
  96. infrahub/core/node/base.py +1 -1
  97. infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
  98. infrahub/core/node/delete_validator.py +4 -4
  99. infrahub/core/node/ipam.py +13 -8
  100. infrahub/core/node/permissions.py +4 -0
  101. infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
  102. infrahub/core/node/standard.py +3 -5
  103. infrahub/core/property.py +1 -1
  104. infrahub/core/protocols.py +4 -0
  105. infrahub/core/protocols_base.py +4 -2
  106. infrahub/core/query/__init__.py +2 -5
  107. infrahub/core/query/attribute.py +9 -9
  108. infrahub/core/query/branch.py +5 -5
  109. infrahub/core/query/delete.py +1 -1
  110. infrahub/core/query/diff.py +45 -7
  111. infrahub/core/query/ipam.py +4 -4
  112. infrahub/core/query/node.py +19 -14
  113. infrahub/core/query/relationship.py +10 -11
  114. infrahub/core/query/resource_manager.py +13 -11
  115. infrahub/core/query/standard_node.py +6 -6
  116. infrahub/core/query/task.py +3 -3
  117. infrahub/core/query/task_log.py +1 -1
  118. infrahub/core/query/utils.py +5 -5
  119. infrahub/core/registry.py +0 -2
  120. infrahub/core/relationship/constraints/count.py +1 -1
  121. infrahub/core/relationship/constraints/peer_kind.py +1 -1
  122. infrahub/core/relationship/model.py +66 -26
  123. infrahub/core/schema/__init__.py +6 -4
  124. infrahub/core/schema/basenode_schema.py +1 -3
  125. infrahub/core/schema/definitions/core.py +14 -2
  126. infrahub/core/schema/definitions/internal.py +16 -0
  127. infrahub/core/schema/generated/genericnode_schema.py +5 -0
  128. infrahub/core/schema/generated/node_schema.py +5 -0
  129. infrahub/core/schema/generic_schema.py +5 -1
  130. infrahub/core/schema/manager.py +45 -42
  131. infrahub/core/schema/node_schema.py +4 -0
  132. infrahub/core/schema/profile_schema.py +4 -0
  133. infrahub/core/schema/relationship_schema.py +2 -2
  134. infrahub/core/schema/schema_branch.py +248 -14
  135. infrahub/core/schema/template_schema.py +36 -0
  136. infrahub/core/task/user_task.py +7 -5
  137. infrahub/core/timestamp.py +1 -1
  138. infrahub/core/utils.py +3 -2
  139. infrahub/core/validators/attribute/choices.py +1 -1
  140. infrahub/core/validators/attribute/enum.py +1 -1
  141. infrahub/core/validators/attribute/kind.py +1 -1
  142. infrahub/core/validators/attribute/length.py +1 -1
  143. infrahub/core/validators/attribute/optional.py +1 -1
  144. infrahub/core/validators/attribute/regex.py +1 -1
  145. infrahub/core/validators/attribute/unique.py +1 -1
  146. infrahub/core/validators/checks_runner.py +37 -0
  147. infrahub/core/validators/node/generate_profile.py +1 -1
  148. infrahub/core/validators/node/hierarchy.py +1 -1
  149. infrahub/core/validators/query.py +1 -1
  150. infrahub/core/validators/relationship/count.py +1 -1
  151. infrahub/core/validators/relationship/optional.py +1 -1
  152. infrahub/core/validators/relationship/peer.py +1 -1
  153. infrahub/core/validators/tasks.py +8 -6
  154. infrahub/core/validators/uniqueness/query.py +20 -17
  155. infrahub/database/__init__.py +15 -2
  156. infrahub/database/memgraph.py +1 -1
  157. infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
  158. infrahub/dependencies/builder/diff/combiner.py +1 -1
  159. infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
  160. infrahub/dependencies/builder/diff/coordinator.py +0 -2
  161. infrahub/dependencies/builder/diff/deserializer.py +1 -1
  162. infrahub/dependencies/builder/diff/enricher/summary_counts.py +1 -1
  163. infrahub/events/branch_action.py +47 -21
  164. infrahub/events/group_action.py +73 -0
  165. infrahub/events/models.py +159 -51
  166. infrahub/events/node_action.py +74 -8
  167. infrahub/events/repository_action.py +8 -8
  168. infrahub/events/schema_action.py +21 -8
  169. infrahub/generators/tasks.py +12 -13
  170. infrahub/git/base.py +3 -5
  171. infrahub/git/constants.py +0 -1
  172. infrahub/git/integrator.py +36 -35
  173. infrahub/git/repository.py +7 -8
  174. infrahub/git/tasks.py +43 -107
  175. infrahub/git_credential/helper.py +2 -3
  176. infrahub/graphql/analyzer.py +572 -11
  177. infrahub/graphql/app.py +34 -26
  178. infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
  179. infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
  180. infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
  181. infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
  182. infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
  183. infrahub/graphql/enums.py +1 -1
  184. infrahub/graphql/initialization.py +5 -1
  185. infrahub/graphql/loaders/node.py +2 -2
  186. infrahub/graphql/manager.py +59 -54
  187. infrahub/graphql/mutations/account.py +20 -13
  188. infrahub/graphql/mutations/artifact_definition.py +16 -12
  189. infrahub/graphql/mutations/branch.py +61 -40
  190. infrahub/graphql/mutations/computed_attribute.py +19 -13
  191. infrahub/graphql/mutations/diff.py +37 -9
  192. infrahub/graphql/mutations/diff_conflict.py +9 -8
  193. infrahub/graphql/mutations/graphql_query.py +19 -11
  194. infrahub/graphql/mutations/ipam.py +21 -19
  195. infrahub/graphql/mutations/main.py +197 -44
  196. infrahub/graphql/mutations/menu.py +8 -8
  197. infrahub/graphql/mutations/proposed_change.py +36 -28
  198. infrahub/graphql/mutations/relationship.py +302 -105
  199. infrahub/graphql/mutations/repository.py +41 -35
  200. infrahub/graphql/mutations/resource_manager.py +26 -26
  201. infrahub/graphql/mutations/schema.py +51 -33
  202. infrahub/graphql/mutations/tasks.py +16 -10
  203. infrahub/graphql/parser.py +1 -1
  204. infrahub/graphql/permissions.py +6 -4
  205. infrahub/graphql/queries/account.py +22 -18
  206. infrahub/graphql/queries/branch.py +6 -4
  207. infrahub/graphql/queries/diff/tree.py +48 -42
  208. infrahub/graphql/queries/event.py +112 -0
  209. infrahub/graphql/queries/internal.py +3 -3
  210. infrahub/graphql/queries/ipam.py +23 -18
  211. infrahub/graphql/queries/relationship.py +11 -10
  212. infrahub/graphql/queries/resource_manager.py +43 -27
  213. infrahub/graphql/queries/search.py +9 -8
  214. infrahub/graphql/queries/status.py +12 -9
  215. infrahub/graphql/queries/task.py +11 -9
  216. infrahub/graphql/resolvers/resolver.py +69 -43
  217. infrahub/graphql/resolvers/single_relationship.py +16 -10
  218. infrahub/graphql/schema.py +2 -0
  219. infrahub/graphql/subscription/__init__.py +1 -1
  220. infrahub/graphql/subscription/events.py +1 -1
  221. infrahub/graphql/subscription/graphql_query.py +8 -8
  222. infrahub/graphql/types/branch.py +2 -2
  223. infrahub/graphql/types/common.py +6 -1
  224. infrahub/graphql/types/enums.py +2 -0
  225. infrahub/graphql/types/event.py +100 -0
  226. infrahub/graphql/types/interface.py +2 -2
  227. infrahub/graphql/types/node.py +3 -3
  228. infrahub/graphql/types/permission.py +2 -2
  229. infrahub/graphql/types/relationship.py +3 -3
  230. infrahub/graphql/types/standard_node.py +9 -11
  231. infrahub/graphql/utils.py +28 -182
  232. infrahub/groups/tasks.py +2 -3
  233. infrahub/lock.py +1 -1
  234. infrahub/menu/constants.py +1 -0
  235. infrahub/menu/generator.py +14 -3
  236. infrahub/menu/menu.py +116 -127
  237. infrahub/menu/models.py +4 -4
  238. infrahub/message_bus/messages/__init__.py +0 -4
  239. infrahub/message_bus/messages/event_branch_merge.py +3 -0
  240. infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
  241. infrahub/message_bus/operations/__init__.py +3 -5
  242. infrahub/message_bus/operations/check/__init__.py +2 -2
  243. infrahub/message_bus/operations/check/generator.py +1 -3
  244. infrahub/message_bus/operations/check/repository.py +1 -1
  245. infrahub/message_bus/operations/event/branch.py +7 -3
  246. infrahub/message_bus/operations/event/schema.py +1 -1
  247. infrahub/message_bus/operations/finalize/validator.py +1 -1
  248. infrahub/message_bus/operations/git/file.py +2 -2
  249. infrahub/message_bus/operations/git/repository.py +1 -1
  250. infrahub/message_bus/operations/requests/__init__.py +0 -2
  251. infrahub/message_bus/operations/requests/generator_definition.py +1 -1
  252. infrahub/message_bus/operations/requests/proposed_change.py +26 -11
  253. infrahub/message_bus/operations/requests/repository.py +2 -2
  254. infrahub/message_bus/operations/send/echo.py +1 -1
  255. infrahub/message_bus/types.py +1 -1
  256. infrahub/permissions/__init__.py +2 -1
  257. infrahub/permissions/types.py +26 -0
  258. infrahub/pools/prefix.py +29 -165
  259. infrahub/prefect_server/__init__.py +0 -0
  260. infrahub/prefect_server/app.py +18 -0
  261. infrahub/prefect_server/database.py +20 -0
  262. infrahub/prefect_server/events.py +28 -0
  263. infrahub/prefect_server/models.py +46 -0
  264. infrahub/proposed_change/models.py +15 -1
  265. infrahub/proposed_change/tasks.py +173 -35
  266. infrahub/pytest_plugin.py +4 -4
  267. infrahub/server.py +12 -11
  268. infrahub/services/__init__.py +147 -62
  269. infrahub/services/adapters/cache/__init__.py +7 -5
  270. infrahub/services/adapters/cache/nats.py +40 -22
  271. infrahub/services/adapters/cache/redis.py +0 -4
  272. infrahub/services/adapters/event/__init__.py +10 -18
  273. infrahub/services/adapters/http/__init__.py +0 -5
  274. infrahub/services/adapters/http/httpx.py +22 -15
  275. infrahub/services/adapters/message_bus/__init__.py +23 -6
  276. infrahub/services/adapters/message_bus/local.py +8 -6
  277. infrahub/services/adapters/message_bus/nats.py +12 -6
  278. infrahub/services/adapters/message_bus/rabbitmq.py +22 -9
  279. infrahub/services/adapters/workflow/__init__.py +11 -8
  280. infrahub/services/adapters/workflow/local.py +28 -7
  281. infrahub/services/adapters/workflow/worker.py +23 -7
  282. infrahub/services/component.py +38 -35
  283. infrahub/services/scheduler.py +32 -29
  284. infrahub/storage.py +2 -4
  285. infrahub/task_manager/constants.py +1 -1
  286. infrahub/task_manager/event.py +182 -0
  287. infrahub/task_manager/models.py +125 -1
  288. infrahub/task_manager/task.py +1 -1
  289. infrahub/tasks/artifact.py +14 -16
  290. infrahub/tasks/registry.py +1 -1
  291. infrahub/tasks/telemetry.py +13 -14
  292. infrahub/transformations/tasks.py +3 -5
  293. infrahub/trigger/__init__.py +0 -0
  294. infrahub/trigger/catalogue.py +15 -0
  295. infrahub/trigger/constants.py +9 -0
  296. infrahub/trigger/models.py +69 -0
  297. infrahub/trigger/tasks.py +85 -0
  298. infrahub/types.py +1 -1
  299. infrahub/utils.py +1 -1
  300. infrahub/webhook/constants.py +0 -2
  301. infrahub/webhook/models.py +8 -2
  302. infrahub/webhook/tasks.py +20 -73
  303. infrahub/webhook/triggers.py +20 -0
  304. infrahub/workers/infrahub_async.py +36 -25
  305. infrahub/workers/utils.py +63 -0
  306. infrahub/workflows/catalogue.py +13 -37
  307. infrahub/workflows/initialization.py +6 -8
  308. infrahub/workflows/models.py +3 -5
  309. infrahub/workflows/utils.py +1 -1
  310. infrahub_sdk/ctl/check.py +3 -3
  311. infrahub_sdk/ctl/cli_commands.py +11 -10
  312. infrahub_sdk/ctl/exceptions.py +0 -6
  313. infrahub_sdk/ctl/exporter.py +1 -1
  314. infrahub_sdk/ctl/generator.py +5 -5
  315. infrahub_sdk/ctl/importer.py +3 -2
  316. infrahub_sdk/ctl/menu.py +1 -1
  317. infrahub_sdk/ctl/object.py +1 -1
  318. infrahub_sdk/ctl/repository.py +23 -15
  319. infrahub_sdk/ctl/schema.py +2 -2
  320. infrahub_sdk/ctl/utils.py +4 -3
  321. infrahub_sdk/ctl/validate.py +2 -1
  322. infrahub_sdk/exceptions.py +6 -0
  323. infrahub_sdk/generator.py +3 -0
  324. infrahub_sdk/node.py +2 -2
  325. infrahub_sdk/schema/__init__.py +14 -2
  326. infrahub_sdk/schema/main.py +7 -0
  327. infrahub_sdk/utils.py +11 -1
  328. infrahub_sdk/yaml.py +2 -3
  329. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/METADATA +46 -12
  330. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/RECORD +338 -321
  331. infrahub_testcontainers/container.py +14 -6
  332. infrahub_testcontainers/docker-compose.test.yml +24 -5
  333. infrahub_testcontainers/haproxy.cfg +43 -0
  334. infrahub_testcontainers/helpers.py +85 -1
  335. infrahub/core/branch/constants.py +0 -2
  336. infrahub/graphql/query.py +0 -52
  337. infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
  338. infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
  339. infrahub/schema/constants.py +0 -1
  340. infrahub/schema/tasks.py +0 -76
  341. infrahub/services/adapters/database/__init__.py +0 -9
  342. infrahub_sdk/ctl/_file.py +0 -13
  343. /infrahub/{schema → artifacts}/__init__.py +0 -0
  344. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/LICENSE.txt +0 -0
  345. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/WHEEL +0 -0
  346. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/entry_points.txt +0 -0
@@ -3,7 +3,6 @@ import uuid
3
3
  from dataclasses import dataclass
4
4
  from functools import cached_property
5
5
  from pathlib import Path
6
- from typing import Optional
7
6
 
8
7
  from testcontainers.compose import DockerCompose
9
8
  from typing_extensions import Self
@@ -18,7 +17,7 @@ class ContainerService:
18
17
 
19
18
 
20
19
  INFRAHUB_SERVICES: dict[str, ContainerService] = {
21
- "server": ContainerService(container="infrahub-server", port=8000),
20
+ "server": ContainerService(container="infrahub-server-lb", port=8000),
22
21
  "task-manager": ContainerService(container="task-manager", port=4200),
23
22
  }
24
23
 
@@ -33,8 +32,8 @@ PROJECT_ENV_VARIABLES: dict[str, str] = {
33
32
  "INFRAHUB_TESTING_INITIAL_ADMIN_TOKEN": "06438eb2-8019-4776-878c-0941b1f1d1ec",
34
33
  "INFRAHUB_TESTING_INITIAL_AGENT_TOKEN": "44af444d-3b26-410d-9546-b758657e026c",
35
34
  "INFRAHUB_TESTING_SECURITY_SECRET_KEY": "327f747f-efac-42be-9e73-999f08f86b92",
36
- "INFRAHUB_TESTING_ADDRESS": "http://infrahub-server:8000",
37
- "INFRAHUB_TESTING_INTERNAL_ADDRESS": "http://infrahub-server:8000",
35
+ "INFRAHUB_TESTING_ADDRESS": "http://infrahub-server-lb:8000",
36
+ "INFRAHUB_TESTING_INTERNAL_ADDRESS": "http://infrahub-server-lb:8000",
38
37
  "INFRAHUB_TESTING_BROKER_ADDRESS": "message-queue",
39
38
  "INFRAHUB_TESTING_CACHE_ADDRESS": "cache",
40
39
  "INFRAHUB_TESTING_WORKFLOW_ADDRESS": "task-manager",
@@ -43,15 +42,19 @@ PROJECT_ENV_VARIABLES: dict[str, str] = {
43
42
  "INFRAHUB_TESTING_LOCAL_REMOTE_GIT_DIRECTORY": "repos",
44
43
  "INFRAHUB_TESTING_INTERNAL_REMOTE_GIT_DIRECTORY": "/remote",
45
44
  "INFRAHUB_TESTING_WEB_CONCURRENCY": "4",
45
+ "INFRAHUB_TESTING_LOCAL_DB_BACKUP_DIRECTORY": "backups",
46
+ "INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY": "/backups",
47
+ "INFRAHUB_TESTING_API_SERVER_COUNT": "2",
48
+ "INFRAHUB_TESTING_TASK_WORKER_COUNT": "2",
46
49
  }
47
50
 
48
51
 
49
52
  @dataclass
50
53
  class InfrahubDockerCompose(DockerCompose):
51
- project_name: Optional[str] = None
54
+ project_name: str | None = None
52
55
 
53
56
  @classmethod
54
- def init(cls, directory: Optional[Path] = None, version: Optional[str] = None) -> Self:
57
+ def init(cls, directory: Path | None = None, version: str | None = None) -> Self:
55
58
  if not directory:
56
59
  directory = Path.cwd()
57
60
 
@@ -80,6 +83,11 @@ class InfrahubDockerCompose(DockerCompose):
80
83
  test_compose_file = directory / "docker-compose.yml"
81
84
  test_compose_file.write_bytes(compose_file.read_bytes())
82
85
 
86
+ haproxy_config_file = current_directory / "haproxy.cfg"
87
+
88
+ test_haproxy_config_file = directory / "haproxy.cfg"
89
+ test_haproxy_config_file.write_bytes(haproxy_config_file.read_bytes())
90
+
83
91
  return test_compose_file
84
92
 
85
93
  @classmethod
@@ -28,6 +28,22 @@ services:
28
28
  timeout: 5s
29
29
  retries: 3
30
30
 
31
+ infrahub-server-lb:
32
+ image: haproxy:3.1-alpine
33
+ volumes:
34
+ - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
35
+ depends_on:
36
+ infrahub-server:
37
+ condition: service_started
38
+ healthcheck:
39
+ test: wget -O /dev/null http://127.0.0.1:8000/api/config || exit 1
40
+ interval: 5s
41
+ timeout: 5s
42
+ retries: 20
43
+ start_period: 10s
44
+ ports:
45
+ - ${INFRAHUB_TESTING_SERVER_PORT:-0}:8000
46
+
31
47
  database:
32
48
  image: ${NEO4J_DOCKER_IMAGE:-neo4j:5.20.0-community}
33
49
  restart: unless-stopped
@@ -35,9 +51,11 @@ services:
35
51
  NEO4J_AUTH: neo4j/admin
36
52
  NEO4J_dbms_security_procedures_unrestricted: "apoc.*"
37
53
  NEO4J_dbms_security_auth__minimum__password__length: 4
54
+ NEO4J_ACCEPT_LICENSE_AGREEMENT: "yes"
38
55
  volumes:
39
56
  - "database_data:/data"
40
57
  - "database_logs:/logs"
58
+ - "./${INFRAHUB_TESTING_LOCAL_DB_BACKUP_DIRECTORY}:${INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY}"
41
59
  healthcheck:
42
60
  test: wget http://localhost:7474 || exit 1
43
61
  interval: 2s
@@ -49,8 +67,8 @@ services:
49
67
  - ${INFRAHUB_TESTING_DATABASE_UI_PORT:-0}:7474
50
68
 
51
69
  task-manager:
52
- image: "${TASK_MANAGER_DOCKER_IMAGE:-prefecthq/prefect:3.0.11-python3.12}"
53
- command: prefect server start --host 0.0.0.0 --ui
70
+ image: "${INFRAHUB_TESTING_DOCKER_IMAGE}:${INFRAHUB_TESTING_IMAGE_VERSION}"
71
+ command: uvicorn --host 0.0.0.0 --port 4200 --factory infrahub.prefect_server.app:create_infrahub_prefect
54
72
  depends_on:
55
73
  task-manager-db:
56
74
  condition: service_healthy
@@ -80,6 +98,9 @@ services:
80
98
  retries: 5
81
99
 
82
100
  infrahub-server:
101
+ deploy:
102
+ mode: replicated
103
+ replicas: ${INFRAHUB_TESTING_API_SERVER_COUNT}
83
104
  image: "${INFRAHUB_TESTING_DOCKER_IMAGE}:${INFRAHUB_TESTING_IMAGE_VERSION}"
84
105
  command: >
85
106
  gunicorn --config backend/infrahub/serve/gunicorn_config.py
@@ -106,8 +127,6 @@ services:
106
127
  condition: service_healthy
107
128
  task-manager:
108
129
  condition: service_healthy
109
- ports:
110
- - ${INFRAHUB_TESTING_SERVER_PORT:-0}:8000
111
130
  volumes:
112
131
  - "storage_data:/opt/infrahub/storage"
113
132
  tty: true
@@ -121,7 +140,7 @@ services:
121
140
  task-worker:
122
141
  deploy:
123
142
  mode: replicated
124
- replicas: 2
143
+ replicas: ${INFRAHUB_TESTING_TASK_WORKER_COUNT}
125
144
  image: "${INFRAHUB_TESTING_DOCKER_IMAGE}:${INFRAHUB_TESTING_IMAGE_VERSION}"
126
145
  command: prefect worker start --type infrahubasync --pool infrahub-worker --with-healthcheck
127
146
  environment:
@@ -0,0 +1,43 @@
1
+ global
2
+ log stdout local0
3
+ log stdout local1 notice
4
+ #chroot /var/lib/haproxy
5
+ #stats socket /run/haproxy/admin.sock mode 660 level admin
6
+ stats timeout 30s
7
+ user haproxy
8
+ group haproxy
9
+ daemon
10
+
11
+ # Default SSL material locations
12
+ ca-base /etc/ssl/certs
13
+ crt-base /etc/ssl/private
14
+
15
+ # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
16
+ ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
17
+ ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
18
+ ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
19
+
20
+ defaults
21
+ log global
22
+ mode http
23
+ option httplog
24
+ option dontlognull
25
+ timeout connect 5000
26
+ timeout client 50000
27
+ timeout server 50000
28
+
29
+ resolvers docker
30
+ parse-resolv-conf
31
+ accepted_payload_size 8192
32
+
33
+ frontend fe
34
+ mode http
35
+ bind *:8000
36
+ option forwardfor
37
+
38
+ default_backend be
39
+
40
+ backend be
41
+ mode http
42
+ balance roundrobin
43
+ server-template api 100 infrahub-server:8000 check resolvers docker init-addr none
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import shutil
2
3
  import subprocess # noqa: S404
3
4
  from pathlib import Path
4
5
 
@@ -36,12 +37,25 @@ class TestInfrahubDocker:
36
37
 
37
38
  return directory
38
39
 
40
+ @pytest.fixture(scope="class")
41
+ def remote_backups_dir(self, tmp_directory: Path) -> Path:
42
+ directory = tmp_directory / PROJECT_ENV_VARIABLES["INFRAHUB_TESTING_LOCAL_DB_BACKUP_DIRECTORY"]
43
+ directory.mkdir(exist_ok=True)
44
+
45
+ return directory
46
+
39
47
  @pytest.fixture(scope="class")
40
48
  def default_branch(self) -> str:
41
49
  return "main"
42
50
 
43
51
  @pytest.fixture(scope="class")
44
- def infrahub_compose(self, tmp_directory: Path, infrahub_version: str) -> InfrahubDockerCompose:
52
+ def infrahub_compose(
53
+ self,
54
+ tmp_directory: Path,
55
+ remote_repos_dir: Path, # initialize repository before running docker compose to fix permissions issues # noqa: ARG002
56
+ remote_backups_dir: Path, # noqa: ARG002
57
+ infrahub_version: str,
58
+ ) -> InfrahubDockerCompose:
45
59
  return InfrahubDockerCompose.init(directory=tmp_directory, version=infrahub_version)
46
60
 
47
61
  @pytest.fixture(scope="class")
@@ -62,3 +76,73 @@ class TestInfrahubDocker:
62
76
  @pytest.fixture(scope="class")
63
77
  def task_manager_port(self, infrahub_app: dict[str, int]) -> int:
64
78
  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()
@@ -1,2 +0,0 @@
1
- AUTOMATION_NAME_CREATE = "Trigger-branch-create-events"
2
- AUTOMATION_NAME_REMOVE = "Trigger-branch-remove-events"
infrahub/graphql/query.py DELETED
@@ -1,52 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING, Optional
4
-
5
- from graphql import graphql
6
-
7
- from infrahub.core.branch import Branch
8
- from infrahub.core.constants import InfrahubKind
9
- from infrahub.core.manager import NodeManager
10
- from infrahub.core.protocols import CoreGraphQLQuery
11
- from infrahub.core.registry import registry
12
- from infrahub.core.timestamp import Timestamp
13
- from infrahub.graphql.initialization import prepare_graphql_params
14
-
15
- if TYPE_CHECKING:
16
- from graphql.execution import ExecutionResult
17
-
18
- from infrahub.database import InfrahubDatabase
19
-
20
-
21
- async def execute_query(
22
- name: str,
23
- db: InfrahubDatabase,
24
- params: Optional[dict] = None,
25
- branch: Branch | str | None = None,
26
- at: Timestamp | str | None = None,
27
- ) -> ExecutionResult:
28
- """Helper function to Execute a GraphQL Query."""
29
-
30
- if not isinstance(branch, Branch):
31
- branch = await registry.get_branch(db=db, branch=branch)
32
- at = Timestamp(at)
33
-
34
- graphql_query = await NodeManager.get_one_by_default_filter(
35
- db=db, id=name, kind=CoreGraphQLQuery, branch=branch, at=at
36
- )
37
- if not graphql_query:
38
- raise ValueError(f"Unable to find the {InfrahubKind.GRAPHQLQUERY} {name}")
39
-
40
- gql_params = await prepare_graphql_params(
41
- branch=branch, db=db, at=at, include_mutation=False, include_subscription=False
42
- )
43
-
44
- result = await graphql(
45
- schema=gql_params.schema,
46
- source=graphql_query.query.value,
47
- context_value=gql_params.context,
48
- root_value=None,
49
- variable_values=params or {},
50
- )
51
-
52
- return result
@@ -1,17 +0,0 @@
1
- from pydantic import ConfigDict, Field
2
-
3
- from infrahub.message_bus import InfrahubMessage
4
- from infrahub.message_bus.types import ProposedChangeArtifactDefinition, ProposedChangeBranchDiff
5
-
6
-
7
- class RequestArtifactDefinitionCheck(InfrahubMessage):
8
- """Sent to validate the generation of artifacts in relation to a proposed change."""
9
-
10
- model_config = ConfigDict(arbitrary_types_allowed=True)
11
-
12
- artifact_definition: ProposedChangeArtifactDefinition = Field(..., description="The Artifact Definition")
13
- branch_diff: ProposedChangeBranchDiff = Field(..., description="The calculated diff between the two branches")
14
- proposed_change: str = Field(..., description="The unique ID of the Proposed Change")
15
- source_branch: str = Field(..., description="The source branch")
16
- source_branch_sync_with_git: bool = Field(..., description="Indicates if the source branch should sync with git")
17
- destination_branch: str = Field(..., description="The target branch")
@@ -1,148 +0,0 @@
1
- from typing import Optional
2
-
3
- from infrahub_sdk.uuidt import UUIDT
4
- from prefect import flow
5
- from prefect.logging import get_run_logger
6
-
7
- from infrahub.core.constants import InfrahubKind, ValidatorConclusion, ValidatorState
8
- from infrahub.core.timestamp import Timestamp
9
- from infrahub.message_bus import InfrahubMessage, Meta, messages
10
- from infrahub.message_bus.types import KVTTL
11
- from infrahub.services import InfrahubServices
12
- from infrahub.workflows.utils import add_tags
13
-
14
-
15
- @flow(
16
- name="artifact-definition-check",
17
- flow_run_name="Validating generation of artifacts for {message.artifact_definition.definition_name}",
18
- )
19
- async def check(message: messages.RequestArtifactDefinitionCheck, service: InfrahubServices) -> None:
20
- events: list[InfrahubMessage] = []
21
- await add_tags(branches=[message.source_branch], nodes=[message.proposed_change], db_change=True)
22
-
23
- log = get_run_logger()
24
- artifact_definition = await service.client.get(
25
- kind=InfrahubKind.ARTIFACTDEFINITION,
26
- id=message.artifact_definition.definition_id,
27
- branch=message.source_branch,
28
- )
29
- proposed_change = await service.client.get(kind=InfrahubKind.PROPOSEDCHANGE, id=message.proposed_change)
30
-
31
- validator_name = f"Artifact Validator: {message.artifact_definition.definition_name}"
32
- validator_execution_id = str(UUIDT())
33
- check_execution_ids: list[str] = []
34
-
35
- await proposed_change.validations.fetch()
36
-
37
- validator = None
38
- for relationship in proposed_change.validations.peers:
39
- existing_validator = relationship.peer
40
- if (
41
- existing_validator.typename == InfrahubKind.ARTIFACTVALIDATOR
42
- and existing_validator.definition.id == message.artifact_definition.definition_id
43
- ):
44
- validator = existing_validator
45
-
46
- if validator:
47
- validator.conclusion.value = ValidatorConclusion.UNKNOWN.value
48
- validator.state.value = ValidatorState.QUEUED.value
49
- validator.started_at.value = ""
50
- validator.completed_at.value = ""
51
- await validator.save()
52
- else:
53
- validator = await service.client.create(
54
- kind=InfrahubKind.ARTIFACTVALIDATOR,
55
- data={
56
- "label": validator_name,
57
- "proposed_change": message.proposed_change,
58
- "definition": message.artifact_definition.definition_id,
59
- },
60
- )
61
- await validator.save()
62
-
63
- await artifact_definition.targets.fetch()
64
- group = artifact_definition.targets.peer
65
- await group.members.fetch()
66
-
67
- existing_artifacts = await service.client.filters(
68
- kind=InfrahubKind.ARTIFACT,
69
- definition__ids=[message.artifact_definition.definition_id],
70
- include=["object"],
71
- branch=message.source_branch,
72
- )
73
- artifacts_by_member = {}
74
- for artifact in existing_artifacts:
75
- artifacts_by_member[artifact.object.peer.id] = artifact.id
76
-
77
- repository = message.branch_diff.get_repository(repository_id=message.artifact_definition.repository_id)
78
- requested_artifacts = 0
79
- impacted_artifacts = message.branch_diff.get_subscribers_ids(kind=InfrahubKind.ARTIFACT)
80
- for relationship in group.members.peers:
81
- member = relationship.peer
82
- artifact_id = artifacts_by_member.get(member.id)
83
- if _render_artifact(
84
- artifact_id=artifact_id,
85
- managed_branch=message.source_branch_sync_with_git,
86
- impacted_artifacts=impacted_artifacts,
87
- ):
88
- check_execution_id = str(UUIDT())
89
- check_execution_ids.append(check_execution_id)
90
- requested_artifacts += 1
91
- log.info(f"Trigger Artifact processing for {member.display_label}")
92
- events.append(
93
- messages.CheckArtifactCreate(
94
- artifact_name=message.artifact_definition.artifact_name,
95
- artifact_id=artifact_id,
96
- artifact_definition=message.artifact_definition.definition_id,
97
- commit=repository.source_commit,
98
- content_type=message.artifact_definition.content_type,
99
- transform_type=message.artifact_definition.transform_kind,
100
- transform_location=message.artifact_definition.transform_location,
101
- repository_id=repository.repository_id,
102
- repository_name=repository.repository_name,
103
- repository_kind=repository.kind,
104
- branch_name=message.source_branch,
105
- query=message.artifact_definition.query_name,
106
- variables=member.extract(params=artifact_definition.parameters.value),
107
- target_id=member.id,
108
- target_name=member.display_label,
109
- timeout=message.artifact_definition.timeout,
110
- validator_id=validator.id,
111
- meta=Meta(validator_execution_id=validator_execution_id, check_execution_id=check_execution_id),
112
- )
113
- )
114
-
115
- checks_in_execution = ",".join(check_execution_ids)
116
- await service.cache.set(
117
- key=f"validator_execution_id:{validator_execution_id}:checks",
118
- value=checks_in_execution,
119
- expires=KVTTL.TWO_HOURS,
120
- )
121
- events.append(
122
- messages.FinalizeValidatorExecution(
123
- start_time=Timestamp().to_string(),
124
- validator_id=validator.id,
125
- validator_execution_id=validator_execution_id,
126
- validator_type=InfrahubKind.ARTIFACTVALIDATOR,
127
- )
128
- )
129
- for event in events:
130
- event.assign_meta(parent=message)
131
- await service.send(message=event)
132
-
133
-
134
- def _render_artifact(artifact_id: Optional[str], managed_branch: bool, impacted_artifacts: list[str]) -> bool: # pylint: disable=unused-argument
135
- """Returns a boolean to indicate if an artifact should be generated or not.
136
- Will return true if:
137
- * The artifact_id wasn't set which could be that it's a new object that doesn't have a previous artifact
138
- * The source brance is not data only which would indicate that it could contain updates in git to the transform
139
- * The artifact_id exists in the impacted_artifacts list
140
- Will return false if:
141
- * The source branch is a data only branch and the artifact_id exists and is not in the impacted list
142
- """
143
-
144
- # if not artifact_id or managed_branch:
145
- # return True
146
- # return artifact_id in impacted_artifacts
147
- # Temporary workaround tracked in https://github.com/opsmill/infrahub/issues/4991
148
- return True
@@ -1 +0,0 @@
1
- AUTOMATION_NAME = "Trigger-schema-update-event"
infrahub/schema/tasks.py DELETED
@@ -1,76 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from datetime import timedelta
4
-
5
- from prefect import flow
6
- from prefect.automations import AutomationCore
7
- from prefect.client.orchestration import get_client
8
- from prefect.client.schemas.filters import DeploymentFilter, DeploymentFilterName
9
- from prefect.events.actions import RunDeployment
10
- from prefect.events.schemas.automations import EventTrigger, Posture
11
- from prefect.logging import get_run_logger
12
-
13
- from infrahub.workflows.catalogue import COMPUTED_ATTRIBUTE_SETUP, COMPUTED_ATTRIBUTE_SETUP_PYTHON
14
-
15
- from .constants import AUTOMATION_NAME
16
-
17
-
18
- @flow(name="schema-updated-setup", flow_run_name="Setup schema updated event in task-manager")
19
- async def schema_updated_setup() -> None:
20
- log = get_run_logger()
21
-
22
- async with get_client(sync_client=False) as client:
23
- deployments = {
24
- item.name: item
25
- for item in await client.read_deployments(
26
- deployment_filter=DeploymentFilter(
27
- name=DeploymentFilterName(
28
- any_=[COMPUTED_ATTRIBUTE_SETUP.name, COMPUTED_ATTRIBUTE_SETUP_PYTHON.name]
29
- )
30
- )
31
- )
32
- }
33
- if COMPUTED_ATTRIBUTE_SETUP.name not in deployments:
34
- raise ValueError("Unable to find the deployment for PROCESS_COMPUTED_MACRO")
35
-
36
- deployment_id_computed_attribute_setup = deployments[COMPUTED_ATTRIBUTE_SETUP.name].id
37
- deployment_id_computed_attribute_setup_python = deployments[COMPUTED_ATTRIBUTE_SETUP_PYTHON.name].id
38
-
39
- schema_update_automation = await client.find_automation(id_or_name=AUTOMATION_NAME)
40
-
41
- automation = AutomationCore(
42
- name=AUTOMATION_NAME,
43
- description="Trigger actions on schema update event",
44
- enabled=True,
45
- trigger=EventTrigger(
46
- posture=Posture.Reactive,
47
- expect={"infrahub.schema.update"},
48
- within=timedelta(0),
49
- threshold=1,
50
- ),
51
- actions=[
52
- RunDeployment(
53
- source="selected",
54
- deployment_id=deployment_id_computed_attribute_setup,
55
- parameters={
56
- "branch_name": "{{ event.resource['infrahub.branch.name'] }}",
57
- },
58
- job_variables={},
59
- ),
60
- RunDeployment(
61
- source="selected",
62
- deployment_id=deployment_id_computed_attribute_setup_python,
63
- parameters={
64
- "branch_name": "{{ event.resource['infrahub.branch.name'] }}",
65
- },
66
- job_variables={},
67
- ),
68
- ],
69
- )
70
-
71
- if schema_update_automation:
72
- await client.update_automation(automation_id=schema_update_automation.id, automation=automation)
73
- log.info(f"{AUTOMATION_NAME} Updated")
74
- else:
75
- await client.create_automation(automation=automation)
76
- log.info(f"{AUTOMATION_NAME} Created")
@@ -1,9 +0,0 @@
1
- from neo4j import AsyncSession
2
-
3
-
4
- class InfrahubDatabase:
5
- """Base class for database access"""
6
-
7
- @property
8
- def session(self) -> AsyncSession:
9
- raise NotImplementedError()
infrahub_sdk/ctl/_file.py DELETED
@@ -1,13 +0,0 @@
1
- from pathlib import Path
2
-
3
- from .exceptions import FileNotValidError
4
-
5
-
6
- def read_file(file_name: Path) -> str:
7
- if not file_name.is_file():
8
- raise FileNotValidError(name=str(file_name), message=f"{file_name} is not a valid file")
9
- try:
10
- with Path.open(file_name, encoding="utf-8") as fobj:
11
- return fobj.read()
12
- except UnicodeDecodeError as exc:
13
- raise FileNotValidError(name=str(file_name), message=f"Unable to read {file_name} with utf-8 encoding") from exc
File without changes