infrahub-server 1.1.5__py3-none-any.whl → 1.1.7__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 (66) hide show
  1. infrahub/api/oidc.py +1 -0
  2. infrahub/core/attribute.py +4 -1
  3. infrahub/core/branch/tasks.py +7 -4
  4. infrahub/core/diff/calculator.py +21 -39
  5. infrahub/core/diff/combiner.py +11 -7
  6. infrahub/core/diff/coordinator.py +49 -70
  7. infrahub/core/diff/data_check_synchronizer.py +86 -7
  8. infrahub/core/diff/enricher/aggregated.py +3 -3
  9. infrahub/core/diff/enricher/cardinality_one.py +1 -6
  10. infrahub/core/diff/enricher/labels.py +13 -3
  11. infrahub/core/diff/enricher/path_identifier.py +2 -8
  12. infrahub/core/diff/ipam_diff_parser.py +1 -1
  13. infrahub/core/diff/merger/merger.py +5 -3
  14. infrahub/core/diff/merger/serializer.py +15 -8
  15. infrahub/core/diff/model/path.py +42 -24
  16. infrahub/core/diff/query/all_conflicts.py +5 -2
  17. infrahub/core/diff/query/diff_get.py +19 -23
  18. infrahub/core/diff/query/field_specifiers.py +2 -0
  19. infrahub/core/diff/query/field_summary.py +2 -1
  20. infrahub/core/diff/query/filters.py +12 -1
  21. infrahub/core/diff/query/has_conflicts_query.py +5 -2
  22. infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +3 -3
  23. infrahub/core/diff/query/roots_metadata.py +8 -1
  24. infrahub/core/diff/query/save.py +148 -63
  25. infrahub/core/diff/query/summary_counts_enricher.py +220 -0
  26. infrahub/core/diff/query/time_range_query.py +2 -1
  27. infrahub/core/diff/query_parser.py +49 -24
  28. infrahub/core/diff/repository/deserializer.py +74 -71
  29. infrahub/core/diff/repository/repository.py +119 -30
  30. infrahub/core/node/__init__.py +6 -1
  31. infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
  32. infrahub/core/node/ipam.py +6 -1
  33. infrahub/core/node/permissions.py +4 -0
  34. infrahub/core/query/diff.py +223 -230
  35. infrahub/core/query/node.py +8 -2
  36. infrahub/core/query/relationship.py +2 -1
  37. infrahub/core/query/resource_manager.py +3 -1
  38. infrahub/core/relationship/model.py +1 -1
  39. infrahub/core/schema/schema_branch.py +16 -7
  40. infrahub/core/utils.py +1 -0
  41. infrahub/core/validators/uniqueness/query.py +20 -17
  42. infrahub/database/__init__.py +13 -0
  43. infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
  44. infrahub/dependencies/builder/diff/coordinator.py +0 -2
  45. infrahub/git/integrator.py +10 -6
  46. infrahub/graphql/mutations/computed_attribute.py +3 -1
  47. infrahub/graphql/mutations/diff.py +28 -4
  48. infrahub/graphql/mutations/main.py +11 -6
  49. infrahub/graphql/mutations/relationship.py +29 -1
  50. infrahub/graphql/mutations/tasks.py +6 -3
  51. infrahub/graphql/queries/resource_manager.py +7 -3
  52. infrahub/permissions/__init__.py +2 -1
  53. infrahub/permissions/types.py +26 -0
  54. infrahub/proposed_change/tasks.py +6 -1
  55. infrahub/storage.py +6 -5
  56. {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/METADATA +41 -7
  57. {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/RECORD +64 -64
  58. infrahub_testcontainers/container.py +12 -3
  59. infrahub_testcontainers/docker-compose.test.yml +22 -3
  60. infrahub_testcontainers/haproxy.cfg +43 -0
  61. infrahub_testcontainers/helpers.py +85 -1
  62. infrahub/core/diff/enricher/summary_counts.py +0 -105
  63. infrahub/dependencies/builder/diff/enricher/summary_counts.py +0 -8
  64. {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/LICENSE.txt +0 -0
  65. {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/WHEEL +0 -0
  66. {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/entry_points.txt +0 -0
@@ -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,105 +0,0 @@
1
- from collections import Counter
2
- from typing import Iterable
3
-
4
- from infrahub.core.constants import DiffAction
5
-
6
- from ..model.path import (
7
- BaseSummary,
8
- CalculatedDiffs,
9
- EnrichedDiffAttribute,
10
- EnrichedDiffNode,
11
- EnrichedDiffRelationship,
12
- EnrichedDiffRoot,
13
- EnrichedDiffSingleRelationship,
14
- )
15
- from .interface import DiffEnricherInterface
16
-
17
-
18
- class DiffSummaryCountsEnricher(DiffEnricherInterface):
19
- async def enrich(
20
- self, enriched_diff_root: EnrichedDiffRoot, calculated_diffs: CalculatedDiffs | None = None
21
- ) -> None:
22
- self._add_root_summaries(diff_root=enriched_diff_root)
23
-
24
- def _add_summary(self, summary_node: BaseSummary, actions: Iterable[DiffAction]) -> None:
25
- summary_count = Counter(actions)
26
- summary_node.num_added = summary_count.get(DiffAction.ADDED, 0)
27
- summary_node.num_updated = summary_count.get(DiffAction.UPDATED, 0)
28
- summary_node.num_removed = summary_count.get(DiffAction.REMOVED, 0)
29
-
30
- def _add_root_summaries(self, diff_root: EnrichedDiffRoot) -> None:
31
- contains_conflict = False
32
- num_conflicts = 0
33
- for diff_node in diff_root.nodes:
34
- contains_conflict |= self._add_node_summaries(diff_node=diff_node)
35
- if diff_node.conflict or diff_node.contains_conflict:
36
- num_conflicts += 1
37
- self._add_summary(summary_node=diff_root, actions=(n.action for n in diff_root.nodes))
38
- diff_root.contains_conflict = contains_conflict
39
- diff_root.num_conflicts = num_conflicts
40
- self._add_child_nodes_to_summaries(diff_root=diff_root)
41
-
42
- def _add_node_summaries(self, diff_node: EnrichedDiffNode) -> bool:
43
- contains_conflict = False
44
- num_conflicts = 0
45
- for diff_attr in diff_node.attributes:
46
- contains_conflict |= self._add_attribute_summaries(diff_attribute=diff_attr)
47
- if diff_attr.contains_conflict:
48
- num_conflicts += 1
49
- for diff_rel in diff_node.relationships:
50
- contains_conflict |= self._add_relationship_summaries(diff_relationship=diff_rel)
51
- if diff_rel.contains_conflict:
52
- num_conflicts += 1
53
- self._add_summary(
54
- summary_node=diff_node, actions=(field.action for field in diff_node.relationships | diff_node.attributes)
55
- )
56
- diff_node.contains_conflict = contains_conflict
57
- diff_node.num_conflicts = num_conflicts
58
- return contains_conflict
59
-
60
- def _add_attribute_summaries(self, diff_attribute: EnrichedDiffAttribute) -> bool:
61
- contains_conflict = False
62
- num_conflicts = 0
63
- for diff_prop in diff_attribute.properties:
64
- if diff_prop.conflict:
65
- num_conflicts += 1
66
- contains_conflict = True
67
- self._add_summary(summary_node=diff_attribute, actions=(p.action for p in diff_attribute.properties))
68
- diff_attribute.contains_conflict = contains_conflict
69
- diff_attribute.num_conflicts = num_conflicts
70
- return contains_conflict
71
-
72
- def _add_relationship_summaries(self, diff_relationship: EnrichedDiffRelationship) -> bool:
73
- contains_conflict = False
74
- num_conflicts = 0
75
- for diff_element in diff_relationship.relationships:
76
- contains_conflict |= self._add_element_summaries(diff_element=diff_element)
77
- if diff_element.conflict:
78
- num_conflicts += 1
79
- self._add_summary(summary_node=diff_relationship, actions=(e.action for e in diff_relationship.relationships))
80
- diff_relationship.contains_conflict = contains_conflict
81
- diff_relationship.num_conflicts = num_conflicts
82
- return contains_conflict
83
-
84
- def _add_element_summaries(self, diff_element: EnrichedDiffSingleRelationship) -> bool:
85
- if diff_element.conflict is None:
86
- contains_conflict = False
87
- num_conflicts = 0
88
- else:
89
- contains_conflict = True
90
- num_conflicts = 1
91
- for diff_prop in diff_element.properties:
92
- if diff_prop.conflict:
93
- num_conflicts += 1
94
- contains_conflict = True
95
- self._add_summary(summary_node=diff_element, actions=(p.action for p in diff_element.properties))
96
- diff_element.contains_conflict = contains_conflict
97
- diff_element.num_conflicts = num_conflicts
98
- return contains_conflict
99
-
100
- def _add_child_nodes_to_summaries(self, diff_root: EnrichedDiffRoot) -> None:
101
- for diff_node in diff_root.nodes:
102
- for diff_rel in diff_node.relationships:
103
- if not diff_rel.contains_conflict:
104
- diff_rel.contains_conflict = any(n.contains_conflict for n in diff_rel.nodes)
105
- diff_rel.num_conflicts += sum(bool(n.contains_conflict or n.conflict) for n in diff_rel.nodes)
@@ -1,8 +0,0 @@
1
- from infrahub.core.diff.enricher.summary_counts import DiffSummaryCountsEnricher
2
- from infrahub.dependencies.interface import DependencyBuilder, DependencyBuilderContext
3
-
4
-
5
- class DiffSummaryCountsEnricherDependency(DependencyBuilder[DiffSummaryCountsEnricher]):
6
- @classmethod
7
- def build(cls, context: DependencyBuilderContext) -> DiffSummaryCountsEnricher:
8
- return DiffSummaryCountsEnricher()