infrahub-server 1.3.8__py3-none-any.whl → 1.4.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/api/internal.py +5 -0
- infrahub/artifacts/tasks.py +17 -22
- infrahub/branch/merge_mutation_checker.py +38 -0
- infrahub/cli/__init__.py +2 -2
- infrahub/cli/context.py +7 -3
- infrahub/cli/db.py +5 -16
- infrahub/cli/upgrade.py +10 -29
- infrahub/computed_attribute/tasks.py +36 -46
- infrahub/config.py +57 -6
- infrahub/constants/environment.py +1 -0
- infrahub/core/attribute.py +15 -7
- infrahub/core/branch/tasks.py +43 -41
- infrahub/core/constants/__init__.py +21 -6
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/diff/coordinator.py +3 -1
- infrahub/core/diff/repository/repository.py +0 -8
- infrahub/core/diff/tasks.py +11 -8
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/index.py +1 -2
- infrahub/core/graph/schema.py +50 -29
- infrahub/core/initialization.py +81 -47
- infrahub/core/ipam/tasks.py +4 -3
- infrahub/core/merge.py +8 -10
- infrahub/core/migrations/__init__.py +2 -0
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m036_drop_attr_value_index.py +45 -0
- infrahub/core/migrations/graph/m037_index_attr_vals.py +577 -0
- infrahub/core/migrations/query/attribute_add.py +27 -2
- infrahub/core/migrations/schema/attribute_kind_update.py +156 -0
- infrahub/core/migrations/schema/tasks.py +6 -5
- infrahub/core/models.py +5 -1
- infrahub/core/node/proposed_change.py +43 -0
- infrahub/core/protocols.py +12 -0
- infrahub/core/query/attribute.py +32 -14
- infrahub/core/query/diff.py +11 -0
- infrahub/core/query/ipam.py +13 -7
- infrahub/core/query/node.py +51 -10
- infrahub/core/query/resource_manager.py +3 -3
- infrahub/core/schema/basenode_schema.py +8 -0
- infrahub/core/schema/definitions/core/__init__.py +10 -1
- infrahub/core/schema/definitions/core/ipam.py +28 -2
- infrahub/core/schema/definitions/core/propose_change.py +15 -0
- infrahub/core/schema/definitions/core/webhook.py +3 -0
- infrahub/core/schema/definitions/internal.py +1 -1
- infrahub/core/schema/generated/attribute_schema.py +1 -1
- infrahub/core/schema/generic_schema.py +10 -0
- infrahub/core/schema/manager.py +10 -1
- infrahub/core/schema/node_schema.py +22 -17
- infrahub/core/schema/profile_schema.py +8 -0
- infrahub/core/schema/schema_branch.py +9 -5
- infrahub/core/schema/template_schema.py +8 -0
- infrahub/core/validators/attribute/kind.py +5 -1
- infrahub/core/validators/checks_runner.py +5 -5
- infrahub/core/validators/determiner.py +22 -2
- infrahub/core/validators/tasks.py +6 -7
- infrahub/core/validators/uniqueness/checker.py +4 -2
- infrahub/core/validators/uniqueness/model.py +1 -0
- infrahub/core/validators/uniqueness/query.py +57 -7
- infrahub/database/__init__.py +2 -1
- infrahub/events/__init__.py +20 -0
- infrahub/events/constants.py +7 -0
- infrahub/events/generator.py +29 -2
- infrahub/events/proposed_change_action.py +203 -0
- infrahub/generators/tasks.py +24 -20
- infrahub/git/base.py +4 -7
- infrahub/git/integrator.py +21 -12
- infrahub/git/repository.py +15 -30
- infrahub/git/tasks.py +121 -106
- infrahub/graphql/field_extractor.py +69 -0
- infrahub/graphql/manager.py +15 -11
- infrahub/graphql/mutations/account.py +2 -2
- infrahub/graphql/mutations/action.py +8 -2
- infrahub/graphql/mutations/artifact_definition.py +4 -1
- infrahub/graphql/mutations/branch.py +10 -5
- infrahub/graphql/mutations/graphql_query.py +2 -1
- infrahub/graphql/mutations/main.py +14 -8
- infrahub/graphql/mutations/menu.py +2 -1
- infrahub/graphql/mutations/proposed_change.py +230 -8
- infrahub/graphql/mutations/relationship.py +5 -0
- infrahub/graphql/mutations/repository.py +2 -1
- infrahub/graphql/mutations/tasks.py +7 -9
- infrahub/graphql/mutations/webhook.py +4 -1
- infrahub/graphql/parser.py +15 -6
- infrahub/graphql/queries/__init__.py +10 -1
- infrahub/graphql/queries/account.py +3 -3
- infrahub/graphql/queries/branch.py +2 -2
- infrahub/graphql/queries/diff/tree.py +3 -3
- infrahub/graphql/queries/event.py +13 -3
- infrahub/graphql/queries/ipam.py +23 -1
- infrahub/graphql/queries/proposed_change.py +84 -0
- infrahub/graphql/queries/relationship.py +2 -2
- infrahub/graphql/queries/resource_manager.py +3 -3
- infrahub/graphql/queries/search.py +3 -2
- infrahub/graphql/queries/status.py +3 -2
- infrahub/graphql/queries/task.py +2 -2
- infrahub/graphql/resolvers/ipam.py +440 -0
- infrahub/graphql/resolvers/many_relationship.py +4 -3
- infrahub/graphql/resolvers/resolver.py +5 -5
- infrahub/graphql/resolvers/single_relationship.py +3 -2
- infrahub/graphql/schema.py +25 -5
- infrahub/graphql/types/__init__.py +2 -2
- infrahub/graphql/types/attribute.py +3 -3
- infrahub/graphql/types/event.py +68 -0
- infrahub/groups/tasks.py +6 -6
- infrahub/lock.py +3 -2
- infrahub/menu/generator.py +8 -0
- infrahub/message_bus/operations/__init__.py +9 -12
- infrahub/message_bus/operations/git/file.py +6 -5
- infrahub/message_bus/operations/git/repository.py +12 -20
- infrahub/message_bus/operations/refresh/registry.py +15 -9
- infrahub/message_bus/operations/send/echo.py +7 -4
- infrahub/message_bus/types.py +1 -0
- infrahub/permissions/__init__.py +2 -1
- infrahub/permissions/constants.py +13 -0
- infrahub/permissions/globals.py +31 -2
- infrahub/permissions/manager.py +8 -5
- infrahub/pools/prefix.py +7 -5
- infrahub/prefect_server/app.py +31 -0
- infrahub/prefect_server/bootstrap.py +18 -0
- infrahub/proposed_change/action_checker.py +206 -0
- infrahub/proposed_change/approval_revoker.py +40 -0
- infrahub/proposed_change/branch_diff.py +3 -1
- infrahub/proposed_change/checker.py +45 -0
- infrahub/proposed_change/constants.py +32 -2
- infrahub/proposed_change/tasks.py +182 -150
- infrahub/py.typed +0 -0
- infrahub/server.py +29 -17
- infrahub/services/__init__.py +13 -28
- infrahub/services/adapters/cache/__init__.py +4 -0
- infrahub/services/adapters/cache/nats.py +2 -0
- infrahub/services/adapters/cache/redis.py +3 -0
- infrahub/services/adapters/message_bus/__init__.py +0 -2
- infrahub/services/adapters/message_bus/local.py +1 -2
- infrahub/services/adapters/message_bus/nats.py +6 -8
- infrahub/services/adapters/message_bus/rabbitmq.py +7 -9
- infrahub/services/adapters/workflow/__init__.py +1 -0
- infrahub/services/adapters/workflow/local.py +1 -8
- infrahub/services/component.py +2 -1
- infrahub/task_manager/event.py +56 -0
- infrahub/task_manager/models.py +9 -0
- infrahub/tasks/artifact.py +6 -7
- infrahub/tasks/check.py +4 -7
- infrahub/telemetry/tasks.py +15 -18
- infrahub/transformations/tasks.py +10 -6
- infrahub/trigger/tasks.py +4 -3
- infrahub/types.py +4 -0
- infrahub/validators/events.py +7 -7
- infrahub/validators/tasks.py +6 -7
- infrahub/webhook/models.py +45 -45
- infrahub/webhook/tasks.py +25 -24
- infrahub/workers/dependencies.py +143 -0
- infrahub/workers/infrahub_async.py +19 -43
- infrahub/workflows/catalogue.py +16 -2
- infrahub/workflows/initialization.py +5 -4
- infrahub/workflows/models.py +2 -0
- infrahub_sdk/client.py +2 -2
- infrahub_sdk/ctl/repository.py +51 -0
- infrahub_sdk/ctl/schema.py +9 -9
- infrahub_sdk/node/node.py +2 -2
- infrahub_sdk/pytest_plugin/items/graphql_query.py +1 -1
- infrahub_sdk/schema/repository.py +1 -1
- infrahub_sdk/testing/docker.py +1 -1
- infrahub_sdk/utils.py +2 -2
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/METADATA +7 -5
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/RECORD +172 -156
- infrahub_testcontainers/container.py +17 -0
- infrahub_testcontainers/docker-compose-cluster.test.yml +56 -1
- infrahub_testcontainers/docker-compose.test.yml +56 -1
- infrahub_testcontainers/helpers.py +4 -1
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Sequence
|
|
4
|
+
|
|
5
|
+
from infrahub.types import is_large_attribute_type
|
|
6
|
+
|
|
7
|
+
from ..query import AttributeMigrationQuery
|
|
8
|
+
from ..shared import AttributeSchemaMigration, MigrationResult
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from infrahub.core.branch.models import Branch
|
|
12
|
+
from infrahub.core.timestamp import Timestamp
|
|
13
|
+
from infrahub.database import InfrahubDatabase
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AttributeKindUpdateMigrationQuery(AttributeMigrationQuery):
|
|
17
|
+
name = "migration_attribute_kind"
|
|
18
|
+
insert_return = False
|
|
19
|
+
|
|
20
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
21
|
+
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at)
|
|
22
|
+
self.params.update(branch_params)
|
|
23
|
+
needs_index = not is_large_attribute_type(self.migration.new_attribute_schema.kind)
|
|
24
|
+
self.params["needs_index"] = needs_index
|
|
25
|
+
self.params["branch"] = self.branch.name
|
|
26
|
+
self.params["branch_level"] = self.branch.hierarchy_level
|
|
27
|
+
self.params["at"] = self.at.to_string()
|
|
28
|
+
self.params["attr_name"] = self.migration.previous_attribute_schema.name
|
|
29
|
+
new_attr_value_labels = "AttributeValue"
|
|
30
|
+
if needs_index:
|
|
31
|
+
new_attr_value_labels += ":AttributeValueIndexed"
|
|
32
|
+
# ruff: noqa: S608
|
|
33
|
+
query = """
|
|
34
|
+
// ------------
|
|
35
|
+
// start with all the Attribute vertices we might care about
|
|
36
|
+
// ------------
|
|
37
|
+
MATCH (n:%(schema_kind)s)-[:HAS_ATTRIBUTE]->(attr:Attribute)
|
|
38
|
+
WHERE attr.name = $attr_name
|
|
39
|
+
WITH DISTINCT n, attr
|
|
40
|
+
|
|
41
|
+
// ------------
|
|
42
|
+
// for each Attribute, find the most recent active edge and AttributeValue vertex that needs to be [un]indexed
|
|
43
|
+
// ------------
|
|
44
|
+
CALL (n, attr) {
|
|
45
|
+
MATCH (n)-[r1:HAS_ATTRIBUTE]->(attr:Attribute)-[r2:HAS_VALUE]->(av)
|
|
46
|
+
WHERE all(r IN [r1, r2] WHERE %(branch_filter)s)
|
|
47
|
+
WITH r2, av, r1.status = "active" AND r2.status = "active" AS is_active
|
|
48
|
+
ORDER BY r2.branch_level DESC, r2.from DESC, r2.status = "active" DESC, r1.branch_level DESC, r1.from DESC, r1.status = "active" DESC
|
|
49
|
+
LIMIT 1
|
|
50
|
+
WITH r2 AS has_value_e, av, "AttributeValueIndexed" IN labels(av) AS is_indexed
|
|
51
|
+
WHERE is_active AND is_indexed <> $needs_index
|
|
52
|
+
RETURN has_value_e, av
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ------------
|
|
56
|
+
// check if the correct AttributeValue vertex to use exists
|
|
57
|
+
// create it if not
|
|
58
|
+
// ------------
|
|
59
|
+
WITH DISTINCT av.is_default AS av_is_default, av.value AS av_value
|
|
60
|
+
CALL (av_is_default, av_value) {
|
|
61
|
+
OPTIONAL MATCH (existing_av:AttributeValue {is_default: av_is_default, value: av_value})
|
|
62
|
+
WHERE "AttributeValueIndexed" IN labels(existing_av) = $needs_index
|
|
63
|
+
WITH existing_av WHERE existing_av IS NULL
|
|
64
|
+
LIMIT 1
|
|
65
|
+
CREATE (:%(new_attr_value_labels)s {is_default: av_is_default, value: av_value})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ------------
|
|
69
|
+
// get all the AttributeValue vertices that need to be updated again and run the updates
|
|
70
|
+
// ------------
|
|
71
|
+
WITH 1 AS one
|
|
72
|
+
LIMIT 1
|
|
73
|
+
MATCH (n:%(schema_kind)s)-[:HAS_ATTRIBUTE]->(attr:Attribute)
|
|
74
|
+
WHERE attr.name = $attr_name
|
|
75
|
+
WITH DISTINCT n, attr
|
|
76
|
+
|
|
77
|
+
// ------------
|
|
78
|
+
// for each Attribute, find the most recent active edge and AttributeValue vertex that needs to be [un]indexed
|
|
79
|
+
// ------------
|
|
80
|
+
CALL (n, attr) {
|
|
81
|
+
MATCH (n)-[r1:HAS_ATTRIBUTE]->(attr:Attribute)-[r2:HAS_VALUE]->(av)
|
|
82
|
+
WHERE all(r IN [r1, r2] WHERE %(branch_filter)s)
|
|
83
|
+
WITH r2, av, r1.status = "active" AND r2.status = "active" AS is_active
|
|
84
|
+
ORDER BY r2.branch_level DESC, r2.from DESC, r2.status = "active" DESC, r1.branch_level DESC, r1.from DESC, r1.status = "active" DESC
|
|
85
|
+
LIMIT 1
|
|
86
|
+
WITH r2 AS has_value_e, av, "AttributeValueIndexed" IN labels(av) AS is_indexed
|
|
87
|
+
WHERE is_active AND is_indexed <> $needs_index
|
|
88
|
+
RETURN has_value_e, av
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
// ------------
|
|
93
|
+
// create and update the HAS_VALUE edges
|
|
94
|
+
// ------------
|
|
95
|
+
CALL (attr, has_value_e, av) {
|
|
96
|
+
// ------------
|
|
97
|
+
// get the correct AttributeValue vertex b/c it definitely exists now
|
|
98
|
+
// ------------
|
|
99
|
+
MATCH (new_av:%(new_attr_value_labels)s {is_default: av.is_default, value: av.value})
|
|
100
|
+
WHERE "AttributeValueIndexed" IN labels(new_av) = $needs_index
|
|
101
|
+
LIMIT 1
|
|
102
|
+
|
|
103
|
+
// ------------
|
|
104
|
+
// create the new HAS_VALUE edge
|
|
105
|
+
// ------------
|
|
106
|
+
CREATE (attr)-[new_has_value_e:HAS_VALUE]->(new_av)
|
|
107
|
+
SET new_has_value_e = properties(has_value_e)
|
|
108
|
+
SET new_has_value_e.status = "active"
|
|
109
|
+
SET new_has_value_e.branch = $branch
|
|
110
|
+
SET new_has_value_e.branch_level = $branch_level
|
|
111
|
+
SET new_has_value_e.from = $at
|
|
112
|
+
SET new_has_value_e.to = NULL
|
|
113
|
+
|
|
114
|
+
// ------------
|
|
115
|
+
// if we are updating on a branch and the existing edge is on the default branch,
|
|
116
|
+
// then create a new deleted edge on this branch
|
|
117
|
+
// ------------
|
|
118
|
+
WITH attr, has_value_e, av
|
|
119
|
+
WHERE has_value_e.branch <> $branch
|
|
120
|
+
CREATE (attr)-[deleted_has_value_e:HAS_VALUE]->(av)
|
|
121
|
+
SET deleted_has_value_e = properties(has_value_e)
|
|
122
|
+
SET deleted_has_value_e.status = "deleted"
|
|
123
|
+
SET deleted_has_value_e.branch = $branch
|
|
124
|
+
SET deleted_has_value_e.branch_level = $branch_level
|
|
125
|
+
SET deleted_has_value_e.from = $at
|
|
126
|
+
SET deleted_has_value_e.to = NULL
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ------------
|
|
130
|
+
// if the existing edge is on the same branch as the update,
|
|
131
|
+
// then set its "to" time
|
|
132
|
+
// ------------
|
|
133
|
+
CALL (has_value_e) {
|
|
134
|
+
WITH has_value_e
|
|
135
|
+
WHERE has_value_e.branch = $branch
|
|
136
|
+
SET has_value_e.to = $at
|
|
137
|
+
}
|
|
138
|
+
""" % {
|
|
139
|
+
"schema_kind": self.migration.previous_schema.kind,
|
|
140
|
+
"branch_filter": branch_filter,
|
|
141
|
+
"new_attr_value_labels": new_attr_value_labels,
|
|
142
|
+
}
|
|
143
|
+
self.add_to_query(query)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class AttributeKindUpdateMigration(AttributeSchemaMigration):
|
|
147
|
+
name: str = "attribute.kind.update"
|
|
148
|
+
queries: Sequence[type[AttributeMigrationQuery]] = [AttributeKindUpdateMigrationQuery] # type: ignore[assignment]
|
|
149
|
+
|
|
150
|
+
async def execute(self, db: InfrahubDatabase, branch: Branch, at: Timestamp | str | None = None) -> MigrationResult:
|
|
151
|
+
is_indexed_previous = is_large_attribute_type(self.previous_attribute_schema.kind)
|
|
152
|
+
is_indexed_new = is_large_attribute_type(self.new_attribute_schema.kind)
|
|
153
|
+
if is_indexed_previous is is_indexed_new:
|
|
154
|
+
return MigrationResult()
|
|
155
|
+
|
|
156
|
+
return await super().execute(db=db, branch=branch, at=at)
|
|
@@ -10,17 +10,18 @@ from prefect.logging import get_run_logger
|
|
|
10
10
|
from infrahub.core.branch import Branch # noqa: TC001
|
|
11
11
|
from infrahub.core.migrations import MIGRATION_MAP
|
|
12
12
|
from infrahub.core.path import SchemaPath # noqa: TC001
|
|
13
|
-
from infrahub.
|
|
13
|
+
from infrahub.workers.dependencies import get_database
|
|
14
14
|
from infrahub.workflows.utils import add_branch_tag
|
|
15
15
|
|
|
16
16
|
from .models import SchemaApplyMigrationData, SchemaMigrationPathResponseData
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
19
19
|
from infrahub.core.schema import MainSchemaTypes
|
|
20
|
+
from infrahub.database import InfrahubDatabase
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
@flow(name="schema_apply_migrations", flow_run_name="Apply schema migrations", persist_result=True)
|
|
23
|
-
async def schema_apply_migrations(message: SchemaApplyMigrationData
|
|
24
|
+
async def schema_apply_migrations(message: SchemaApplyMigrationData) -> list[str]:
|
|
24
25
|
await add_branch_tag(branch_name=message.branch.name)
|
|
25
26
|
log = get_run_logger()
|
|
26
27
|
|
|
@@ -55,7 +56,7 @@ async def schema_apply_migrations(message: SchemaApplyMigrationData, service: In
|
|
|
55
56
|
new_node_schema=new_node_schema,
|
|
56
57
|
previous_node_schema=previous_node_schema,
|
|
57
58
|
schema_path=migration.path,
|
|
58
|
-
|
|
59
|
+
database=await get_database(),
|
|
59
60
|
)
|
|
60
61
|
|
|
61
62
|
async for _, result in batch.execute():
|
|
@@ -75,13 +76,13 @@ async def schema_path_migrate(
|
|
|
75
76
|
branch: Branch,
|
|
76
77
|
migration_name: str,
|
|
77
78
|
schema_path: SchemaPath,
|
|
78
|
-
|
|
79
|
+
database: InfrahubDatabase,
|
|
79
80
|
new_node_schema: MainSchemaTypes | None = None,
|
|
80
81
|
previous_node_schema: MainSchemaTypes | None = None,
|
|
81
82
|
) -> SchemaMigrationPathResponseData:
|
|
82
83
|
log = get_run_logger()
|
|
83
84
|
|
|
84
|
-
async with
|
|
85
|
+
async with database.start_session() as db:
|
|
85
86
|
node_kind = None
|
|
86
87
|
if new_node_schema:
|
|
87
88
|
node_kind = new_node_schema.kind
|
infrahub/core/models.py
CHANGED
|
@@ -569,7 +569,11 @@ class HashableModel(BaseModel):
|
|
|
569
569
|
|
|
570
570
|
for field_name in other.model_fields.keys():
|
|
571
571
|
if not hasattr(self, field_name):
|
|
572
|
-
|
|
572
|
+
try:
|
|
573
|
+
setattr(self, field_name, getattr(other, field_name))
|
|
574
|
+
except ValueError:
|
|
575
|
+
# handles the case where self and other are different types and other has fields that self does not
|
|
576
|
+
pass
|
|
573
577
|
continue
|
|
574
578
|
|
|
575
579
|
attr_other = getattr(other, field_name)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import cast
|
|
2
|
+
|
|
3
|
+
from infrahub.core.constants.infrahubkind import THREADCOMMENT
|
|
4
|
+
from infrahub.core.manager import NodeManager
|
|
5
|
+
from infrahub.core.node import Node
|
|
6
|
+
from infrahub.core.protocols import CoreProposedChange as CoreProposedChangeProtocol
|
|
7
|
+
from infrahub.database import InfrahubDatabase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CoreProposedChange(Node):
|
|
11
|
+
async def to_graphql(
|
|
12
|
+
self,
|
|
13
|
+
db: InfrahubDatabase,
|
|
14
|
+
fields: dict | None = None,
|
|
15
|
+
related_node_ids: set | None = None,
|
|
16
|
+
filter_sensitive: bool = False,
|
|
17
|
+
permissions: dict | None = None,
|
|
18
|
+
include_properties: bool = True,
|
|
19
|
+
) -> dict:
|
|
20
|
+
response = await super().to_graphql(
|
|
21
|
+
db,
|
|
22
|
+
fields=fields,
|
|
23
|
+
related_node_ids=related_node_ids,
|
|
24
|
+
filter_sensitive=filter_sensitive,
|
|
25
|
+
permissions=permissions,
|
|
26
|
+
include_properties=include_properties,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
if fields:
|
|
30
|
+
if "total_comments" in fields:
|
|
31
|
+
total_comments = 0
|
|
32
|
+
proposed_change = cast(CoreProposedChangeProtocol, self)
|
|
33
|
+
change_comments = await proposed_change.comments.get_relationships(db=db)
|
|
34
|
+
total_comments += len(change_comments)
|
|
35
|
+
|
|
36
|
+
threads = await proposed_change.threads.get_peers(db=db)
|
|
37
|
+
thread_comments = await NodeManager.query(
|
|
38
|
+
db=db, schema=THREADCOMMENT, filters={"thread__ids": list(threads.keys())}
|
|
39
|
+
)
|
|
40
|
+
total_comments += len(thread_comments)
|
|
41
|
+
response["total_comments"] = {"value": total_comments}
|
|
42
|
+
|
|
43
|
+
return response
|
infrahub/core/protocols.py
CHANGED
|
@@ -319,6 +319,7 @@ class CoreCheckDefinition(CoreTaskTarget):
|
|
|
319
319
|
|
|
320
320
|
|
|
321
321
|
class CoreCustomWebhook(CoreWebhook, CoreTaskTarget):
|
|
322
|
+
shared_key: StringOptional
|
|
322
323
|
transformation: RelationshipManager
|
|
323
324
|
|
|
324
325
|
|
|
@@ -480,7 +481,10 @@ class CoreProposedChange(CoreTaskTarget):
|
|
|
480
481
|
source_branch: String
|
|
481
482
|
destination_branch: String
|
|
482
483
|
state: Enum
|
|
484
|
+
is_draft: Boolean
|
|
485
|
+
total_comments: IntegerOptional
|
|
483
486
|
approved_by: RelationshipManager
|
|
487
|
+
rejected_by: RelationshipManager
|
|
484
488
|
reviewers: RelationshipManager
|
|
485
489
|
created_by: RelationshipManager
|
|
486
490
|
comments: RelationshipManager
|
|
@@ -554,6 +558,14 @@ class InternalAccountToken(CoreNode):
|
|
|
554
558
|
account: RelationshipManager
|
|
555
559
|
|
|
556
560
|
|
|
561
|
+
class InternalIPPrefixAvailable(BuiltinIPPrefix):
|
|
562
|
+
pass
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
class InternalIPRangeAvailable(BuiltinIPAddress):
|
|
566
|
+
last_address: IPHost
|
|
567
|
+
|
|
568
|
+
|
|
557
569
|
class InternalRefreshToken(CoreNode):
|
|
558
570
|
expiration: DateTime
|
|
559
571
|
account: RelationshipManager
|
infrahub/core/query/attribute.py
CHANGED
|
@@ -5,9 +5,16 @@ from typing import TYPE_CHECKING, Any
|
|
|
5
5
|
from infrahub.core.constants import AttributeDBNodeType
|
|
6
6
|
from infrahub.core.constants.relationship_label import RELATIONSHIP_TO_NODE_LABEL, RELATIONSHIP_TO_VALUE_LABEL
|
|
7
7
|
from infrahub.core.constants.schema import FlagProperty, NodeProperty
|
|
8
|
+
from infrahub.core.graph.schema import (
|
|
9
|
+
GraphAttributeIPHostNode,
|
|
10
|
+
GraphAttributeIPNetworkNode,
|
|
11
|
+
GraphAttributeValueIndexedNode,
|
|
12
|
+
GraphAttributeValueNode,
|
|
13
|
+
)
|
|
8
14
|
from infrahub.core.query import Query, QueryNode, QueryRel, QueryType
|
|
9
15
|
from infrahub.core.timestamp import Timestamp
|
|
10
16
|
from infrahub.core.utils import build_regex_attrs
|
|
17
|
+
from infrahub.types import is_large_attribute_type
|
|
11
18
|
|
|
12
19
|
if TYPE_CHECKING:
|
|
13
20
|
from infrahub.core.attribute import BaseAttribute
|
|
@@ -56,12 +63,14 @@ class AttributeUpdateValueQuery(AttributeQuery):
|
|
|
56
63
|
|
|
57
64
|
prop_list = [f"{key}: ${key}" for key in content.keys()]
|
|
58
65
|
|
|
59
|
-
labels = [
|
|
66
|
+
labels = [GraphAttributeValueNode.get_default_label()]
|
|
60
67
|
node_type = self.attr.get_db_node_type()
|
|
61
|
-
if
|
|
62
|
-
labels.append(
|
|
63
|
-
|
|
64
|
-
labels.append(
|
|
68
|
+
if AttributeDBNodeType.INDEXED in node_type:
|
|
69
|
+
labels.append(GraphAttributeValueIndexedNode.get_default_label())
|
|
70
|
+
if AttributeDBNodeType.IPHOST in node_type:
|
|
71
|
+
labels.append(GraphAttributeIPHostNode.get_default_label())
|
|
72
|
+
if AttributeDBNodeType.IPNETWORK in node_type:
|
|
73
|
+
labels.append(GraphAttributeIPNetworkNode.get_default_label())
|
|
65
74
|
|
|
66
75
|
query = """
|
|
67
76
|
MATCH (a:Attribute { uuid: $attr_uuid })
|
|
@@ -198,6 +207,9 @@ async def default_attribute_query_filter(
|
|
|
198
207
|
support_profiles: bool = False,
|
|
199
208
|
) -> tuple[list[QueryElement], dict[str, Any], list[str]]:
|
|
200
209
|
"""Generate Query String Snippet to filter the right node."""
|
|
210
|
+
attribute_value_label = GraphAttributeValueNode.get_default_label()
|
|
211
|
+
if attribute_kind and not is_large_attribute_type(attribute_kind):
|
|
212
|
+
attribute_value_label = GraphAttributeValueIndexedNode.get_default_label()
|
|
201
213
|
|
|
202
214
|
query_filter: list[QueryElement] = []
|
|
203
215
|
query_params: dict[str, Any] = {}
|
|
@@ -226,33 +238,35 @@ async def default_attribute_query_filter(
|
|
|
226
238
|
query_filter.append(QueryRel(labels=[RELATIONSHIP_TO_VALUE_LABEL]))
|
|
227
239
|
|
|
228
240
|
if filter_value is None:
|
|
229
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
241
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
230
242
|
else:
|
|
231
243
|
if partial_match:
|
|
232
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
244
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
233
245
|
query_where.append(
|
|
234
246
|
f"toLower(toString(av.{filter_name})) CONTAINS toLower(toString(${param_prefix}_{filter_name}))"
|
|
235
247
|
)
|
|
236
248
|
elif attribute_kind and attribute_kind == "List" and not isinstance(filter_value, list):
|
|
237
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
249
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
238
250
|
filter_value = build_regex_attrs(values=[filter_value])
|
|
239
251
|
query_where.append(f"toString(av.{filter_name}) =~ ${param_prefix}_{filter_name}")
|
|
240
252
|
elif filter_name == "isnull":
|
|
241
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
253
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
242
254
|
elif support_profiles:
|
|
243
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
255
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
244
256
|
query_where.append(f"(av.{filter_name} = ${param_prefix}_{filter_name} OR av.is_default)")
|
|
245
257
|
else:
|
|
246
258
|
query_filter.append(
|
|
247
259
|
QueryNode(
|
|
248
|
-
name="av",
|
|
260
|
+
name="av",
|
|
261
|
+
labels=[attribute_value_label],
|
|
262
|
+
params={filter_name: f"${param_prefix}_{filter_name}"},
|
|
249
263
|
)
|
|
250
264
|
)
|
|
251
265
|
query_params[f"{param_prefix}_{filter_name}"] = filter_value
|
|
252
266
|
|
|
253
267
|
elif filter_name == "values" and isinstance(filter_value, list):
|
|
254
268
|
query_filter.extend(
|
|
255
|
-
(QueryRel(labels=[RELATIONSHIP_TO_VALUE_LABEL]), QueryNode(name="av", labels=[
|
|
269
|
+
(QueryRel(labels=[RELATIONSHIP_TO_VALUE_LABEL]), QueryNode(name="av", labels=[attribute_value_label]))
|
|
256
270
|
)
|
|
257
271
|
if attribute_kind and attribute_kind == "List":
|
|
258
272
|
query_params[f"{param_prefix}_{filter_name}"] = build_regex_attrs(values=filter_value)
|
|
@@ -267,10 +281,14 @@ async def default_attribute_query_filter(
|
|
|
267
281
|
query_filter.append(QueryRel(labels=[RELATIONSHIP_TO_VALUE_LABEL]))
|
|
268
282
|
|
|
269
283
|
if filter_value is None:
|
|
270
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
284
|
+
query_filter.append(QueryNode(name="av", labels=[GraphAttributeValueNode.get_default_label()]))
|
|
271
285
|
else:
|
|
272
286
|
query_filter.append(
|
|
273
|
-
QueryNode(
|
|
287
|
+
QueryNode(
|
|
288
|
+
name="av",
|
|
289
|
+
labels=[GraphAttributeValueNode.get_default_label()],
|
|
290
|
+
params={filter_name: f"${param_prefix}_{filter_name}"},
|
|
291
|
+
)
|
|
274
292
|
)
|
|
275
293
|
query_params[f"{param_prefix}_{filter_name}"] = filter_value
|
|
276
294
|
|
infrahub/core/query/diff.py
CHANGED
|
@@ -100,6 +100,17 @@ class DiffCountChanges(Query):
|
|
|
100
100
|
return branch_count_map
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
async def get_num_changes_in_time_range_by_branch(
|
|
104
|
+
branch_names: list[str],
|
|
105
|
+
from_time: Timestamp,
|
|
106
|
+
to_time: Timestamp,
|
|
107
|
+
db: InfrahubDatabase,
|
|
108
|
+
) -> dict[str, int]:
|
|
109
|
+
query = await DiffCountChanges.init(db=db, branch_names=branch_names, diff_from=from_time, diff_to=to_time)
|
|
110
|
+
await query.execute(db=db)
|
|
111
|
+
return query.get_num_changes_by_branch()
|
|
112
|
+
|
|
113
|
+
|
|
103
114
|
class DiffCalculationQuery(DiffQuery):
|
|
104
115
|
type = QueryType.READ
|
|
105
116
|
insert_limit = False
|
infrahub/core/query/ipam.py
CHANGED
|
@@ -5,6 +5,7 @@ from dataclasses import dataclass
|
|
|
5
5
|
from typing import TYPE_CHECKING, Iterable
|
|
6
6
|
|
|
7
7
|
from infrahub.core.constants import InfrahubKind
|
|
8
|
+
from infrahub.core.graph.schema import GraphAttributeIPHostNode, GraphAttributeIPNetworkNode
|
|
8
9
|
from infrahub.core.ipam.constants import AllIPTypes, IPAddressType, IPNetworkType
|
|
9
10
|
from infrahub.core.query import QueryType
|
|
10
11
|
from infrahub.core.registry import registry
|
|
@@ -21,8 +22,8 @@ if TYPE_CHECKING:
|
|
|
21
22
|
from infrahub.database import InfrahubDatabase
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
PREFIX_ATTRIBUTE_LABEL =
|
|
25
|
-
ADDRESS_ATTRIBUTE_LABEL =
|
|
25
|
+
PREFIX_ATTRIBUTE_LABEL = GraphAttributeIPNetworkNode.get_default_label()
|
|
26
|
+
ADDRESS_ATTRIBUTE_LABEL = GraphAttributeIPHostNode.get_default_label()
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
@dataclass
|
|
@@ -280,14 +281,13 @@ class IPPrefixUtilization(Query):
|
|
|
280
281
|
MATCH path = (
|
|
281
282
|
(pfx)-[r_1:IS_RELATED]-(rl:Relationship)-[r_2:IS_RELATED]-(child:Node)
|
|
282
283
|
-[r_attr:HAS_ATTRIBUTE]->(attr:Attribute)
|
|
283
|
-
-[r_attr_val:HAS_VALUE]->(av:
|
|
284
|
+
-[r_attr_val:HAS_VALUE]->(av:{PREFIX_ATTRIBUTE_LABEL}|{ADDRESS_ATTRIBUTE_LABEL})
|
|
284
285
|
)
|
|
285
286
|
WHERE %(id_func)s(r_1) = %(id_func)s(r_rel1)
|
|
286
287
|
AND %(id_func)s(r_2) = %(id_func)s(r_rel2)
|
|
287
288
|
AND ({rel_filter("r_attr")})
|
|
288
289
|
AND ({rel_filter("r_attr_val")})
|
|
289
290
|
AND attr.name IN ["prefix", "address"]
|
|
290
|
-
AND any(l in labels(av) WHERE l in ["{PREFIX_ATTRIBUTE_LABEL}", "{ADDRESS_ATTRIBUTE_LABEL}"])
|
|
291
291
|
WITH
|
|
292
292
|
path,
|
|
293
293
|
pfx,
|
|
@@ -478,6 +478,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
478
478
|
-[pr2:IS_RELATED {status: "active"}]-(maybe_new_parent:%(ip_prefix_kind)s)
|
|
479
479
|
-[har:HAS_ATTRIBUTE]->(:Attribute {name: "prefix"})
|
|
480
480
|
-[hvr:HAS_VALUE]->(av:%(ip_prefix_attribute_kind)s)
|
|
481
|
+
USING INDEX av:%(ip_prefix_attribute_kind)s(binary_address)
|
|
481
482
|
WHERE all(r IN relationships(parent_path) WHERE (%(branch_filter)s))
|
|
482
483
|
AND av.version = $ip_version
|
|
483
484
|
AND av.binary_address IN $possible_prefix_list
|
|
@@ -514,15 +515,16 @@ class IPPrefixReconcileQuery(Query):
|
|
|
514
515
|
OPTIONAL MATCH child_path = (
|
|
515
516
|
(ip_namespace)-[r1:IS_RELATED]
|
|
516
517
|
-(ns_rel:Relationship)-[r2:IS_RELATED]
|
|
517
|
-
-(maybe_new_child
|
|
518
|
+
-(maybe_new_child:%(ip_prefix_kind)s|%(ip_address_kind)s)-[har:HAS_ATTRIBUTE]
|
|
518
519
|
->(a:Attribute)-[hvr:HAS_VALUE]
|
|
519
|
-
->(av
|
|
520
|
+
->(av:%(ip_prefix_attribute_kind)s|%(ip_address_attribute_kind)s)
|
|
520
521
|
)
|
|
522
|
+
USING INDEX av:%(ip_prefix_attribute_kind)s(binary_address)
|
|
523
|
+
USING INDEX av:%(ip_address_attribute_kind)s(binary_address)
|
|
521
524
|
WHERE $is_prefix // only prefix nodes can have children
|
|
522
525
|
AND ns_rel.name IN ["ip_namespace__ip_prefix", "ip_namespace__ip_address"]
|
|
523
526
|
AND any(child_kind IN [$ip_prefix_kind, $ip_address_kind] WHERE child_kind IN labels(maybe_new_child))
|
|
524
527
|
AND a.name in ["prefix", "address"]
|
|
525
|
-
AND any(attr_kind IN [$ip_prefix_attribute_kind, $ip_address_attribute_kind] WHERE attr_kind IN labels(av))
|
|
526
528
|
AND (ip_node IS NULL OR maybe_new_child.uuid <> ip_node.uuid)
|
|
527
529
|
AND (
|
|
528
530
|
($ip_prefix_kind IN labels(maybe_new_child) AND av.prefixlen > $prefixlen)
|
|
@@ -580,6 +582,10 @@ class IPPrefixReconcileQuery(Query):
|
|
|
580
582
|
collect(new_child) as new_children
|
|
581
583
|
""" % {
|
|
582
584
|
"branch_filter": branch_filter,
|
|
585
|
+
"ip_prefix_kind": InfrahubKind.IPPREFIX,
|
|
586
|
+
"ip_address_kind": InfrahubKind.IPADDRESS,
|
|
587
|
+
"ip_prefix_attribute_kind": PREFIX_ATTRIBUTE_LABEL,
|
|
588
|
+
"ip_address_attribute_kind": ADDRESS_ATTRIBUTE_LABEL,
|
|
583
589
|
}
|
|
584
590
|
self.add_to_query(get_new_children_query)
|
|
585
591
|
self.return_labels = ["ip_node", "current_parent", "current_children", "new_parent", "new_children"]
|
infrahub/core/query/node.py
CHANGED
|
@@ -140,15 +140,19 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
140
140
|
attributes: list[AttributeCreateData] = []
|
|
141
141
|
attributes_iphost: list[AttributeCreateData] = []
|
|
142
142
|
attributes_ipnetwork: list[AttributeCreateData] = []
|
|
143
|
+
attributes_indexed: list[AttributeCreateData] = []
|
|
143
144
|
|
|
144
145
|
for attr_name in self.node._attributes:
|
|
145
146
|
attr: BaseAttribute = getattr(self.node, attr_name)
|
|
146
147
|
attr_data = attr.get_create_data()
|
|
148
|
+
node_type = attr.get_db_node_type()
|
|
147
149
|
|
|
148
|
-
if
|
|
150
|
+
if AttributeDBNodeType.IPHOST in node_type:
|
|
149
151
|
attributes_iphost.append(attr_data)
|
|
150
|
-
elif
|
|
152
|
+
elif AttributeDBNodeType.IPNETWORK in node_type:
|
|
151
153
|
attributes_ipnetwork.append(attr_data)
|
|
154
|
+
elif AttributeDBNodeType.INDEXED in node_type:
|
|
155
|
+
attributes_indexed.append(attr_data)
|
|
152
156
|
else:
|
|
153
157
|
attributes.append(attr_data)
|
|
154
158
|
|
|
@@ -182,6 +186,7 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
182
186
|
relationships.append(rel_create_data)
|
|
183
187
|
|
|
184
188
|
self.params["attrs"] = [attr.model_dump() for attr in attributes]
|
|
189
|
+
self.params["attrs_indexed"] = [attr.model_dump() for attr in attributes_indexed]
|
|
185
190
|
self.params["attrs_iphost"] = [attr.model_dump() for attr in attributes_iphost]
|
|
186
191
|
self.params["attrs_ipnetwork"] = [attr.model_dump() for attr in attributes_ipnetwork]
|
|
187
192
|
self.params["rels_bidir"] = [
|
|
@@ -224,24 +229,59 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
224
229
|
"binary_address": "attr.content.binary_address",
|
|
225
230
|
"version": "attr.content.version",
|
|
226
231
|
"prefixlen": "attr.content.prefixlen",
|
|
227
|
-
# "num_addresses": "attr.content.num_addresses",
|
|
228
232
|
}
|
|
229
233
|
ipnetwork_prop_list = [f"{key}: {value}" for key, value in ipnetwork_prop.items()]
|
|
230
234
|
|
|
231
|
-
|
|
235
|
+
attrs_nonindexed_query = """
|
|
232
236
|
WITH distinct n
|
|
233
237
|
UNWIND $attrs AS attr
|
|
238
|
+
// Try to find a matching vertex
|
|
239
|
+
OPTIONAL MATCH (existing_av:AttributeValue {value: attr.content.value, is_default: attr.content.is_default})
|
|
240
|
+
WHERE NOT existing_av:AttributeValueIndexed
|
|
241
|
+
CALL (attr, existing_av) {
|
|
242
|
+
// If none found, create a new one
|
|
243
|
+
WITH existing_av
|
|
244
|
+
WHERE existing_av IS NULL
|
|
245
|
+
CREATE (:AttributeValue {value: attr.content.value, is_default: attr.content.is_default})
|
|
246
|
+
}
|
|
247
|
+
CALL (attr) {
|
|
248
|
+
MATCH (av:AttributeValue {value: attr.content.value, is_default: attr.content.is_default})
|
|
249
|
+
WHERE NOT av:AttributeValueIndexed
|
|
250
|
+
RETURN av
|
|
251
|
+
LIMIT 1
|
|
252
|
+
}
|
|
253
|
+
CALL (n, attr, av) {
|
|
254
|
+
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
255
|
+
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
256
|
+
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
257
|
+
MERGE (ip:Boolean { value: attr.is_protected })
|
|
258
|
+
MERGE (iv:Boolean { value: attr.is_visible })
|
|
259
|
+
WITH a, ip, iv
|
|
260
|
+
LIMIT 1
|
|
261
|
+
CREATE (a)-[:IS_PROTECTED { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(ip)
|
|
262
|
+
CREATE (a)-[:IS_VISIBLE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(iv)
|
|
263
|
+
FOREACH ( prop IN attr.source_prop |
|
|
264
|
+
MERGE (peer:Node { uuid: prop.peer_id })
|
|
265
|
+
CREATE (a)-[:HAS_SOURCE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
|
|
266
|
+
)
|
|
267
|
+
FOREACH ( prop IN attr.owner_prop |
|
|
268
|
+
MERGE (peer:Node { uuid: prop.peer_id })
|
|
269
|
+
CREATE (a)-[:HAS_OWNER { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
|
|
270
|
+
)
|
|
271
|
+
}"""
|
|
272
|
+
|
|
273
|
+
attrs_indexed_query = """
|
|
274
|
+
WITH distinct n
|
|
275
|
+
UNWIND $attrs_indexed AS attr
|
|
234
276
|
CALL (n, attr) {
|
|
235
277
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
236
278
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
237
|
-
MERGE (av:AttributeValue { value: attr.content.value, is_default: attr.content.is_default })
|
|
279
|
+
MERGE (av:AttributeValue:AttributeValueIndexed { value: attr.content.value, is_default: attr.content.is_default })
|
|
238
280
|
WITH av, a
|
|
239
281
|
LIMIT 1
|
|
240
282
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
241
283
|
MERGE (ip:Boolean { value: attr.is_protected })
|
|
242
284
|
MERGE (iv:Boolean { value: attr.is_visible })
|
|
243
|
-
WITH a, ip, iv
|
|
244
|
-
LIMIT 1
|
|
245
285
|
CREATE (a)-[:IS_PROTECTED { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(ip)
|
|
246
286
|
CREATE (a)-[:IS_VISIBLE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(iv)
|
|
247
287
|
FOREACH ( prop IN attr.source_prop |
|
|
@@ -260,7 +300,7 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
260
300
|
CALL (n, attr) {
|
|
261
301
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
262
302
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
263
|
-
MERGE (av:AttributeValue:AttributeIPHost { %(iphost_prop)s })
|
|
303
|
+
MERGE (av:AttributeValue:AttributeValueIndexed:AttributeIPHost { %(iphost_prop)s })
|
|
264
304
|
WITH attr, av, a
|
|
265
305
|
LIMIT 1
|
|
266
306
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
@@ -287,7 +327,7 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
287
327
|
CALL (n, attr) {
|
|
288
328
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
289
329
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
290
|
-
MERGE (av:AttributeValue:AttributeIPNetwork { %(ipnetwork_prop)s })
|
|
330
|
+
MERGE (av:AttributeValue:AttributeValueIndexed:AttributeIPNetwork { %(ipnetwork_prop)s })
|
|
291
331
|
WITH attr, av, a
|
|
292
332
|
LIMIT 1
|
|
293
333
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
@@ -424,7 +464,8 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
424
464
|
MATCH (root:Root)
|
|
425
465
|
CREATE (n:Node:%(labels)s $node_prop )
|
|
426
466
|
CREATE (n)-[r:IS_PART_OF $node_branch_prop ]->(root)
|
|
427
|
-
{
|
|
467
|
+
{attrs_nonindexed_query if self.params["attrs"] else ""}
|
|
468
|
+
{attrs_indexed_query if self.params["attrs_indexed"] else ""}
|
|
428
469
|
{attrs_iphost_query if self.params["attrs_iphost"] else ""}
|
|
429
470
|
{attrs_ipnetwork_query if self.params["attrs_ipnetwork"] else ""}
|
|
430
471
|
{rels_bidir_query if self.params["rels_bidir"] else ""}
|
|
@@ -140,7 +140,7 @@ class NumberPoolGetAllocated(Query):
|
|
|
140
140
|
self.params.update(branch_params)
|
|
141
141
|
|
|
142
142
|
query = """
|
|
143
|
-
MATCH (n:%(node)s)-[ha:HAS_ATTRIBUTE]-(a:Attribute {name: $node_attribute})-[hv:HAS_VALUE]-(av:
|
|
143
|
+
MATCH (n:%(node)s)-[ha:HAS_ATTRIBUTE]-(a:Attribute {name: $node_attribute})-[hv:HAS_VALUE]-(av:AttributeValueIndexed)
|
|
144
144
|
MATCH (a)-[hs:HAS_SOURCE]-(pool:%(number_pool_kind)s)
|
|
145
145
|
WHERE
|
|
146
146
|
pool.uuid = $pool_id
|
|
@@ -306,7 +306,7 @@ class NumberPoolGetUsed(Query):
|
|
|
306
306
|
self.params["attribute_name"] = self.pool.node_attribute.value
|
|
307
307
|
|
|
308
308
|
query = """
|
|
309
|
-
MATCH (pool:%(number_pool)s { uuid: $pool_id })-[res:IS_RESERVED]->(av:
|
|
309
|
+
MATCH (pool:%(number_pool)s { uuid: $pool_id })-[res:IS_RESERVED]->(av:AttributeValueIndexed)
|
|
310
310
|
WHERE toInteger(av.value) >= $start_range and toInteger(av.value) <= $end_range
|
|
311
311
|
CALL (pool, res, av) {
|
|
312
312
|
MATCH (pool)-[res]->(av)<-[hv:HAS_VALUE]-(attr:Attribute)<-[ha:HAS_ATTRIBUTE]-(n:%(node)s)
|
|
@@ -371,7 +371,7 @@ class NumberPoolSetReserved(Query):
|
|
|
371
371
|
|
|
372
372
|
query = """
|
|
373
373
|
MATCH (pool:%(number_pool)s { uuid: $pool_id })
|
|
374
|
-
MERGE (value:AttributeValue { value: $reserved, is_default: false })
|
|
374
|
+
MERGE (value:AttributeValue:AttributeValueIndexed { value: $reserved, is_default: false })
|
|
375
375
|
WITH value, pool
|
|
376
376
|
LIMIT 1
|
|
377
377
|
CREATE (pool)-[rel:IS_RESERVED $rel_prop]->(value)
|
|
@@ -55,6 +55,14 @@ class BaseNodeSchema(GeneratedBaseNodeSchema):
|
|
|
55
55
|
def is_profile_schema(self) -> bool:
|
|
56
56
|
return False
|
|
57
57
|
|
|
58
|
+
@property
|
|
59
|
+
def is_ip_prefix(self) -> bool:
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def is_ip_address(self) -> bool:
|
|
64
|
+
return False
|
|
65
|
+
|
|
58
66
|
@property
|
|
59
67
|
def kind(self) -> str:
|
|
60
68
|
if self.namespace == "Attribute":
|