infrahub-server 1.2.7__py3-none-any.whl → 1.2.9rc0__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/transformation.py +1 -0
- infrahub/artifacts/models.py +4 -0
- infrahub/cli/db.py +15 -6
- infrahub/computed_attribute/tasks.py +1 -0
- infrahub/config.py +2 -1
- infrahub/constants/__init__.py +0 -0
- infrahub/core/constants/__init__.py +1 -0
- infrahub/core/graph/index.py +3 -1
- infrahub/core/initialization.py +23 -7
- infrahub/core/manager.py +16 -5
- infrahub/core/migrations/graph/m014_remove_index_attr_value.py +9 -8
- infrahub/core/protocols.py +1 -0
- infrahub/core/query/node.py +96 -29
- infrahub/core/schema/definitions/core/builtin.py +2 -4
- infrahub/core/schema/definitions/core/transform.py +1 -0
- infrahub/core/validators/aggregated_checker.py +2 -2
- infrahub/core/validators/uniqueness/query.py +30 -9
- infrahub/database/__init__.py +1 -16
- infrahub/database/index.py +1 -1
- infrahub/database/memgraph.py +1 -12
- infrahub/database/neo4j.py +1 -13
- infrahub/git/integrator.py +27 -3
- infrahub/git/models.py +4 -0
- infrahub/git/tasks.py +3 -0
- infrahub/git_credential/helper.py +2 -2
- infrahub/graphql/mutations/computed_attribute.py +5 -1
- infrahub/message_bus/operations/requests/proposed_change.py +6 -0
- infrahub/message_bus/types.py +3 -0
- infrahub/patch/queries/consolidate_duplicated_nodes.py +109 -0
- infrahub/patch/queries/delete_duplicated_edges.py +138 -0
- infrahub/proposed_change/tasks.py +1 -0
- infrahub/server.py +1 -3
- infrahub/transformations/models.py +3 -0
- infrahub/transformations/tasks.py +1 -0
- infrahub/webhook/models.py +3 -0
- infrahub_sdk/client.py +4 -4
- infrahub_sdk/config.py +17 -0
- infrahub_sdk/ctl/cli_commands.py +7 -1
- infrahub_sdk/ctl/generator.py +2 -2
- infrahub_sdk/generator.py +12 -66
- infrahub_sdk/operation.py +80 -0
- infrahub_sdk/protocols.py +12 -0
- infrahub_sdk/recorder.py +3 -0
- infrahub_sdk/schema/repository.py +4 -0
- infrahub_sdk/transforms.py +15 -27
- {infrahub_server-1.2.7.dist-info → infrahub_server-1.2.9rc0.dist-info}/METADATA +2 -2
- {infrahub_server-1.2.7.dist-info → infrahub_server-1.2.9rc0.dist-info}/RECORD +53 -50
- infrahub_testcontainers/container.py +1 -0
- infrahub_testcontainers/docker-compose.test.yml +4 -0
- infrahub/database/manager.py +0 -15
- /infrahub/{database/constants.py → constants/database.py} +0 -0
- {infrahub_server-1.2.7.dist-info → infrahub_server-1.2.9rc0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.7.dist-info → infrahub_server-1.2.9rc0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.2.7.dist-info → infrahub_server-1.2.9rc0.dist-info}/entry_points.txt +0 -0
infrahub_sdk/ctl/generator.py
CHANGED
|
@@ -62,7 +62,7 @@ async def run(
|
|
|
62
62
|
generator = generator_class(
|
|
63
63
|
query=generator_config.query,
|
|
64
64
|
client=client,
|
|
65
|
-
branch=branch,
|
|
65
|
+
branch=branch or "",
|
|
66
66
|
params=variables_dict,
|
|
67
67
|
convert_query_response=generator_config.convert_query_response,
|
|
68
68
|
infrahub_node=InfrahubNode,
|
|
@@ -91,7 +91,7 @@ async def run(
|
|
|
91
91
|
generator = generator_class(
|
|
92
92
|
query=generator_config.query,
|
|
93
93
|
client=client,
|
|
94
|
-
branch=branch,
|
|
94
|
+
branch=branch or "",
|
|
95
95
|
params=params,
|
|
96
96
|
convert_query_response=generator_config.convert_query_response,
|
|
97
97
|
infrahub_node=InfrahubNode,
|
infrahub_sdk/generator.py
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import os
|
|
5
4
|
from abc import abstractmethod
|
|
6
5
|
from typing import TYPE_CHECKING
|
|
7
6
|
|
|
8
|
-
from infrahub_sdk.repository import GitRepoManager
|
|
9
|
-
|
|
10
7
|
from .exceptions import UninitializedError
|
|
8
|
+
from .operation import InfrahubOperation
|
|
11
9
|
|
|
12
10
|
if TYPE_CHECKING:
|
|
13
11
|
from .client import InfrahubClient
|
|
14
12
|
from .context import RequestContext
|
|
15
13
|
from .node import InfrahubNode
|
|
16
|
-
from .store import NodeStore
|
|
17
14
|
|
|
18
15
|
|
|
19
|
-
class InfrahubGenerator:
|
|
16
|
+
class InfrahubGenerator(InfrahubOperation):
|
|
20
17
|
"""Infrahub Generator class"""
|
|
21
18
|
|
|
22
19
|
def __init__(
|
|
@@ -24,7 +21,7 @@ class InfrahubGenerator:
|
|
|
24
21
|
query: str,
|
|
25
22
|
client: InfrahubClient,
|
|
26
23
|
infrahub_node: type[InfrahubNode],
|
|
27
|
-
branch: str
|
|
24
|
+
branch: str = "",
|
|
28
25
|
root_directory: str = "",
|
|
29
26
|
generator_instance: str = "",
|
|
30
27
|
params: dict | None = None,
|
|
@@ -33,37 +30,21 @@ class InfrahubGenerator:
|
|
|
33
30
|
request_context: RequestContext | None = None,
|
|
34
31
|
) -> None:
|
|
35
32
|
self.query = query
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
|
|
34
|
+
super().__init__(
|
|
35
|
+
client=client,
|
|
36
|
+
infrahub_node=infrahub_node,
|
|
37
|
+
convert_query_response=convert_query_response,
|
|
38
|
+
branch=branch,
|
|
39
|
+
root_directory=root_directory,
|
|
40
|
+
)
|
|
41
|
+
|
|
38
42
|
self.params = params or {}
|
|
39
|
-
self.root_directory = root_directory or os.getcwd()
|
|
40
43
|
self.generator_instance = generator_instance
|
|
41
|
-
self._init_client = client.clone()
|
|
42
|
-
self._init_client.config.default_branch = self._init_client.default_branch = self.branch_name
|
|
43
|
-
self._init_client.store._default_branch = self.branch_name
|
|
44
44
|
self._client: InfrahubClient | None = None
|
|
45
|
-
self._nodes: list[InfrahubNode] = []
|
|
46
|
-
self._related_nodes: list[InfrahubNode] = []
|
|
47
|
-
self.infrahub_node = infrahub_node
|
|
48
|
-
self.convert_query_response = convert_query_response
|
|
49
45
|
self.logger = logger if logger else logging.getLogger("infrahub.tasks")
|
|
50
46
|
self.request_context = request_context
|
|
51
47
|
|
|
52
|
-
@property
|
|
53
|
-
def store(self) -> NodeStore:
|
|
54
|
-
"""The store will be populated with nodes based on the query during the collection of data if activated"""
|
|
55
|
-
return self._init_client.store
|
|
56
|
-
|
|
57
|
-
@property
|
|
58
|
-
def nodes(self) -> list[InfrahubNode]:
|
|
59
|
-
"""Returns nodes collected and parsed during the data collection process if this feature is enables"""
|
|
60
|
-
return self._nodes
|
|
61
|
-
|
|
62
|
-
@property
|
|
63
|
-
def related_nodes(self) -> list[InfrahubNode]:
|
|
64
|
-
"""Returns nodes collected and parsed during the data collection process if this feature is enables"""
|
|
65
|
-
return self._related_nodes
|
|
66
|
-
|
|
67
48
|
@property
|
|
68
49
|
def subscribers(self) -> list[str] | None:
|
|
69
50
|
if self.generator_instance:
|
|
@@ -80,20 +61,6 @@ class InfrahubGenerator:
|
|
|
80
61
|
def client(self, value: InfrahubClient) -> None:
|
|
81
62
|
self._client = value
|
|
82
63
|
|
|
83
|
-
@property
|
|
84
|
-
def branch_name(self) -> str:
|
|
85
|
-
"""Return the name of the current git branch."""
|
|
86
|
-
|
|
87
|
-
if self.branch:
|
|
88
|
-
return self.branch
|
|
89
|
-
|
|
90
|
-
if not self.git:
|
|
91
|
-
self.git = GitRepoManager(self.root_directory)
|
|
92
|
-
|
|
93
|
-
self.branch = str(self.git.active_branch)
|
|
94
|
-
|
|
95
|
-
return self.branch
|
|
96
|
-
|
|
97
64
|
async def collect_data(self) -> dict:
|
|
98
65
|
"""Query the result of the GraphQL Query defined in self.query and return the result"""
|
|
99
66
|
|
|
@@ -119,27 +86,6 @@ class InfrahubGenerator:
|
|
|
119
86
|
) as self.client:
|
|
120
87
|
await self.generate(data=unpacked)
|
|
121
88
|
|
|
122
|
-
async def process_nodes(self, data: dict) -> None:
|
|
123
|
-
if not self.convert_query_response:
|
|
124
|
-
return
|
|
125
|
-
|
|
126
|
-
await self._init_client.schema.all(branch=self.branch_name)
|
|
127
|
-
|
|
128
|
-
for kind in data:
|
|
129
|
-
if kind in self._init_client.schema.cache[self.branch_name].nodes.keys():
|
|
130
|
-
for result in data[kind].get("edges", []):
|
|
131
|
-
node = await self.infrahub_node.from_graphql(
|
|
132
|
-
client=self._init_client, branch=self.branch_name, data=result
|
|
133
|
-
)
|
|
134
|
-
self._nodes.append(node)
|
|
135
|
-
await node._process_relationships(
|
|
136
|
-
node_data=result, branch=self.branch_name, related_nodes=self._related_nodes
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
for node in self._nodes + self._related_nodes:
|
|
140
|
-
if node.id:
|
|
141
|
-
self._init_client.store.set(node=node)
|
|
142
|
-
|
|
143
89
|
@abstractmethod
|
|
144
90
|
async def generate(self, data: dict) -> None:
|
|
145
91
|
"""Code to run the generator
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from .repository import GitRepoManager
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from . import InfrahubClient
|
|
10
|
+
from .node import InfrahubNode
|
|
11
|
+
from .store import NodeStore
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class InfrahubOperation:
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
client: InfrahubClient,
|
|
18
|
+
infrahub_node: type[InfrahubNode],
|
|
19
|
+
convert_query_response: bool,
|
|
20
|
+
branch: str,
|
|
21
|
+
root_directory: str,
|
|
22
|
+
):
|
|
23
|
+
self.branch = branch
|
|
24
|
+
self.convert_query_response = convert_query_response
|
|
25
|
+
self.root_directory = root_directory or os.getcwd()
|
|
26
|
+
self.infrahub_node = infrahub_node
|
|
27
|
+
self._nodes: list[InfrahubNode] = []
|
|
28
|
+
self._related_nodes: list[InfrahubNode] = []
|
|
29
|
+
self._init_client = client.clone(branch=self.branch_name)
|
|
30
|
+
self.git: GitRepoManager | None = None
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def branch_name(self) -> str:
|
|
34
|
+
"""Return the name of the current git branch."""
|
|
35
|
+
|
|
36
|
+
if self.branch:
|
|
37
|
+
return self.branch
|
|
38
|
+
|
|
39
|
+
if not hasattr(self, "git") or not self.git:
|
|
40
|
+
self.git = GitRepoManager(self.root_directory)
|
|
41
|
+
|
|
42
|
+
self.branch = str(self.git.active_branch)
|
|
43
|
+
|
|
44
|
+
return self.branch
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def store(self) -> NodeStore:
|
|
48
|
+
"""The store will be populated with nodes based on the query during the collection of data if activated"""
|
|
49
|
+
return self._init_client.store
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def nodes(self) -> list[InfrahubNode]:
|
|
53
|
+
"""Returns nodes collected and parsed during the data collection process if this feature is enabled"""
|
|
54
|
+
return self._nodes
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def related_nodes(self) -> list[InfrahubNode]:
|
|
58
|
+
"""Returns nodes collected and parsed during the data collection process if this feature is enabled"""
|
|
59
|
+
return self._related_nodes
|
|
60
|
+
|
|
61
|
+
async def process_nodes(self, data: dict) -> None:
|
|
62
|
+
if not self.convert_query_response:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
await self._init_client.schema.all(branch=self.branch_name)
|
|
66
|
+
|
|
67
|
+
for kind in data:
|
|
68
|
+
if kind in self._init_client.schema.cache[self.branch_name].nodes.keys():
|
|
69
|
+
for result in data[kind].get("edges", []):
|
|
70
|
+
node = await self.infrahub_node.from_graphql(
|
|
71
|
+
client=self._init_client, branch=self.branch_name, data=result
|
|
72
|
+
)
|
|
73
|
+
self._nodes.append(node)
|
|
74
|
+
await node._process_relationships(
|
|
75
|
+
node_data=result, branch=self.branch_name, related_nodes=self._related_nodes
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
for node in self._nodes + self._related_nodes:
|
|
79
|
+
if node.id:
|
|
80
|
+
self._init_client.store.set(node=node)
|
infrahub_sdk/protocols.py
CHANGED
|
@@ -154,6 +154,10 @@ class CoreMenu(CoreNode):
|
|
|
154
154
|
children: RelationshipManager
|
|
155
155
|
|
|
156
156
|
|
|
157
|
+
class CoreObjectComponentTemplate(CoreNode):
|
|
158
|
+
template_name: String
|
|
159
|
+
|
|
160
|
+
|
|
157
161
|
class CoreObjectTemplate(CoreNode):
|
|
158
162
|
template_name: String
|
|
159
163
|
|
|
@@ -205,6 +209,7 @@ class CoreWebhook(CoreNode):
|
|
|
205
209
|
name: String
|
|
206
210
|
event_type: Enum
|
|
207
211
|
branch_scope: Dropdown
|
|
212
|
+
node_kind: StringOptional
|
|
208
213
|
description: StringOptional
|
|
209
214
|
url: URL
|
|
210
215
|
validate_certificates: BooleanOptional
|
|
@@ -479,6 +484,7 @@ class CoreTransformJinja2(CoreTransformation):
|
|
|
479
484
|
class CoreTransformPython(CoreTransformation):
|
|
480
485
|
file_path: String
|
|
481
486
|
class_name: String
|
|
487
|
+
convert_query_response: BooleanOptional
|
|
482
488
|
|
|
483
489
|
|
|
484
490
|
class CoreUserValidator(CoreValidator):
|
|
@@ -625,6 +631,10 @@ class CoreMenuSync(CoreNodeSync):
|
|
|
625
631
|
children: RelationshipManagerSync
|
|
626
632
|
|
|
627
633
|
|
|
634
|
+
class CoreObjectComponentTemplateSync(CoreNodeSync):
|
|
635
|
+
template_name: String
|
|
636
|
+
|
|
637
|
+
|
|
628
638
|
class CoreObjectTemplateSync(CoreNodeSync):
|
|
629
639
|
template_name: String
|
|
630
640
|
|
|
@@ -676,6 +686,7 @@ class CoreWebhookSync(CoreNodeSync):
|
|
|
676
686
|
name: String
|
|
677
687
|
event_type: Enum
|
|
678
688
|
branch_scope: Dropdown
|
|
689
|
+
node_kind: StringOptional
|
|
679
690
|
description: StringOptional
|
|
680
691
|
url: URL
|
|
681
692
|
validate_certificates: BooleanOptional
|
|
@@ -950,6 +961,7 @@ class CoreTransformJinja2Sync(CoreTransformationSync):
|
|
|
950
961
|
class CoreTransformPythonSync(CoreTransformationSync):
|
|
951
962
|
file_path: String
|
|
952
963
|
class_name: String
|
|
964
|
+
convert_query_response: BooleanOptional
|
|
953
965
|
|
|
954
966
|
|
|
955
967
|
class CoreUserValidatorSync(CoreValidatorSync):
|
infrahub_sdk/recorder.py
CHANGED
|
@@ -31,6 +31,9 @@ class NoRecorder:
|
|
|
31
31
|
def default(cls) -> NoRecorder:
|
|
32
32
|
return cls()
|
|
33
33
|
|
|
34
|
+
def __eq__(self, other: object) -> bool:
|
|
35
|
+
return isinstance(other, NoRecorder)
|
|
36
|
+
|
|
34
37
|
|
|
35
38
|
class JSONRecorder(BaseSettings):
|
|
36
39
|
model_config = SettingsConfigDict(env_prefix="INFRAHUB_JSON_RECORDER_")
|
|
@@ -117,6 +117,10 @@ class InfrahubPythonTransformConfig(InfrahubRepositoryConfigElement):
|
|
|
117
117
|
name: str = Field(..., description="The name of the Transform")
|
|
118
118
|
file_path: Path = Field(..., description="The file within the repository with the transform code.")
|
|
119
119
|
class_name: str = Field(default="Transform", description="The name of the transform class to run.")
|
|
120
|
+
convert_query_response: bool = Field(
|
|
121
|
+
default=False,
|
|
122
|
+
description="Decide if the transform should convert the result of the GraphQL query to SDK InfrahubNode objects.",
|
|
123
|
+
)
|
|
120
124
|
|
|
121
125
|
def load_class(self, import_root: str | None = None, relative_path: str | None = None) -> type[InfrahubTransform]:
|
|
122
126
|
module = import_module(module_path=self.file_path, import_root=import_root, relative_path=relative_path)
|
infrahub_sdk/transforms.py
CHANGED
|
@@ -5,34 +5,38 @@ import os
|
|
|
5
5
|
from abc import abstractmethod
|
|
6
6
|
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
|
|
10
|
-
from .exceptions import UninitializedError
|
|
8
|
+
from .operation import InfrahubOperation
|
|
11
9
|
|
|
12
10
|
if TYPE_CHECKING:
|
|
13
11
|
from . import InfrahubClient
|
|
12
|
+
from .node import InfrahubNode
|
|
14
13
|
|
|
15
14
|
INFRAHUB_TRANSFORM_VARIABLE_TO_IMPORT = "INFRAHUB_TRANSFORMS"
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
class InfrahubTransform:
|
|
17
|
+
class InfrahubTransform(InfrahubOperation):
|
|
19
18
|
name: str | None = None
|
|
20
19
|
query: str
|
|
21
20
|
timeout: int = 10
|
|
22
21
|
|
|
23
22
|
def __init__(
|
|
24
23
|
self,
|
|
24
|
+
client: InfrahubClient,
|
|
25
|
+
infrahub_node: type[InfrahubNode],
|
|
26
|
+
convert_query_response: bool = False,
|
|
25
27
|
branch: str = "",
|
|
26
28
|
root_directory: str = "",
|
|
27
29
|
server_url: str = "",
|
|
28
|
-
client: InfrahubClient | None = None,
|
|
29
30
|
):
|
|
30
|
-
|
|
31
|
+
super().__init__(
|
|
32
|
+
client=client,
|
|
33
|
+
infrahub_node=infrahub_node,
|
|
34
|
+
convert_query_response=convert_query_response,
|
|
35
|
+
branch=branch,
|
|
36
|
+
root_directory=root_directory,
|
|
37
|
+
)
|
|
31
38
|
|
|
32
|
-
self.branch = branch
|
|
33
39
|
self.server_url = server_url or os.environ.get("INFRAHUB_URL", "http://127.0.0.1:8000")
|
|
34
|
-
self.root_directory = root_directory or os.getcwd()
|
|
35
|
-
|
|
36
40
|
self._client = client
|
|
37
41
|
|
|
38
42
|
if not self.name:
|
|
@@ -43,24 +47,7 @@ class InfrahubTransform:
|
|
|
43
47
|
|
|
44
48
|
@property
|
|
45
49
|
def client(self) -> InfrahubClient:
|
|
46
|
-
|
|
47
|
-
return self._client
|
|
48
|
-
|
|
49
|
-
raise UninitializedError("The client has not been initialized")
|
|
50
|
-
|
|
51
|
-
@property
|
|
52
|
-
def branch_name(self) -> str:
|
|
53
|
-
"""Return the name of the current git branch."""
|
|
54
|
-
|
|
55
|
-
if self.branch:
|
|
56
|
-
return self.branch
|
|
57
|
-
|
|
58
|
-
if not hasattr(self, "git") or not self.git:
|
|
59
|
-
self.git = GitRepoManager(self.root_directory)
|
|
60
|
-
|
|
61
|
-
self.branch = str(self.git.active_branch)
|
|
62
|
-
|
|
63
|
-
return self.branch
|
|
50
|
+
return self._init_client
|
|
64
51
|
|
|
65
52
|
@abstractmethod
|
|
66
53
|
def transform(self, data: dict) -> Any:
|
|
@@ -86,6 +73,7 @@ class InfrahubTransform:
|
|
|
86
73
|
data = await self.collect_data()
|
|
87
74
|
|
|
88
75
|
unpacked = data.get("data") or data
|
|
76
|
+
await self.process_nodes(data=unpacked)
|
|
89
77
|
|
|
90
78
|
if asyncio.iscoroutinefunction(self.transform):
|
|
91
79
|
return await self.transform(data=unpacked)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: infrahub-server
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.9rc0
|
|
4
4
|
Summary: Infrahub is taking a new approach to Infrastructure Management by providing a new generation of datastore to organize and control all the data that defines how an infrastructure should run.
|
|
5
5
|
Home-page: https://opsmill.com
|
|
6
6
|
License: AGPL-3.0-only
|
|
@@ -39,7 +39,7 @@ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc (==1.28.1)
|
|
|
39
39
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http (==1.28.1)
|
|
40
40
|
Requires-Dist: opentelemetry-instrumentation-aio-pika (==0.49b1)
|
|
41
41
|
Requires-Dist: opentelemetry-instrumentation-fastapi (==0.49b1)
|
|
42
|
-
Requires-Dist: prefect (==3.3.
|
|
42
|
+
Requires-Dist: prefect (==3.3.7)
|
|
43
43
|
Requires-Dist: prefect-redis (==0.2.2)
|
|
44
44
|
Requires-Dist: pyarrow (>=14,<15)
|
|
45
45
|
Requires-Dist: pydantic (>=2.10,<2.11)
|