infrahub-server 1.4.12__py3-none-any.whl → 1.5.0__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/actions/tasks.py +208 -16
- infrahub/api/artifact.py +3 -0
- infrahub/api/diff/diff.py +1 -1
- infrahub/api/internal.py +2 -0
- infrahub/api/query.py +2 -0
- infrahub/api/schema.py +27 -3
- infrahub/auth.py +5 -5
- infrahub/cli/__init__.py +2 -0
- infrahub/cli/db.py +160 -157
- infrahub/cli/dev.py +118 -0
- infrahub/cli/tasks.py +46 -0
- infrahub/cli/upgrade.py +56 -9
- infrahub/computed_attribute/tasks.py +19 -7
- infrahub/config.py +7 -2
- infrahub/core/attribute.py +35 -24
- infrahub/core/branch/enums.py +1 -1
- infrahub/core/branch/models.py +9 -5
- infrahub/core/branch/needs_rebase_status.py +11 -0
- infrahub/core/branch/tasks.py +72 -10
- infrahub/core/changelog/models.py +2 -10
- infrahub/core/constants/__init__.py +4 -0
- infrahub/core/constants/infrahubkind.py +1 -0
- infrahub/core/convert_object_type/object_conversion.py +201 -0
- infrahub/core/convert_object_type/repository_conversion.py +89 -0
- infrahub/core/convert_object_type/schema_mapping.py +27 -3
- infrahub/core/diff/calculator.py +2 -2
- infrahub/core/diff/model/path.py +4 -0
- infrahub/core/diff/payload_builder.py +1 -1
- infrahub/core/diff/query/artifact.py +1 -0
- infrahub/core/diff/query/delete_query.py +9 -5
- infrahub/core/diff/query/field_summary.py +1 -0
- infrahub/core/diff/query/merge.py +39 -23
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/initialization.py +7 -4
- infrahub/core/manager.py +3 -81
- infrahub/core/migrations/__init__.py +3 -0
- infrahub/core/migrations/exceptions.py +4 -0
- infrahub/core/migrations/graph/__init__.py +13 -10
- infrahub/core/migrations/graph/load_schema_branch.py +21 -0
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +1 -1
- infrahub/core/migrations/graph/m037_index_attr_vals.py +11 -30
- infrahub/core/migrations/graph/m039_ipam_reconcile.py +9 -7
- infrahub/core/migrations/graph/m041_deleted_dup_edges.py +149 -0
- infrahub/core/migrations/graph/m042_profile_attrs_in_db.py +147 -0
- infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py +164 -0
- infrahub/core/migrations/graph/m044_backfill_hfid_display_label_in_db.py +864 -0
- infrahub/core/migrations/query/__init__.py +7 -8
- infrahub/core/migrations/query/attribute_add.py +8 -6
- infrahub/core/migrations/query/attribute_remove.py +134 -0
- infrahub/core/migrations/runner.py +54 -0
- infrahub/core/migrations/schema/attribute_kind_update.py +9 -3
- infrahub/core/migrations/schema/attribute_supports_profile.py +90 -0
- infrahub/core/migrations/schema/node_attribute_add.py +26 -5
- infrahub/core/migrations/schema/node_attribute_remove.py +13 -109
- infrahub/core/migrations/schema/node_kind_update.py +2 -1
- infrahub/core/migrations/schema/node_remove.py +2 -1
- infrahub/core/migrations/schema/placeholder_dummy.py +3 -2
- infrahub/core/migrations/shared.py +66 -19
- infrahub/core/models.py +2 -2
- infrahub/core/node/__init__.py +207 -54
- infrahub/core/node/create.py +53 -49
- infrahub/core/node/lock_utils.py +124 -0
- infrahub/core/node/node_property_attribute.py +230 -0
- infrahub/core/node/resource_manager/ip_address_pool.py +2 -1
- infrahub/core/node/resource_manager/ip_prefix_pool.py +2 -1
- infrahub/core/node/resource_manager/number_pool.py +2 -1
- infrahub/core/node/standard.py +1 -1
- infrahub/core/property.py +11 -0
- infrahub/core/protocols.py +8 -1
- infrahub/core/query/attribute.py +82 -15
- infrahub/core/query/diff.py +61 -16
- infrahub/core/query/ipam.py +16 -4
- infrahub/core/query/node.py +92 -212
- infrahub/core/query/relationship.py +44 -26
- infrahub/core/query/subquery.py +0 -8
- infrahub/core/relationship/model.py +69 -24
- infrahub/core/schema/__init__.py +56 -0
- infrahub/core/schema/attribute_schema.py +4 -2
- infrahub/core/schema/basenode_schema.py +42 -2
- infrahub/core/schema/definitions/core/__init__.py +2 -0
- infrahub/core/schema/definitions/core/check.py +1 -1
- infrahub/core/schema/definitions/core/generator.py +2 -0
- infrahub/core/schema/definitions/core/group.py +16 -2
- infrahub/core/schema/definitions/core/repository.py +7 -0
- infrahub/core/schema/definitions/core/transform.py +1 -1
- infrahub/core/schema/definitions/internal.py +12 -3
- infrahub/core/schema/generated/attribute_schema.py +2 -2
- infrahub/core/schema/generated/base_node_schema.py +6 -1
- infrahub/core/schema/manager.py +3 -0
- infrahub/core/schema/node_schema.py +1 -0
- infrahub/core/schema/relationship_schema.py +0 -1
- infrahub/core/schema/schema_branch.py +295 -10
- infrahub/core/schema/schema_branch_display.py +135 -0
- infrahub/core/schema/schema_branch_hfid.py +120 -0
- infrahub/core/validators/aggregated_checker.py +1 -1
- infrahub/database/graph.py +21 -0
- infrahub/display_labels/__init__.py +0 -0
- infrahub/display_labels/gather.py +48 -0
- infrahub/display_labels/models.py +240 -0
- infrahub/display_labels/tasks.py +192 -0
- infrahub/display_labels/triggers.py +22 -0
- infrahub/events/branch_action.py +27 -1
- infrahub/events/group_action.py +1 -1
- infrahub/events/node_action.py +1 -1
- infrahub/generators/constants.py +7 -0
- infrahub/generators/models.py +38 -12
- infrahub/generators/tasks.py +34 -16
- infrahub/git/base.py +42 -2
- infrahub/git/integrator.py +22 -14
- infrahub/git/tasks.py +52 -2
- infrahub/graphql/analyzer.py +9 -0
- infrahub/graphql/api/dependencies.py +2 -4
- infrahub/graphql/api/endpoints.py +16 -6
- infrahub/graphql/app.py +2 -4
- infrahub/graphql/initialization.py +2 -3
- infrahub/graphql/manager.py +213 -137
- infrahub/graphql/middleware.py +12 -0
- infrahub/graphql/mutations/branch.py +16 -0
- infrahub/graphql/mutations/computed_attribute.py +110 -3
- infrahub/graphql/mutations/convert_object_type.py +44 -13
- infrahub/graphql/mutations/display_label.py +118 -0
- infrahub/graphql/mutations/generator.py +25 -7
- infrahub/graphql/mutations/hfid.py +125 -0
- infrahub/graphql/mutations/ipam.py +73 -41
- infrahub/graphql/mutations/main.py +61 -178
- infrahub/graphql/mutations/profile.py +195 -0
- infrahub/graphql/mutations/proposed_change.py +8 -1
- infrahub/graphql/mutations/relationship.py +2 -2
- infrahub/graphql/mutations/repository.py +22 -83
- infrahub/graphql/mutations/resource_manager.py +2 -2
- infrahub/graphql/mutations/webhook.py +1 -1
- infrahub/graphql/queries/resource_manager.py +1 -1
- infrahub/graphql/registry.py +173 -0
- infrahub/graphql/resolvers/resolver.py +2 -0
- infrahub/graphql/schema.py +8 -1
- infrahub/graphql/schema_sort.py +170 -0
- infrahub/graphql/types/branch.py +4 -1
- infrahub/graphql/types/enums.py +3 -0
- infrahub/groups/tasks.py +1 -1
- infrahub/hfid/__init__.py +0 -0
- infrahub/hfid/gather.py +48 -0
- infrahub/hfid/models.py +240 -0
- infrahub/hfid/tasks.py +191 -0
- infrahub/hfid/triggers.py +22 -0
- infrahub/lock.py +119 -42
- infrahub/locks/__init__.py +0 -0
- infrahub/locks/tasks.py +37 -0
- infrahub/message_bus/types.py +1 -0
- infrahub/patch/plan_writer.py +2 -2
- infrahub/permissions/constants.py +2 -0
- infrahub/profiles/__init__.py +0 -0
- infrahub/profiles/node_applier.py +101 -0
- infrahub/profiles/queries/__init__.py +0 -0
- infrahub/profiles/queries/get_profile_data.py +98 -0
- infrahub/profiles/tasks.py +63 -0
- infrahub/proposed_change/tasks.py +67 -14
- infrahub/repositories/__init__.py +0 -0
- infrahub/repositories/create_repository.py +113 -0
- infrahub/server.py +9 -1
- infrahub/services/__init__.py +8 -5
- infrahub/services/adapters/http/__init__.py +5 -0
- infrahub/services/adapters/workflow/worker.py +14 -3
- infrahub/task_manager/event.py +5 -0
- infrahub/task_manager/models.py +7 -0
- infrahub/task_manager/task.py +73 -0
- infrahub/tasks/registry.py +6 -4
- infrahub/trigger/catalogue.py +4 -0
- infrahub/trigger/models.py +2 -0
- infrahub/trigger/setup.py +13 -4
- infrahub/trigger/tasks.py +6 -0
- infrahub/webhook/models.py +1 -1
- infrahub/workers/dependencies.py +3 -1
- infrahub/workers/infrahub_async.py +10 -2
- infrahub/workflows/catalogue.py +118 -3
- infrahub/workflows/initialization.py +21 -0
- infrahub/workflows/models.py +17 -2
- infrahub/workflows/utils.py +2 -1
- infrahub_sdk/branch.py +17 -8
- infrahub_sdk/checks.py +1 -1
- infrahub_sdk/client.py +376 -95
- infrahub_sdk/config.py +29 -2
- infrahub_sdk/convert_object_type.py +61 -0
- infrahub_sdk/ctl/branch.py +3 -0
- infrahub_sdk/ctl/check.py +2 -3
- infrahub_sdk/ctl/cli_commands.py +20 -12
- infrahub_sdk/ctl/config.py +8 -2
- infrahub_sdk/ctl/generator.py +6 -3
- infrahub_sdk/ctl/graphql.py +184 -0
- infrahub_sdk/ctl/repository.py +39 -1
- infrahub_sdk/ctl/schema.py +40 -10
- infrahub_sdk/ctl/task.py +110 -0
- infrahub_sdk/ctl/utils.py +4 -0
- infrahub_sdk/ctl/validate.py +5 -3
- infrahub_sdk/diff.py +4 -5
- infrahub_sdk/exceptions.py +2 -0
- infrahub_sdk/generator.py +7 -1
- infrahub_sdk/graphql/__init__.py +12 -0
- infrahub_sdk/graphql/constants.py +1 -0
- infrahub_sdk/graphql/plugin.py +85 -0
- infrahub_sdk/graphql/query.py +77 -0
- infrahub_sdk/{graphql.py → graphql/renderers.py} +88 -75
- infrahub_sdk/graphql/utils.py +40 -0
- infrahub_sdk/node/attribute.py +2 -0
- infrahub_sdk/node/node.py +28 -20
- infrahub_sdk/node/relationship.py +1 -3
- infrahub_sdk/playback.py +1 -2
- infrahub_sdk/protocols.py +54 -6
- infrahub_sdk/pytest_plugin/plugin.py +7 -4
- infrahub_sdk/pytest_plugin/utils.py +40 -0
- infrahub_sdk/repository.py +1 -2
- infrahub_sdk/schema/__init__.py +70 -4
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/schema/repository.py +8 -0
- infrahub_sdk/spec/models.py +7 -0
- infrahub_sdk/spec/object.py +54 -6
- infrahub_sdk/spec/processors/__init__.py +0 -0
- infrahub_sdk/spec/processors/data_processor.py +10 -0
- infrahub_sdk/spec/processors/factory.py +34 -0
- infrahub_sdk/spec/processors/range_expand_processor.py +56 -0
- infrahub_sdk/spec/range_expansion.py +118 -0
- infrahub_sdk/task/models.py +6 -4
- infrahub_sdk/timestamp.py +18 -6
- infrahub_sdk/transforms.py +1 -1
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/METADATA +9 -10
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/RECORD +233 -176
- infrahub_testcontainers/container.py +114 -2
- infrahub_testcontainers/docker-compose-cluster.test.yml +5 -0
- infrahub_testcontainers/docker-compose.test.yml +5 -0
- infrahub_testcontainers/models.py +2 -2
- infrahub_testcontainers/performance_test.py +4 -4
- infrahub/core/convert_object_type/conversion.py +0 -134
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Sequence
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Sequence, TypeAlias
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel, ConfigDict, Field
|
|
6
|
+
from rich.console import Console
|
|
6
7
|
from typing_extensions import Self
|
|
7
8
|
|
|
8
9
|
from infrahub.core import registry
|
|
9
10
|
from infrahub.core.path import SchemaPath # noqa: TC001
|
|
10
11
|
from infrahub.core.query import Query # noqa: TC001
|
|
11
|
-
from infrahub.core.schema import
|
|
12
|
-
AttributeSchema,
|
|
13
|
-
GenericSchema,
|
|
14
|
-
NodeSchema,
|
|
15
|
-
RelationshipSchema,
|
|
16
|
-
SchemaRoot,
|
|
17
|
-
internal_schema,
|
|
18
|
-
)
|
|
12
|
+
from infrahub.core.schema import AttributeSchema, MainSchemaTypes, RelationshipSchema, SchemaRoot, internal_schema
|
|
19
13
|
from infrahub.core.timestamp import Timestamp
|
|
20
14
|
|
|
21
|
-
from .query import
|
|
15
|
+
from .query import MigrationBaseQuery # noqa: TC001
|
|
16
|
+
|
|
17
|
+
MIGRATION_LOG_TIME_FORMAT = "[%Y-%m-%d %H:%M:%S]"
|
|
18
|
+
_migration_console: Console | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_migration_console() -> Console:
|
|
22
|
+
global _migration_console
|
|
23
|
+
|
|
24
|
+
if _migration_console is None:
|
|
25
|
+
_migration_console = Console(log_time_format=MIGRATION_LOG_TIME_FORMAT)
|
|
26
|
+
|
|
27
|
+
return _migration_console
|
|
28
|
+
|
|
22
29
|
|
|
23
30
|
if TYPE_CHECKING:
|
|
24
31
|
from infrahub.core.branch import Branch
|
|
@@ -41,10 +48,12 @@ class MigrationResult(BaseModel):
|
|
|
41
48
|
class SchemaMigration(BaseModel):
|
|
42
49
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
43
50
|
name: str = Field(..., description="Name of the migration")
|
|
44
|
-
queries: Sequence[type[
|
|
51
|
+
queries: Sequence[type[MigrationBaseQuery]] = Field(
|
|
52
|
+
..., description="List of queries to execute for this migration"
|
|
53
|
+
)
|
|
45
54
|
|
|
46
|
-
new_node_schema:
|
|
47
|
-
previous_node_schema:
|
|
55
|
+
new_node_schema: MainSchemaTypes | None = None
|
|
56
|
+
previous_node_schema: MainSchemaTypes | None = None
|
|
48
57
|
schema_path: SchemaPath
|
|
49
58
|
|
|
50
59
|
async def execute_pre_queries(
|
|
@@ -66,9 +75,14 @@ class SchemaMigration(BaseModel):
|
|
|
66
75
|
return result
|
|
67
76
|
|
|
68
77
|
async def execute_queries(
|
|
69
|
-
self,
|
|
78
|
+
self,
|
|
79
|
+
db: InfrahubDatabase,
|
|
80
|
+
result: MigrationResult,
|
|
81
|
+
branch: Branch,
|
|
82
|
+
at: Timestamp,
|
|
83
|
+
queries: Sequence[type[MigrationBaseQuery]],
|
|
70
84
|
) -> MigrationResult:
|
|
71
|
-
for migration_query in
|
|
85
|
+
for migration_query in queries:
|
|
72
86
|
try:
|
|
73
87
|
query = await migration_query.init(db=db, branch=branch, at=at, migration=self)
|
|
74
88
|
await query.execute(db=db)
|
|
@@ -79,31 +93,40 @@ class SchemaMigration(BaseModel):
|
|
|
79
93
|
|
|
80
94
|
return result
|
|
81
95
|
|
|
82
|
-
async def execute(
|
|
96
|
+
async def execute(
|
|
97
|
+
self,
|
|
98
|
+
db: InfrahubDatabase,
|
|
99
|
+
branch: Branch,
|
|
100
|
+
at: Timestamp | str | None = None,
|
|
101
|
+
queries: Sequence[type[MigrationBaseQuery]] | None = None,
|
|
102
|
+
) -> MigrationResult:
|
|
83
103
|
async with db.start_transaction() as ts:
|
|
84
104
|
result = MigrationResult()
|
|
85
105
|
at = Timestamp(at)
|
|
86
106
|
|
|
87
107
|
await self.execute_pre_queries(db=ts, result=result, branch=branch, at=at)
|
|
88
|
-
|
|
108
|
+
queries_to_execute = queries or self.queries
|
|
109
|
+
await self.execute_queries(db=ts, result=result, branch=branch, at=at, queries=queries_to_execute)
|
|
89
110
|
await self.execute_post_queries(db=ts, result=result, branch=branch, at=at)
|
|
90
111
|
|
|
91
112
|
return result
|
|
92
113
|
|
|
93
114
|
@property
|
|
94
|
-
def new_schema(self) ->
|
|
115
|
+
def new_schema(self) -> MainSchemaTypes:
|
|
95
116
|
if self.new_node_schema:
|
|
96
117
|
return self.new_node_schema
|
|
97
118
|
raise ValueError("new_node_schema hasn't been initialized")
|
|
98
119
|
|
|
99
120
|
@property
|
|
100
|
-
def previous_schema(self) ->
|
|
121
|
+
def previous_schema(self) -> MainSchemaTypes:
|
|
101
122
|
if self.previous_node_schema:
|
|
102
123
|
return self.previous_node_schema
|
|
103
124
|
raise ValueError("previous_node_schema hasn't been initialized")
|
|
104
125
|
|
|
105
126
|
|
|
106
127
|
class AttributeSchemaMigration(SchemaMigration):
|
|
128
|
+
uuids: list[str] | None = None
|
|
129
|
+
|
|
107
130
|
@property
|
|
108
131
|
def new_attribute_schema(self) -> AttributeSchema:
|
|
109
132
|
if not self.schema_path.field_name:
|
|
@@ -215,3 +238,27 @@ class ArbitraryMigration(BaseModel):
|
|
|
215
238
|
|
|
216
239
|
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
217
240
|
raise NotImplementedError()
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class MigrationRequiringRebase(BaseModel):
|
|
244
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
245
|
+
name: str = Field(..., description="Name of the migration")
|
|
246
|
+
minimum_version: int = Field(..., description="Minimum version of the graph to execute this migration")
|
|
247
|
+
|
|
248
|
+
@classmethod
|
|
249
|
+
def init(cls, **kwargs: dict[str, Any]) -> Self:
|
|
250
|
+
return cls(**kwargs) # type: ignore[arg-type]
|
|
251
|
+
|
|
252
|
+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult:
|
|
253
|
+
raise NotImplementedError()
|
|
254
|
+
|
|
255
|
+
async def execute_against_branch(self, db: InfrahubDatabase, branch: Branch) -> MigrationResult:
|
|
256
|
+
"""Method that will be run against non-default branches, it assumes that the branches have been rebased."""
|
|
257
|
+
raise NotImplementedError()
|
|
258
|
+
|
|
259
|
+
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
260
|
+
"""Method that will be run against the default branch."""
|
|
261
|
+
raise NotImplementedError()
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
MigrationTypes: TypeAlias = GraphMigration | InternalSchemaMigration | ArbitraryMigration | MigrationRequiringRebase
|
infrahub/core/models.py
CHANGED
|
@@ -404,8 +404,8 @@ class HashableModelDiff(BaseModel):
|
|
|
404
404
|
class HashableModel(BaseModel):
|
|
405
405
|
model_config = ConfigDict(extra="forbid")
|
|
406
406
|
|
|
407
|
-
id: str | None = None
|
|
408
|
-
state: HashableModelState = HashableModelState.PRESENT
|
|
407
|
+
id: str | None = Field(default=None)
|
|
408
|
+
state: HashableModelState = Field(default=HashableModelState.PRESENT)
|
|
409
409
|
|
|
410
410
|
_exclude_from_hash: list[str] = []
|
|
411
411
|
_sort_by: list[str] = []
|
infrahub/core/node/__init__.py
CHANGED
|
@@ -42,10 +42,12 @@ from infrahub.types import ATTRIBUTE_TYPES
|
|
|
42
42
|
from ...graphql.constants import KIND_GRAPHQL_FIELD_NAME
|
|
43
43
|
from ...graphql.models import OrderModel
|
|
44
44
|
from ...log import get_logger
|
|
45
|
+
from ..attribute import BaseAttribute
|
|
45
46
|
from ..query.relationship import RelationshipDeleteAllQuery
|
|
46
47
|
from ..relationship import RelationshipManager
|
|
47
48
|
from ..utils import update_relationships_to
|
|
48
49
|
from .base import BaseNode, BaseNodeMeta, BaseNodeOptions
|
|
50
|
+
from .node_property_attribute import DisplayLabel, HumanFriendlyIdentifier
|
|
49
51
|
|
|
50
52
|
if TYPE_CHECKING:
|
|
51
53
|
from typing_extensions import Self
|
|
@@ -53,8 +55,6 @@ if TYPE_CHECKING:
|
|
|
53
55
|
from infrahub.core.branch import Branch
|
|
54
56
|
from infrahub.database import InfrahubDatabase
|
|
55
57
|
|
|
56
|
-
from ..attribute import BaseAttribute
|
|
57
|
-
|
|
58
58
|
SchemaProtocol = TypeVar("SchemaProtocol")
|
|
59
59
|
|
|
60
60
|
# ---------------------------------------------------------------------------------------
|
|
@@ -80,6 +80,29 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
80
80
|
_meta.default_filter = default_filter
|
|
81
81
|
super().__init_subclass_with_meta__(_meta=_meta, **options)
|
|
82
82
|
|
|
83
|
+
def __init__(self, schema: NodeSchema | ProfileSchema | TemplateSchema, branch: Branch, at: Timestamp):
|
|
84
|
+
self._schema: NodeSchema | ProfileSchema | TemplateSchema = schema
|
|
85
|
+
self._branch: Branch = branch
|
|
86
|
+
self._at: Timestamp = at
|
|
87
|
+
self._existing: bool = False
|
|
88
|
+
|
|
89
|
+
self._updated_at: Timestamp | None = None
|
|
90
|
+
self.id: str = None
|
|
91
|
+
self.db_id: str = None
|
|
92
|
+
|
|
93
|
+
self._source: Node | None = None
|
|
94
|
+
self._owner: Node | None = None
|
|
95
|
+
self._is_protected: bool = None
|
|
96
|
+
self._computed_jinja2_attributes: list[str] = []
|
|
97
|
+
|
|
98
|
+
self._display_label: DisplayLabel | None = None
|
|
99
|
+
self._human_friendly_id: HumanFriendlyIdentifier | None = None
|
|
100
|
+
|
|
101
|
+
# Lists of attributes and relationships names
|
|
102
|
+
self._attributes: list[str] = []
|
|
103
|
+
self._relationships: list[str] = []
|
|
104
|
+
self._node_changelog: NodeChangelog | None = None
|
|
105
|
+
|
|
83
106
|
def get_schema(self) -> NonGenericSchemaTypes:
|
|
84
107
|
return self._schema
|
|
85
108
|
|
|
@@ -100,16 +123,41 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
100
123
|
def get_updated_at(self) -> Timestamp | None:
|
|
101
124
|
return self._updated_at
|
|
102
125
|
|
|
126
|
+
def get_attribute(self, name: str) -> BaseAttribute:
|
|
127
|
+
attribute = getattr(self, name)
|
|
128
|
+
if not isinstance(attribute, BaseAttribute):
|
|
129
|
+
raise ValueError(f"{name} is not an attribute of {self.get_kind()}")
|
|
130
|
+
return attribute
|
|
131
|
+
|
|
132
|
+
def get_relationship(self, name: str) -> RelationshipManager:
|
|
133
|
+
relationship = getattr(self, name)
|
|
134
|
+
if not isinstance(relationship, RelationshipManager):
|
|
135
|
+
raise ValueError(f"{name} is not a relationship of {self.get_kind()}")
|
|
136
|
+
return relationship
|
|
137
|
+
|
|
138
|
+
def uses_profiles(self) -> bool:
|
|
139
|
+
for attr_name in self.get_schema().attribute_names:
|
|
140
|
+
try:
|
|
141
|
+
node_attr = self.get_attribute(attr_name)
|
|
142
|
+
except ValueError:
|
|
143
|
+
continue
|
|
144
|
+
if node_attr and node_attr.is_from_profile:
|
|
145
|
+
return True
|
|
146
|
+
return False
|
|
147
|
+
|
|
103
148
|
async def get_hfid(self, db: InfrahubDatabase, include_kind: bool = False) -> list[str] | None:
|
|
104
149
|
"""Return the Human friendly id of the node."""
|
|
105
150
|
if not self._schema.human_friendly_id:
|
|
106
151
|
return None
|
|
107
152
|
|
|
108
|
-
hfid_values
|
|
153
|
+
hfid_values: list[str] | None = None
|
|
154
|
+
if self._human_friendly_id:
|
|
155
|
+
hfid_values = self._human_friendly_id.get_value(node=self, at=self._at)
|
|
156
|
+
if not hfid_values:
|
|
157
|
+
hfid_values = [await self.get_path_value(db=db, path=item) for item in self._schema.human_friendly_id]
|
|
158
|
+
|
|
109
159
|
hfid = [value for value in hfid_values if value is not None]
|
|
110
|
-
if include_kind
|
|
111
|
-
return [self.get_kind()] + hfid
|
|
112
|
-
return hfid
|
|
160
|
+
return [self.get_kind()] + hfid if include_kind else hfid
|
|
113
161
|
|
|
114
162
|
async def get_hfid_as_string(self, db: InfrahubDatabase, include_kind: bool = False) -> str | None:
|
|
115
163
|
"""Return the Human friendly id of the node in string format separated with a dunder (__) ."""
|
|
@@ -118,6 +166,37 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
118
166
|
return None
|
|
119
167
|
return "__".join(hfid)
|
|
120
168
|
|
|
169
|
+
def has_human_friendly_id(self) -> bool:
|
|
170
|
+
return self._human_friendly_id is not None
|
|
171
|
+
|
|
172
|
+
async def add_human_friendly_id(self, db: InfrahubDatabase) -> None:
|
|
173
|
+
if not self._schema.human_friendly_id or self._human_friendly_id:
|
|
174
|
+
return
|
|
175
|
+
|
|
176
|
+
self._human_friendly_id = HumanFriendlyIdentifier(
|
|
177
|
+
node_schema=self._schema, template=self._schema.human_friendly_id
|
|
178
|
+
)
|
|
179
|
+
await self._human_friendly_id.compute(db=db, node=self)
|
|
180
|
+
|
|
181
|
+
async def get_display_label(self, db: InfrahubDatabase) -> str:
|
|
182
|
+
if self._display_label:
|
|
183
|
+
if isinstance(self._display_label._value, str):
|
|
184
|
+
return self._display_label._value
|
|
185
|
+
if self._display_label._value:
|
|
186
|
+
return self._display_label._value.value
|
|
187
|
+
|
|
188
|
+
return await self.render_display_label(db=db)
|
|
189
|
+
|
|
190
|
+
def has_display_label(self) -> bool:
|
|
191
|
+
return self._display_label is not None
|
|
192
|
+
|
|
193
|
+
async def add_display_label(self, db: InfrahubDatabase) -> None:
|
|
194
|
+
if not self._schema.display_label or self._display_label:
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
self._display_label = DisplayLabel(node_schema=self._schema, template=self._schema.display_label)
|
|
198
|
+
await self._display_label.compute(db=db, node=self)
|
|
199
|
+
|
|
121
200
|
async def get_path_value(self, db: InfrahubDatabase, path: str) -> str:
|
|
122
201
|
schema_path = self._schema.parse_schema_path(
|
|
123
202
|
path=path, schema=db.schema.get_schema_branch(name=self._branch.name)
|
|
@@ -176,30 +255,8 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
176
255
|
return self._branch
|
|
177
256
|
|
|
178
257
|
def __repr__(self) -> str:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return f"{self.get_kind()}(ID: {str(self.id)})"
|
|
183
|
-
|
|
184
|
-
def __init__(self, schema: NodeSchema | ProfileSchema | TemplateSchema, branch: Branch, at: Timestamp):
|
|
185
|
-
self._schema: NodeSchema | ProfileSchema | TemplateSchema = schema
|
|
186
|
-
self._branch: Branch = branch
|
|
187
|
-
self._at: Timestamp = at
|
|
188
|
-
self._existing: bool = False
|
|
189
|
-
|
|
190
|
-
self._updated_at: Timestamp | None = None
|
|
191
|
-
self.id: str = None
|
|
192
|
-
self.db_id: str = None
|
|
193
|
-
|
|
194
|
-
self._source: Node | None = None
|
|
195
|
-
self._owner: Node | None = None
|
|
196
|
-
self._is_protected: bool = None
|
|
197
|
-
self._computed_jinja2_attributes: list[str] = []
|
|
198
|
-
|
|
199
|
-
# Lists of attributes and relationships names
|
|
200
|
-
self._attributes: list[str] = []
|
|
201
|
-
self._relationships: list[str] = []
|
|
202
|
-
self._node_changelog: NodeChangelog | None = None
|
|
258
|
+
v = f"{self.get_kind()}(ID: {str(self.id)})"
|
|
259
|
+
return v if self._existing else f"{v}[NEW]"
|
|
203
260
|
|
|
204
261
|
@property
|
|
205
262
|
def node_changelog(self) -> NodeChangelog:
|
|
@@ -257,7 +314,9 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
257
314
|
|
|
258
315
|
return cls(**attrs)
|
|
259
316
|
|
|
260
|
-
async def handle_pool(
|
|
317
|
+
async def handle_pool(
|
|
318
|
+
self, db: InfrahubDatabase, attribute: BaseAttribute, errors: list, allocate_resources: bool = True
|
|
319
|
+
) -> None:
|
|
261
320
|
"""Evaluate if a resource has been requested from a pool and apply the resource
|
|
262
321
|
|
|
263
322
|
This method only works on number pools, currently Integer is the only type that has the from_pool
|
|
@@ -268,7 +327,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
268
327
|
attribute.from_pool = {"id": attribute.schema.parameters.number_pool_id}
|
|
269
328
|
attribute.is_default = False
|
|
270
329
|
|
|
271
|
-
if not attribute.from_pool:
|
|
330
|
+
if not attribute.from_pool or not allocate_resources:
|
|
272
331
|
return
|
|
273
332
|
|
|
274
333
|
try:
|
|
@@ -428,7 +487,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
428
487
|
elif relationship_peers := await relationship.get_peers(db=db):
|
|
429
488
|
fields[relationship_name] = [{"id": peer_id} for peer_id in relationship_peers]
|
|
430
489
|
|
|
431
|
-
async def _process_fields(self, fields: dict, db: InfrahubDatabase) -> None:
|
|
490
|
+
async def _process_fields(self, fields: dict, db: InfrahubDatabase, process_pools: bool = True) -> None:
|
|
432
491
|
errors = []
|
|
433
492
|
|
|
434
493
|
if "_source" in fields.keys():
|
|
@@ -482,7 +541,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
482
541
|
# Generate Attribute and Relationship and assign them
|
|
483
542
|
# -------------------------------------------
|
|
484
543
|
errors.extend(await self._process_fields_relationships(fields=fields, db=db))
|
|
485
|
-
errors.extend(await self._process_fields_attributes(fields=fields, db=db))
|
|
544
|
+
errors.extend(await self._process_fields_attributes(fields=fields, db=db, process_pools=process_pools))
|
|
486
545
|
|
|
487
546
|
if errors:
|
|
488
547
|
raise ValidationError(errors)
|
|
@@ -519,7 +578,9 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
519
578
|
|
|
520
579
|
return errors
|
|
521
580
|
|
|
522
|
-
async def _process_fields_attributes(
|
|
581
|
+
async def _process_fields_attributes(
|
|
582
|
+
self, fields: dict, db: InfrahubDatabase, process_pools: bool
|
|
583
|
+
) -> list[ValidationError]:
|
|
523
584
|
errors: list[ValidationError] = []
|
|
524
585
|
|
|
525
586
|
for attr_schema in self._schema.attributes:
|
|
@@ -544,9 +605,10 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
544
605
|
)
|
|
545
606
|
if not self._existing:
|
|
546
607
|
attribute: BaseAttribute = getattr(self, attr_schema.name)
|
|
547
|
-
await self.handle_pool(db=db, attribute=attribute, errors=errors)
|
|
608
|
+
await self.handle_pool(db=db, attribute=attribute, errors=errors, allocate_resources=process_pools)
|
|
548
609
|
|
|
549
|
-
|
|
610
|
+
if process_pools or attribute.from_pool is None:
|
|
611
|
+
attribute.validate(value=attribute.value, name=attribute.name, schema=attribute.schema)
|
|
550
612
|
except ValidationError as exc:
|
|
551
613
|
errors.append(exc)
|
|
552
614
|
|
|
@@ -674,7 +736,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
674
736
|
self.label.value = " ".join([word.title() for word in self.name.value.split("_")])
|
|
675
737
|
self.label.is_default = False
|
|
676
738
|
|
|
677
|
-
async def new(self, db: InfrahubDatabase, id: str | None = None, **kwargs: Any) -> Self:
|
|
739
|
+
async def new(self, db: InfrahubDatabase, id: str | None = None, process_pools: bool = True, **kwargs: Any) -> Self:
|
|
678
740
|
if id and not is_valid_uuid(id):
|
|
679
741
|
raise ValidationError({"id": f"{id} is not a valid UUID"})
|
|
680
742
|
if id:
|
|
@@ -684,15 +746,40 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
684
746
|
|
|
685
747
|
self.id = id or str(UUIDT())
|
|
686
748
|
|
|
687
|
-
await self._process_fields(db=db, fields=kwargs)
|
|
749
|
+
await self._process_fields(db=db, fields=kwargs, process_pools=process_pools)
|
|
688
750
|
await self._process_macros(db=db)
|
|
689
751
|
|
|
690
752
|
return self
|
|
691
753
|
|
|
692
754
|
async def resolve_relationships(self, db: InfrahubDatabase) -> None:
|
|
755
|
+
extra_filters: dict[str, set[str]] = {}
|
|
756
|
+
|
|
757
|
+
if not self._existing:
|
|
758
|
+
# If we are creating a new node, we need to resolve extra filters from HFID and Display Labels,
|
|
759
|
+
# if we don't do this the fields might be blank
|
|
760
|
+
schema_branch = db.schema.get_schema_branch(name=self.get_branch_based_on_support_type().name)
|
|
761
|
+
try:
|
|
762
|
+
hfid_identifier = schema_branch.hfids.get_node_definition(kind=self._schema.kind)
|
|
763
|
+
for rel_name, attrs in hfid_identifier.relationship_fields.items():
|
|
764
|
+
extra_filters.setdefault(rel_name, set()).update(attrs)
|
|
765
|
+
except KeyError:
|
|
766
|
+
# No HFID defined for this kind
|
|
767
|
+
...
|
|
768
|
+
try:
|
|
769
|
+
display_label_identifier = schema_branch.display_labels.get_template_node(kind=self._schema.kind)
|
|
770
|
+
for rel_name, attrs in display_label_identifier.relationship_fields.items():
|
|
771
|
+
extra_filters.setdefault(rel_name, set()).update(attrs)
|
|
772
|
+
except KeyError:
|
|
773
|
+
# No Display Label defined for this kind
|
|
774
|
+
...
|
|
775
|
+
|
|
693
776
|
for name in self._relationships:
|
|
694
777
|
relm: RelationshipManager = getattr(self, name)
|
|
695
|
-
|
|
778
|
+
query_filter = []
|
|
779
|
+
if name in extra_filters:
|
|
780
|
+
query_filter.extend(list(extra_filters[name]))
|
|
781
|
+
|
|
782
|
+
await relm.resolve(db=db, fields=query_filter)
|
|
696
783
|
|
|
697
784
|
async def load(
|
|
698
785
|
self,
|
|
@@ -712,12 +799,26 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
712
799
|
)
|
|
713
800
|
self._updated_at = Timestamp(updated_at)
|
|
714
801
|
|
|
802
|
+
if not self._schema.is_schema_node:
|
|
803
|
+
if hfid := kwargs.pop("human_friendly_id", None):
|
|
804
|
+
self._human_friendly_id = HumanFriendlyIdentifier(
|
|
805
|
+
node_schema=self._schema, template=self._schema.human_friendly_id, value=hfid
|
|
806
|
+
)
|
|
807
|
+
if display_label := kwargs.pop("display_label", None):
|
|
808
|
+
self._display_label = DisplayLabel(
|
|
809
|
+
node_schema=self._schema, template=self._schema.display_label, value=display_label
|
|
810
|
+
)
|
|
811
|
+
|
|
715
812
|
await self._process_fields(db=db, fields=kwargs)
|
|
716
813
|
return self
|
|
717
814
|
|
|
718
815
|
async def _create(self, db: InfrahubDatabase, at: Timestamp | None = None) -> NodeChangelog:
|
|
719
816
|
create_at = Timestamp(at)
|
|
720
817
|
|
|
818
|
+
if not self._schema.is_schema_node:
|
|
819
|
+
await self.add_human_friendly_id(db=db)
|
|
820
|
+
await self.add_display_label(db=db)
|
|
821
|
+
|
|
721
822
|
query = await NodeCreateAllQuery.init(db=db, node=self, at=create_at)
|
|
722
823
|
await query.execute(db=db)
|
|
723
824
|
|
|
@@ -729,6 +830,13 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
729
830
|
new_ids = query.get_ids()
|
|
730
831
|
node_changelog = NodeChangelog(node_id=self.get_id(), node_kind=self.get_kind(), display_label="")
|
|
731
832
|
|
|
833
|
+
if self._human_friendly_id:
|
|
834
|
+
node_changelog.create_attribute(
|
|
835
|
+
attribute=self._human_friendly_id.get_node_attribute(node=self, at=create_at)
|
|
836
|
+
)
|
|
837
|
+
if self._display_label:
|
|
838
|
+
node_changelog.create_attribute(attribute=self._display_label.get_node_attribute(node=self, at=create_at))
|
|
839
|
+
|
|
732
840
|
# Go over the list of Attribute and assign the new IDs one by one
|
|
733
841
|
for name in self._attributes:
|
|
734
842
|
attr: BaseAttribute = getattr(self, name)
|
|
@@ -741,12 +849,10 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
741
849
|
relm: RelationshipManager = getattr(self, name)
|
|
742
850
|
for rel in relm._relationships:
|
|
743
851
|
identifier = f"{rel.schema.identifier}::{rel.peer_id}"
|
|
744
|
-
|
|
745
852
|
rel.id, rel.db_id = new_ids[identifier]
|
|
746
|
-
|
|
747
853
|
node_changelog.create_relationship(relationship=rel)
|
|
748
854
|
|
|
749
|
-
node_changelog.display_label = await self.
|
|
855
|
+
node_changelog.display_label = await self.get_display_label(db=db)
|
|
750
856
|
return node_changelog
|
|
751
857
|
|
|
752
858
|
async def _update(
|
|
@@ -782,19 +888,41 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
782
888
|
if parent := await rel.get_parent(db=db):
|
|
783
889
|
node_changelog.add_parent_from_relationship(parent=parent)
|
|
784
890
|
|
|
785
|
-
|
|
891
|
+
# Update the HFID if one of its variables is being updated
|
|
892
|
+
if self._human_friendly_id and (
|
|
893
|
+
(fields and "human_friendly_id" in fields) or self._human_friendly_id.needs_update(fields=fields)
|
|
894
|
+
):
|
|
895
|
+
await self._human_friendly_id.compute(db=db, node=self)
|
|
896
|
+
updated_attribute = await self._human_friendly_id.get_node_attribute(node=self, at=update_at).save(
|
|
897
|
+
at=update_at, db=db
|
|
898
|
+
)
|
|
899
|
+
if updated_attribute:
|
|
900
|
+
node_changelog.add_attribute(attribute=updated_attribute)
|
|
901
|
+
|
|
902
|
+
# Update the display label if one of its variables is being updated
|
|
903
|
+
if self._display_label and (
|
|
904
|
+
(fields and "display_label" in fields) or self._display_label.needs_update(fields=fields)
|
|
905
|
+
):
|
|
906
|
+
await self._display_label.compute(db=db, node=self)
|
|
907
|
+
self._display_label.get_node_attribute(node=self, at=update_at).get_create_data(node_schema=self._schema)
|
|
908
|
+
updated_attribute = await self._display_label.get_node_attribute(node=self, at=update_at).save(
|
|
909
|
+
at=update_at, db=db
|
|
910
|
+
)
|
|
911
|
+
if updated_attribute:
|
|
912
|
+
node_changelog.add_attribute(attribute=updated_attribute)
|
|
913
|
+
|
|
914
|
+
node_changelog.display_label = await self.get_display_label(db=db)
|
|
786
915
|
return node_changelog
|
|
787
916
|
|
|
788
917
|
async def save(self, db: InfrahubDatabase, at: Timestamp | None = None, fields: list[str] | None = None) -> Self:
|
|
789
918
|
"""Create or Update the Node in the database."""
|
|
790
|
-
|
|
791
919
|
save_at = Timestamp(at)
|
|
792
920
|
|
|
793
921
|
if self._existing:
|
|
794
922
|
self._node_changelog = await self._update(at=save_at, db=db, fields=fields)
|
|
795
|
-
|
|
923
|
+
else:
|
|
924
|
+
self._node_changelog = await self._create(at=save_at, db=db)
|
|
796
925
|
|
|
797
|
-
self._node_changelog = await self._create(at=save_at, db=db)
|
|
798
926
|
return self
|
|
799
927
|
|
|
800
928
|
async def delete(self, db: InfrahubDatabase, at: Timestamp | None = None) -> None:
|
|
@@ -803,13 +931,24 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
803
931
|
delete_at = Timestamp(at)
|
|
804
932
|
|
|
805
933
|
node_changelog = NodeChangelog(
|
|
806
|
-
node_id=self.get_id(), node_kind=self.get_kind(), display_label=await self.
|
|
934
|
+
node_id=self.get_id(), node_kind=self.get_kind(), display_label=await self.get_display_label(db=db)
|
|
807
935
|
)
|
|
808
936
|
# Go over the list of Attribute and update them one by one
|
|
809
937
|
for name in self._attributes:
|
|
810
938
|
attr: BaseAttribute = getattr(self, name)
|
|
811
|
-
deleted_attribute
|
|
812
|
-
|
|
939
|
+
if deleted_attribute := await attr.delete(at=delete_at, db=db):
|
|
940
|
+
node_changelog.add_attribute(attribute=deleted_attribute)
|
|
941
|
+
|
|
942
|
+
if self._human_friendly_id:
|
|
943
|
+
if deleted_attribute := await self._human_friendly_id.get_node_attribute(node=self, at=delete_at).delete(
|
|
944
|
+
at=delete_at, db=db
|
|
945
|
+
):
|
|
946
|
+
node_changelog.add_attribute(attribute=deleted_attribute)
|
|
947
|
+
|
|
948
|
+
if self._display_label:
|
|
949
|
+
if deleted_attribute := await self._display_label.get_node_attribute(node=self, at=delete_at).delete(
|
|
950
|
+
at=delete_at, db=db
|
|
951
|
+
):
|
|
813
952
|
node_changelog.add_attribute(attribute=deleted_attribute)
|
|
814
953
|
|
|
815
954
|
branch = self.get_branch_based_on_support_type()
|
|
@@ -877,7 +1016,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
877
1016
|
continue
|
|
878
1017
|
|
|
879
1018
|
if field_name == "display_label":
|
|
880
|
-
response[field_name] = await self.
|
|
1019
|
+
response[field_name] = await self.get_display_label(db=db)
|
|
881
1020
|
continue
|
|
882
1021
|
|
|
883
1022
|
if field_name == "hfid":
|
|
@@ -937,7 +1076,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
937
1076
|
|
|
938
1077
|
return response
|
|
939
1078
|
|
|
940
|
-
async def from_graphql(self, data: dict, db: InfrahubDatabase) -> bool:
|
|
1079
|
+
async def from_graphql(self, data: dict, db: InfrahubDatabase, process_pools: bool = True) -> bool:
|
|
941
1080
|
"""Update object from a GraphQL payload."""
|
|
942
1081
|
|
|
943
1082
|
changed = False
|
|
@@ -945,7 +1084,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
945
1084
|
for key, value in data.items():
|
|
946
1085
|
if key in self._attributes and isinstance(value, dict):
|
|
947
1086
|
attribute = getattr(self, key)
|
|
948
|
-
changed |= await attribute.from_graphql(data=value, db=db)
|
|
1087
|
+
changed |= await attribute.from_graphql(data=value, db=db, process_pools=process_pools)
|
|
949
1088
|
|
|
950
1089
|
if key in self._relationships:
|
|
951
1090
|
rel: RelationshipManager = getattr(self, key)
|
|
@@ -980,6 +1119,20 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
980
1119
|
return repr(self)
|
|
981
1120
|
return display_label.strip()
|
|
982
1121
|
|
|
1122
|
+
async def set_human_friendly_id(self, value: list[str] | None) -> None:
|
|
1123
|
+
"""Set the human friendly ID of this node if one is set. `save()` must be called to commit the change in the database."""
|
|
1124
|
+
if self._human_friendly_id is None:
|
|
1125
|
+
return
|
|
1126
|
+
|
|
1127
|
+
self._human_friendly_id.set_value(value=value, manually_assigned=True)
|
|
1128
|
+
|
|
1129
|
+
async def set_display_label(self, value: str | None) -> None:
|
|
1130
|
+
"""Set the display label of this node if one is set. `save()` must be called to commit the change in the database."""
|
|
1131
|
+
if self._display_label is None:
|
|
1132
|
+
return
|
|
1133
|
+
|
|
1134
|
+
self._display_label.set_value(value=value, manually_assigned=True)
|
|
1135
|
+
|
|
983
1136
|
def _get_parent_relationship_name(self) -> str | None:
|
|
984
1137
|
"""Return the name of the parent relationship is one is present"""
|
|
985
1138
|
for relationship in self._schema.relationships:
|
|
@@ -989,7 +1142,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
989
1142
|
return None
|
|
990
1143
|
|
|
991
1144
|
async def get_object_template(self, db: InfrahubDatabase) -> CoreObjectTemplate | None:
|
|
992
|
-
object_template: RelationshipManager = getattr(self, OBJECT_TEMPLATE_RELATIONSHIP_NAME, None)
|
|
1145
|
+
object_template: RelationshipManager | None = getattr(self, OBJECT_TEMPLATE_RELATIONSHIP_NAME, None)
|
|
993
1146
|
return (
|
|
994
1147
|
await object_template.get_peer(db=db, peer_type=CoreObjectTemplate) if object_template is not None else None
|
|
995
1148
|
)
|