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.
- infrahub/api/oidc.py +1 -0
- infrahub/core/attribute.py +4 -1
- infrahub/core/branch/tasks.py +7 -4
- infrahub/core/diff/calculator.py +21 -39
- infrahub/core/diff/combiner.py +11 -7
- infrahub/core/diff/coordinator.py +49 -70
- infrahub/core/diff/data_check_synchronizer.py +86 -7
- infrahub/core/diff/enricher/aggregated.py +3 -3
- infrahub/core/diff/enricher/cardinality_one.py +1 -6
- infrahub/core/diff/enricher/labels.py +13 -3
- infrahub/core/diff/enricher/path_identifier.py +2 -8
- infrahub/core/diff/ipam_diff_parser.py +1 -1
- infrahub/core/diff/merger/merger.py +5 -3
- infrahub/core/diff/merger/serializer.py +15 -8
- infrahub/core/diff/model/path.py +42 -24
- infrahub/core/diff/query/all_conflicts.py +5 -2
- infrahub/core/diff/query/diff_get.py +19 -23
- infrahub/core/diff/query/field_specifiers.py +2 -0
- infrahub/core/diff/query/field_summary.py +2 -1
- infrahub/core/diff/query/filters.py +12 -1
- infrahub/core/diff/query/has_conflicts_query.py +5 -2
- infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +3 -3
- infrahub/core/diff/query/roots_metadata.py +8 -1
- infrahub/core/diff/query/save.py +148 -63
- infrahub/core/diff/query/summary_counts_enricher.py +220 -0
- infrahub/core/diff/query/time_range_query.py +2 -1
- infrahub/core/diff/query_parser.py +49 -24
- infrahub/core/diff/repository/deserializer.py +74 -71
- infrahub/core/diff/repository/repository.py +119 -30
- infrahub/core/node/__init__.py +6 -1
- infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
- infrahub/core/node/ipam.py +6 -1
- infrahub/core/node/permissions.py +4 -0
- infrahub/core/query/diff.py +223 -230
- infrahub/core/query/node.py +8 -2
- infrahub/core/query/relationship.py +2 -1
- infrahub/core/query/resource_manager.py +3 -1
- infrahub/core/relationship/model.py +1 -1
- infrahub/core/schema/schema_branch.py +16 -7
- infrahub/core/utils.py +1 -0
- infrahub/core/validators/uniqueness/query.py +20 -17
- infrahub/database/__init__.py +13 -0
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
- infrahub/dependencies/builder/diff/coordinator.py +0 -2
- infrahub/git/integrator.py +10 -6
- infrahub/graphql/mutations/computed_attribute.py +3 -1
- infrahub/graphql/mutations/diff.py +28 -4
- infrahub/graphql/mutations/main.py +11 -6
- infrahub/graphql/mutations/relationship.py +29 -1
- infrahub/graphql/mutations/tasks.py +6 -3
- infrahub/graphql/queries/resource_manager.py +7 -3
- infrahub/permissions/__init__.py +2 -1
- infrahub/permissions/types.py +26 -0
- infrahub/proposed_change/tasks.py +6 -1
- infrahub/storage.py +6 -5
- {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/METADATA +41 -7
- {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/RECORD +64 -64
- infrahub_testcontainers/container.py +12 -3
- infrahub_testcontainers/docker-compose.test.yml +22 -3
- infrahub_testcontainers/haproxy.cfg +43 -0
- infrahub_testcontainers/helpers.py +85 -1
- infrahub/core/diff/enricher/summary_counts.py +0 -105
- infrahub/dependencies/builder/diff/enricher/summary_counts.py +0 -8
- {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.1.5.dist-info → infrahub_server-1.1.7.dist-info}/WHEEL +0 -0
- {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(
|
|
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()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|