infrahub-server 1.3.0b1__py3-none-any.whl → 1.3.0b3__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 (81) hide show
  1. infrahub/actions/constants.py +87 -0
  2. infrahub/actions/gather.py +3 -3
  3. infrahub/actions/models.py +10 -8
  4. infrahub/actions/parsers.py +6 -6
  5. infrahub/actions/schema.py +46 -37
  6. infrahub/actions/tasks.py +4 -11
  7. infrahub/branch/__init__.py +0 -0
  8. infrahub/branch/tasks.py +29 -0
  9. infrahub/branch/triggers.py +22 -0
  10. infrahub/cli/db.py +2 -2
  11. infrahub/computed_attribute/gather.py +3 -1
  12. infrahub/computed_attribute/tasks.py +23 -29
  13. infrahub/core/constants/__init__.py +5 -0
  14. infrahub/core/constants/database.py +1 -0
  15. infrahub/core/convert_object_type/conversion.py +1 -1
  16. infrahub/core/diff/query/save.py +67 -40
  17. infrahub/core/diff/query/time_range_query.py +0 -1
  18. infrahub/core/graph/__init__.py +1 -1
  19. infrahub/core/migrations/graph/__init__.py +6 -0
  20. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +0 -2
  21. infrahub/core/migrations/graph/m029_duplicates_cleanup.py +662 -0
  22. infrahub/core/migrations/graph/m030_illegal_edges.py +82 -0
  23. infrahub/core/migrations/query/attribute_add.py +13 -9
  24. infrahub/core/migrations/query/relationship_duplicate.py +0 -1
  25. infrahub/core/migrations/schema/node_remove.py +0 -1
  26. infrahub/core/node/__init__.py +2 -0
  27. infrahub/core/node/base.py +1 -1
  28. infrahub/core/path.py +1 -1
  29. infrahub/core/protocols.py +4 -3
  30. infrahub/core/query/node.py +1 -1
  31. infrahub/core/query/relationship.py +2 -2
  32. infrahub/core/query/standard_node.py +19 -5
  33. infrahub/core/relationship/constraints/peer_relatives.py +72 -0
  34. infrahub/core/relationship/model.py +1 -1
  35. infrahub/core/schema/attribute_schema.py +26 -6
  36. infrahub/core/schema/basenode_schema.py +2 -2
  37. infrahub/core/schema/definitions/core/resource_pool.py +9 -0
  38. infrahub/core/schema/definitions/internal.py +9 -1
  39. infrahub/core/schema/generated/attribute_schema.py +4 -4
  40. infrahub/core/schema/generated/relationship_schema.py +6 -1
  41. infrahub/core/schema/manager.py +4 -2
  42. infrahub/core/schema/schema_branch.py +14 -5
  43. infrahub/core/validators/tasks.py +1 -1
  44. infrahub/database/__init__.py +1 -1
  45. infrahub/database/validation.py +100 -0
  46. infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
  47. infrahub/dependencies/builder/constraint/relationship_manager/peer_relatives.py +8 -0
  48. infrahub/dependencies/builder/diff/deserializer.py +1 -1
  49. infrahub/dependencies/registry.py +2 -0
  50. infrahub/events/models.py +1 -1
  51. infrahub/graphql/mutations/main.py +1 -1
  52. infrahub/graphql/mutations/resource_manager.py +13 -13
  53. infrahub/graphql/resolvers/many_relationship.py +1 -1
  54. infrahub/graphql/resolvers/resolver.py +2 -2
  55. infrahub/graphql/resolvers/single_relationship.py +1 -1
  56. infrahub/menu/menu.py +5 -4
  57. infrahub/message_bus/operations/refresh/registry.py +3 -3
  58. infrahub/patch/queries/delete_duplicated_edges.py +40 -29
  59. infrahub/pools/registration.py +22 -0
  60. infrahub/pools/tasks.py +56 -0
  61. infrahub/proposed_change/tasks.py +8 -8
  62. infrahub/schema/__init__.py +0 -0
  63. infrahub/schema/tasks.py +27 -0
  64. infrahub/schema/triggers.py +23 -0
  65. infrahub/trigger/catalogue.py +4 -0
  66. infrahub/trigger/models.py +5 -4
  67. infrahub/trigger/setup.py +26 -2
  68. infrahub/trigger/tasks.py +1 -1
  69. infrahub/webhook/tasks.py +6 -9
  70. infrahub/workflows/catalogue.py +27 -1
  71. {infrahub_server-1.3.0b1.dist-info → infrahub_server-1.3.0b3.dist-info}/METADATA +1 -1
  72. {infrahub_server-1.3.0b1.dist-info → infrahub_server-1.3.0b3.dist-info}/RECORD +80 -67
  73. infrahub_testcontainers/container.py +239 -64
  74. infrahub_testcontainers/docker-compose-cluster.test.yml +321 -0
  75. infrahub_testcontainers/docker-compose.test.yml +1 -0
  76. infrahub_testcontainers/helpers.py +15 -1
  77. infrahub_testcontainers/plugin.py +9 -0
  78. infrahub/patch/queries/consolidate_duplicated_nodes.py +0 -106
  79. {infrahub_server-1.3.0b1.dist-info → infrahub_server-1.3.0b3.dist-info}/LICENSE.txt +0 -0
  80. {infrahub_server-1.3.0b1.dist-info → infrahub_server-1.3.0b3.dist-info}/WHEEL +0 -0
  81. {infrahub_server-1.3.0b1.dist-info → infrahub_server-1.3.0b3.dist-info}/entry_points.txt +0 -0
@@ -59,6 +59,7 @@ services:
59
59
  NEO4J_ACCEPT_LICENSE_AGREEMENT: "yes"
60
60
  NEO4J_server_memory_heap_initial__size: ${INFRAHUB_TESTING_DB_HEAP_INITIAL_SIZE}
61
61
  NEO4J_server_memory_heap_max__size: ${INFRAHUB_TESTING_DB_HEAP_MAX_SIZE}
62
+ NEO4J_server_memory_pagecache_size: ${INFRAHUB_TESTING_DB_PAGECACHE_SIZE}
62
63
  volumes:
63
64
  - "database_data:/data"
64
65
  - "database_logs:/logs"
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import subprocess # noqa: S404
3
3
  import uuid
4
+ import warnings
4
5
  from pathlib import Path
5
6
 
6
7
  import pytest
@@ -61,6 +62,10 @@ class TestInfrahubDocker:
61
62
  def default_branch(self) -> str:
62
63
  return "main"
63
64
 
65
+ @pytest.fixture(scope="class")
66
+ def deployment_type(self, request: pytest.FixtureRequest) -> str | None:
67
+ return request.config.getoption(name="infrahub_deployment_type", default=None)
68
+
64
69
  @pytest.fixture(scope="class")
65
70
  def infrahub_compose(
66
71
  self,
@@ -68,12 +73,21 @@ class TestInfrahubDocker:
68
73
  remote_repos_dir: Path, # initialize repository before running docker compose to fix permissions issues # noqa: ARG002
69
74
  remote_backups_dir: Path, # noqa: ARG002
70
75
  infrahub_version: str,
76
+ deployment_type: str | None,
71
77
  ) -> InfrahubDockerCompose:
72
- return InfrahubDockerCompose.init(directory=tmp_directory, version=infrahub_version)
78
+ return InfrahubDockerCompose.init(
79
+ directory=tmp_directory, version=infrahub_version, deployment_type=deployment_type
80
+ )
73
81
 
74
82
  @pytest.fixture(scope="class")
75
83
  def infrahub_app(self, request: pytest.FixtureRequest, infrahub_compose: InfrahubDockerCompose) -> dict[str, int]:
84
+ tests_failed_before_class = request.session.testsfailed
85
+
76
86
  def cleanup() -> None:
87
+ tests_failed_during_class = request.session.testsfailed - tests_failed_before_class
88
+ if tests_failed_during_class > 0:
89
+ stdout, stderr = infrahub_compose.get_logs("infrahub-server", "task-worker")
90
+ warnings.warn(f"Container logs:\nStdout:\n{stdout}\nStderr:\n{stderr}", stacklevel=2)
77
91
  infrahub_compose.stop()
78
92
 
79
93
  request.addfinalizer(cleanup)
@@ -13,6 +13,15 @@ if TYPE_CHECKING:
13
13
  def pytest_addoption(parser: pytest.Parser) -> None:
14
14
  group = parser.getgroup("infrahub-performance-test")
15
15
 
16
+ group.addoption(
17
+ "--deployment-type",
18
+ action="store",
19
+ dest="infrahub_deployment_type",
20
+ default=None,
21
+ metavar="INFRAHUB_DEPLOYMENT_TYPE",
22
+ help="Type of deployment to use (default: None, options: cluster)",
23
+ )
24
+
16
25
  group.addoption(
17
26
  "--performance-result-address",
18
27
  action="store",
@@ -1,106 +0,0 @@
1
- from ..models import EdgeToAdd, EdgeToDelete, PatchPlan, VertexToDelete
2
- from .base import PatchQuery
3
-
4
-
5
- class ConsolidateDuplicatedNodesPatchQuery(PatchQuery):
6
- """
7
- Find any groups of nodes with the same labels and properties, move all the edges to one of the duplicated nodes,
8
- then delete the other duplicated nodes
9
- """
10
-
11
- @property
12
- def name(self) -> str:
13
- return "consolidate-duplicated-nodes"
14
-
15
- async def plan(self) -> PatchPlan:
16
- query = """
17
- //------------
18
- // Find nodes with the same labels and UUID
19
- //------------
20
- MATCH (n:Node)
21
- WITH n.uuid AS node_uuid, count(*) as num_nodes_with_uuid
22
- WHERE num_nodes_with_uuid > 1
23
- WITH DISTINCT node_uuid
24
- MATCH (n:Node {uuid: node_uuid})
25
- CALL (n) {
26
- WITH labels(n) AS n_labels
27
- UNWIND n_labels AS n_label
28
- WITH n_label
29
- ORDER BY n_label ASC
30
- RETURN collect(n_label) AS sorted_labels
31
- }
32
- WITH n.uuid AS n_uuid, sorted_labels, collect(n) AS duplicate_nodes
33
- WHERE size(duplicate_nodes) > 1
34
- WITH n_uuid, head(duplicate_nodes) AS node_to_keep, tail(duplicate_nodes) AS nodes_to_delete
35
- UNWIND nodes_to_delete AS node_to_delete
36
- //------------
37
- // Find the edges that we need to move to the selected node_to_keep
38
- //------------
39
- CALL (node_to_keep, node_to_delete) {
40
- MATCH (node_to_delete)-[edge_to_delete]->(peer)
41
- RETURN {
42
- from_id: %(id_func_name)s(node_to_keep),
43
- to_id: %(id_func_name)s(peer),
44
- edge_type: type(edge_to_delete),
45
- after_props: properties(edge_to_delete)
46
- } AS edge_to_create
47
- UNION
48
- WITH node_to_keep, node_to_delete
49
- MATCH (node_to_delete)<-[edge_to_delete]-(peer)
50
- RETURN {
51
- from_id: %(id_func_name)s(peer),
52
- to_id: %(id_func_name)s(node_to_keep),
53
- edge_type: type(edge_to_delete),
54
- after_props: properties(edge_to_delete)
55
- } AS edge_to_create
56
- }
57
- WITH node_to_delete, collect(edge_to_create) AS edges_to_create
58
- //------------
59
- // Find the edges that we need to remove from the duplicated nodes
60
- //------------
61
- CALL (node_to_delete) {
62
- MATCH (node_to_delete)-[e]->(peer)
63
- RETURN {
64
- db_id: %(id_func_name)s(e),
65
- from_id: %(id_func_name)s(node_to_delete),
66
- to_id: %(id_func_name)s(peer),
67
- edge_type: type(e),
68
- before_props: properties(e)
69
- } AS edge_to_delete
70
- UNION
71
- WITH node_to_delete
72
- MATCH (node_to_delete)<-[e]-(peer)
73
- RETURN {
74
- db_id: %(id_func_name)s(e),
75
- from_id: %(id_func_name)s(peer),
76
- to_id: %(id_func_name)s(node_to_delete),
77
- edge_type: type(e),
78
- before_props: properties(e)
79
- } AS edge_to_delete
80
- }
81
- WITH node_to_delete, edges_to_create, collect(edge_to_delete) AS edges_to_delete
82
- RETURN
83
- {db_id: %(id_func_name)s(node_to_delete), labels: labels(node_to_delete), before_props: properties(node_to_delete)} AS vertex_to_delete,
84
- edges_to_create,
85
- edges_to_delete
86
- """ % {"id_func_name": self.db.get_id_function_name()}
87
- results = await self.db.execute_query(query=query)
88
- vertices_to_delete: list[VertexToDelete] = []
89
- edges_to_delete: list[EdgeToDelete] = []
90
- edges_to_add: list[EdgeToAdd] = []
91
- for result in results:
92
- serial_vertex_to_delete = result.get("vertex_to_delete")
93
- if serial_vertex_to_delete:
94
- vertex_to_delete = VertexToDelete(**serial_vertex_to_delete)
95
- vertices_to_delete.append(vertex_to_delete)
96
- for serial_edge_to_delete in result.get("edges_to_delete"):
97
- edge_to_delete = EdgeToDelete(**serial_edge_to_delete)
98
- edges_to_delete.append(edge_to_delete)
99
- for serial_edge_to_create in result.get("edges_to_create"):
100
- edges_to_add.append(EdgeToAdd(**serial_edge_to_create))
101
- return PatchPlan(
102
- name=self.name,
103
- vertices_to_delete=vertices_to_delete,
104
- edges_to_add=edges_to_add,
105
- edges_to_delete=edges_to_delete,
106
- )