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
|
@@ -152,6 +152,8 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
152
152
|
"INFRAHUB_TESTING_TASKMGR_BACKGROUND_SVC_REPLICAS": "1",
|
|
153
153
|
"PREFECT_MESSAGING_BROKER": "prefect_redis.messaging",
|
|
154
154
|
"PREFECT_MESSAGING_CACHE": "prefect_redis.messaging",
|
|
155
|
+
"PREFECT_SERVER_EVENTS_CAUSAL_ORDERING": "prefect_redis.ordering",
|
|
156
|
+
"PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE": "prefect_redis.lease_storage",
|
|
155
157
|
"PREFECT__SERVER_WEBSERVER_ONLY": "true",
|
|
156
158
|
"PREFECT_API_DATABASE_MIGRATE_ON_START": "false",
|
|
157
159
|
"PREFECT_API_BLOCKS_REGISTER_ON_START": "false",
|
|
@@ -237,7 +239,9 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
237
239
|
for service_name, service_data in INFRAHUB_SERVICES.items()
|
|
238
240
|
}
|
|
239
241
|
|
|
240
|
-
def database_create_backup(
|
|
242
|
+
def database_create_backup(
|
|
243
|
+
self, backup_name: str = "neo4j_database.backup", dest_dir: Path | None = None, compress: bool = False
|
|
244
|
+
) -> None:
|
|
241
245
|
assert self.use_neo4j_enterprise
|
|
242
246
|
|
|
243
247
|
self.exec_in_container(
|
|
@@ -245,7 +249,7 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
245
249
|
"neo4j-admin",
|
|
246
250
|
"database",
|
|
247
251
|
"backup",
|
|
248
|
-
"--compress=false",
|
|
252
|
+
f"--compress={'true' if compress else 'false'}",
|
|
249
253
|
"--to-path",
|
|
250
254
|
str(self.internal_backup_dir),
|
|
251
255
|
],
|
|
@@ -513,3 +517,111 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
513
517
|
)
|
|
514
518
|
self.start()
|
|
515
519
|
print("Database restored successfully")
|
|
520
|
+
|
|
521
|
+
def task_manager_create_backup(self, backup_name: str = "prefect.dump", dest_dir: Path | None = None) -> Path:
|
|
522
|
+
"""Create a backup of the task manager PostgreSQL database using ``pg_dump``.
|
|
523
|
+
|
|
524
|
+
Args:
|
|
525
|
+
backup_name: Name of the archive file to create. Defaults to ``prefect.dump``.
|
|
526
|
+
dest_dir: Optional host directory where the backup should be copied after it is
|
|
527
|
+
produced. When omitted, the backup remains in ``external_backup_dir``.
|
|
528
|
+
|
|
529
|
+
Returns:
|
|
530
|
+
Path to the backup archive on the host filesystem.
|
|
531
|
+
|
|
532
|
+
Raises:
|
|
533
|
+
FileNotFoundError: If the pg_dump command completes but no archive is produced.
|
|
534
|
+
"""
|
|
535
|
+
|
|
536
|
+
service_name = "task-manager-db"
|
|
537
|
+
|
|
538
|
+
try:
|
|
539
|
+
self.get_container(service_name=service_name)
|
|
540
|
+
except ContainerIsNotRunning:
|
|
541
|
+
self.start_container(service_name=service_name)
|
|
542
|
+
|
|
543
|
+
self.external_backup_dir.mkdir(parents=True, exist_ok=True)
|
|
544
|
+
|
|
545
|
+
internal_backup_path = self.internal_backup_dir / backup_name
|
|
546
|
+
dump_command = [
|
|
547
|
+
"pg_dump",
|
|
548
|
+
"--format=custom",
|
|
549
|
+
"--blobs",
|
|
550
|
+
"--no-owner",
|
|
551
|
+
"--no-privileges",
|
|
552
|
+
"--dbname=postgresql://postgres:postgres@localhost:5432/prefect",
|
|
553
|
+
f"--file={internal_backup_path}",
|
|
554
|
+
]
|
|
555
|
+
self.exec_in_container(command=dump_command, service_name=service_name)
|
|
556
|
+
|
|
557
|
+
source_path = self.external_backup_dir / backup_name
|
|
558
|
+
if not source_path.exists():
|
|
559
|
+
raise FileNotFoundError(f"Backup file {source_path} was not created")
|
|
560
|
+
|
|
561
|
+
final_path = source_path
|
|
562
|
+
if dest_dir:
|
|
563
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
564
|
+
if dest_dir.resolve() != self.external_backup_dir.resolve():
|
|
565
|
+
final_path = dest_dir / backup_name
|
|
566
|
+
shutil.copy(source_path, final_path)
|
|
567
|
+
|
|
568
|
+
return final_path
|
|
569
|
+
|
|
570
|
+
def task_manager_restore_backup(self, backup_file: Path) -> None:
|
|
571
|
+
"""Restore the task manager PostgreSQL database from a ``pg_restore`` archive.
|
|
572
|
+
|
|
573
|
+
Args:
|
|
574
|
+
backup_file: Path to the backup archive on the host filesystem.
|
|
575
|
+
|
|
576
|
+
Raises:
|
|
577
|
+
FileNotFoundError: If the provided backup archive does not exist.
|
|
578
|
+
"""
|
|
579
|
+
|
|
580
|
+
if not backup_file.exists():
|
|
581
|
+
raise FileNotFoundError(f"Backup file {backup_file} does not exist")
|
|
582
|
+
|
|
583
|
+
service_name = "task-manager-db"
|
|
584
|
+
|
|
585
|
+
try:
|
|
586
|
+
self.get_container(service_name=service_name)
|
|
587
|
+
except ContainerIsNotRunning:
|
|
588
|
+
self.start_container(service_name=service_name)
|
|
589
|
+
|
|
590
|
+
self.external_backup_dir.mkdir(parents=True, exist_ok=True)
|
|
591
|
+
target_path = self.external_backup_dir / backup_file.name
|
|
592
|
+
shutil.copy(backup_file, target_path)
|
|
593
|
+
|
|
594
|
+
admin_dsn = "postgresql://postgres:postgres@localhost:5432/postgres"
|
|
595
|
+
prefect_dsn = "postgresql://postgres:postgres@localhost:5432/prefect"
|
|
596
|
+
internal_backup_path = self.internal_backup_dir / backup_file.name
|
|
597
|
+
|
|
598
|
+
terminate_sessions_command = [
|
|
599
|
+
"psql",
|
|
600
|
+
f"--dbname={admin_dsn}",
|
|
601
|
+
"--command",
|
|
602
|
+
"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'prefect';",
|
|
603
|
+
]
|
|
604
|
+
drop_database_command = [
|
|
605
|
+
"psql",
|
|
606
|
+
f"--dbname={admin_dsn}",
|
|
607
|
+
"--command",
|
|
608
|
+
"DROP DATABASE IF EXISTS prefect WITH (FORCE);",
|
|
609
|
+
]
|
|
610
|
+
create_database_command = [
|
|
611
|
+
"psql",
|
|
612
|
+
f"--dbname={admin_dsn}",
|
|
613
|
+
"--command",
|
|
614
|
+
"CREATE DATABASE prefect OWNER postgres;",
|
|
615
|
+
]
|
|
616
|
+
restore_command = [
|
|
617
|
+
"pg_restore",
|
|
618
|
+
"--no-owner",
|
|
619
|
+
"--role=postgres",
|
|
620
|
+
f"--dbname={prefect_dsn}",
|
|
621
|
+
str(internal_backup_path),
|
|
622
|
+
]
|
|
623
|
+
|
|
624
|
+
self.exec_in_container(command=terminate_sessions_command, service_name=service_name)
|
|
625
|
+
self.exec_in_container(command=drop_database_command, service_name=service_name)
|
|
626
|
+
self.exec_in_container(command=create_database_command, service_name=service_name)
|
|
627
|
+
self.exec_in_container(command=restore_command, service_name=service_name)
|
|
@@ -184,6 +184,8 @@ services:
|
|
|
184
184
|
|
|
185
185
|
PREFECT_MESSAGING_BROKER:
|
|
186
186
|
PREFECT_MESSAGING_CACHE:
|
|
187
|
+
PREFECT_SERVER_EVENTS_CAUSAL_ORDERING:
|
|
188
|
+
PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE:
|
|
187
189
|
PREFECT__SERVER_WEBSERVER_ONLY:
|
|
188
190
|
PREFECT_API_DATABASE_MIGRATE_ON_START:
|
|
189
191
|
PREFECT_API_BLOCKS_REGISTER_ON_START:
|
|
@@ -225,6 +227,8 @@ services:
|
|
|
225
227
|
INFRAHUB_CACHE_ADDRESS: ${INFRAHUB_TESTING_CACHE_ADDRESS}
|
|
226
228
|
PREFECT_MESSAGING_BROKER: prefect_redis.messaging
|
|
227
229
|
PREFECT_MESSAGING_CACHE: prefect_redis.messaging
|
|
230
|
+
PREFECT_SERVER_EVENTS_CAUSAL_ORDERING: prefect_redis.ordering
|
|
231
|
+
PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE: prefect_redis.lease_storage
|
|
228
232
|
PREFECT_REDIS_MESSAGING_HOST: "${INFRAHUB_TESTING_CACHE_ADDRESS:-cache}"
|
|
229
233
|
PREFECT_REDIS_MESSAGING_DB: "1"
|
|
230
234
|
PREFECT_REDIS_MESSAGING_CONSUMER_MIN_IDLE_TIME: "30"
|
|
@@ -244,6 +248,7 @@ services:
|
|
|
244
248
|
- POSTGRES_DB=prefect
|
|
245
249
|
volumes:
|
|
246
250
|
- workflow_db:/var/lib/postgresql/data
|
|
251
|
+
- "./${INFRAHUB_TESTING_LOCAL_DB_BACKUP_DIRECTORY}:${INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY}"
|
|
247
252
|
healthcheck:
|
|
248
253
|
test: ["CMD-SHELL", "pg_isready"]
|
|
249
254
|
interval: 10s
|
|
@@ -95,6 +95,8 @@ services:
|
|
|
95
95
|
|
|
96
96
|
PREFECT_MESSAGING_BROKER:
|
|
97
97
|
PREFECT_MESSAGING_CACHE:
|
|
98
|
+
PREFECT_SERVER_EVENTS_CAUSAL_ORDERING:
|
|
99
|
+
PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE:
|
|
98
100
|
PREFECT__SERVER_WEBSERVER_ONLY:
|
|
99
101
|
PREFECT_API_DATABASE_MIGRATE_ON_START:
|
|
100
102
|
PREFECT_API_BLOCKS_REGISTER_ON_START:
|
|
@@ -136,6 +138,8 @@ services:
|
|
|
136
138
|
INFRAHUB_CACHE_ADDRESS: ${INFRAHUB_TESTING_CACHE_ADDRESS}
|
|
137
139
|
PREFECT_MESSAGING_BROKER: prefect_redis.messaging
|
|
138
140
|
PREFECT_MESSAGING_CACHE: prefect_redis.messaging
|
|
141
|
+
PREFECT_SERVER_EVENTS_CAUSAL_ORDERING: prefect_redis.ordering
|
|
142
|
+
PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE: prefect_redis.lease_storage
|
|
139
143
|
PREFECT_REDIS_MESSAGING_HOST: "${INFRAHUB_TESTING_CACHE_ADDRESS:-cache}"
|
|
140
144
|
PREFECT_REDIS_MESSAGING_DB: "1"
|
|
141
145
|
PREFECT_REDIS_MESSAGING_CONSUMER_MIN_IDLE_TIME: "30"
|
|
@@ -155,6 +159,7 @@ services:
|
|
|
155
159
|
- POSTGRES_DB=prefect
|
|
156
160
|
volumes:
|
|
157
161
|
- workflow_db:/var/lib/postgresql/data
|
|
162
|
+
- "./${INFRAHUB_TESTING_LOCAL_DB_BACKUP_DIRECTORY}:${INFRAHUB_TESTING_INTERNAL_DB_BACKUP_DIRECTORY}"
|
|
158
163
|
healthcheck:
|
|
159
164
|
test: ["CMD-SHELL", "pg_isready"]
|
|
160
165
|
interval: 10s
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from datetime import
|
|
1
|
+
from datetime import UTC, datetime
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
@@ -27,7 +27,7 @@ class InfrahubResultContext(BaseModel):
|
|
|
27
27
|
|
|
28
28
|
class InfrahubActiveMeasurementItem(BaseModel):
|
|
29
29
|
definition: MeasurementDefinition
|
|
30
|
-
start_time: datetime = Field(default_factory=lambda: datetime.now(
|
|
30
|
+
start_time: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
|
31
31
|
context: dict[str, Any] = Field(default_factory=dict)
|
|
32
32
|
|
|
33
33
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import json
|
|
3
|
-
from datetime import
|
|
3
|
+
from datetime import UTC, datetime
|
|
4
4
|
from types import TracebackType
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
@@ -35,7 +35,7 @@ class InfrahubPerformanceTest:
|
|
|
35
35
|
self.env_vars = {}
|
|
36
36
|
self.project_name = ""
|
|
37
37
|
self.test_info = {}
|
|
38
|
-
self.start_time = datetime.now(
|
|
38
|
+
self.start_time = datetime.now(UTC)
|
|
39
39
|
self.end_time: datetime | None = None
|
|
40
40
|
self.results_url = results_url
|
|
41
41
|
self.scraper_endpoint = ""
|
|
@@ -57,7 +57,7 @@ class InfrahubPerformanceTest:
|
|
|
57
57
|
|
|
58
58
|
def finalize(self, session: pytest.Session) -> None:
|
|
59
59
|
if self.initialized:
|
|
60
|
-
self.end_time = datetime.now(
|
|
60
|
+
self.end_time = datetime.now(UTC)
|
|
61
61
|
self.extract_test_session_information(session)
|
|
62
62
|
self.send_results()
|
|
63
63
|
|
|
@@ -129,7 +129,7 @@ class InfrahubPerformanceTest:
|
|
|
129
129
|
if not exc_type and self.active_measurements:
|
|
130
130
|
self.add_measurement(
|
|
131
131
|
definition=self.active_measurements.definition,
|
|
132
|
-
value=(datetime.now(
|
|
132
|
+
value=(datetime.now(UTC) - self.active_measurements.start_time).total_seconds() * 1000,
|
|
133
133
|
context=self.active_measurements.context,
|
|
134
134
|
)
|
|
135
135
|
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
from infrahub.core.attribute import BaseAttribute
|
|
6
|
-
from infrahub.core.branch import Branch
|
|
7
|
-
from infrahub.core.constants import RelationshipCardinality
|
|
8
|
-
from infrahub.core.manager import NodeManager
|
|
9
|
-
from infrahub.core.node import Node
|
|
10
|
-
from infrahub.core.node.create import create_node
|
|
11
|
-
from infrahub.core.query.relationship import GetAllPeersIds
|
|
12
|
-
from infrahub.core.query.resource_manager import PoolChangeReserved
|
|
13
|
-
from infrahub.core.relationship import RelationshipManager
|
|
14
|
-
from infrahub.core.schema import NodeSchema
|
|
15
|
-
from infrahub.database import InfrahubDatabase
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class InputDataForDestField(BaseModel): # Only one of these fields can be not None
|
|
19
|
-
attribute_value: Any | None = None
|
|
20
|
-
peer_id: str | None = None
|
|
21
|
-
peers_ids: list[str] | None = None
|
|
22
|
-
|
|
23
|
-
@property
|
|
24
|
-
def value(self) -> Any:
|
|
25
|
-
fields = [self.attribute_value, self.peer_id, self.peers_ids]
|
|
26
|
-
set_fields = [f for f in fields if f is not None]
|
|
27
|
-
if len(set_fields) != 1:
|
|
28
|
-
raise ValueError("Exactly one of attribute_value, peer_id, or peers_ids must be set")
|
|
29
|
-
return set_fields[0]
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class InputForDestField(BaseModel): # Only one of these fields can be not None
|
|
33
|
-
source_field: str | None = None
|
|
34
|
-
data: InputDataForDestField | None = None
|
|
35
|
-
|
|
36
|
-
@property
|
|
37
|
-
def value(self) -> Any:
|
|
38
|
-
if self.source_field is not None and self.data is not None:
|
|
39
|
-
raise ValueError("Only one of source_field or data can be set")
|
|
40
|
-
if self.source_field is None and self.data is None:
|
|
41
|
-
raise ValueError("Either source_field or data must be set")
|
|
42
|
-
return self.source_field if self.source_field is not None else self.data
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
async def get_out_rels_peers_ids(node: Node, db: InfrahubDatabase) -> list[str]:
|
|
46
|
-
all_peers: list[Node] = []
|
|
47
|
-
for name in node._relationships:
|
|
48
|
-
relm: RelationshipManager = getattr(node, name)
|
|
49
|
-
peers = await relm.get_peers(db=db)
|
|
50
|
-
all_peers.extend(peers.values())
|
|
51
|
-
return [peer.id for peer in all_peers]
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
async def build_data_new_node(db: InfrahubDatabase, mapping: dict[str, InputForDestField], node: Node) -> dict:
|
|
55
|
-
"""Value of a given field on the target kind to convert is either an input source attribute/relationship of the source node,
|
|
56
|
-
or a raw value."""
|
|
57
|
-
|
|
58
|
-
data = {}
|
|
59
|
-
for dest_field_name, input_for_dest_field in mapping.items():
|
|
60
|
-
value = input_for_dest_field.value
|
|
61
|
-
if isinstance(value, str): # source_field
|
|
62
|
-
item = getattr(node, value)
|
|
63
|
-
if isinstance(item, BaseAttribute):
|
|
64
|
-
data[dest_field_name] = item.value
|
|
65
|
-
elif isinstance(item, RelationshipManager):
|
|
66
|
-
if item.schema.cardinality == RelationshipCardinality.ONE:
|
|
67
|
-
peer = await item.get_peer(db=db)
|
|
68
|
-
if peer is not None:
|
|
69
|
-
data[dest_field_name] = {"id": peer.id}
|
|
70
|
-
# else, relationship is optional, and if the target relationship is mandatory an error will be raised during creation
|
|
71
|
-
elif item.schema.cardinality == RelationshipCardinality.MANY:
|
|
72
|
-
data[dest_field_name] = [{"id": peer.id} for _, peer in (await item.get_peers(db=db)).items()]
|
|
73
|
-
else:
|
|
74
|
-
raise ValueError(f"Unknown cardinality {item.schema.cardinality=}")
|
|
75
|
-
else: # user input data
|
|
76
|
-
data[dest_field_name] = value.value
|
|
77
|
-
return data
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
async def get_unidirectional_rels_peers_ids(node: Node, branch: Branch, db: InfrahubDatabase) -> list[str]:
|
|
81
|
-
"""
|
|
82
|
-
Returns peers ids of nodes connected to input `node` through an incoming unidirectional relationship.
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
out_rels_identifier = [rel.identifier for rel in node.get_schema().relationships]
|
|
86
|
-
query = await GetAllPeersIds.init(db=db, node_id=node.id, branch=branch, exclude_identifiers=out_rels_identifier)
|
|
87
|
-
await query.execute(db=db)
|
|
88
|
-
return query.get_peers_uuids()
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
async def convert_object_type(
|
|
92
|
-
node: Node, target_schema: NodeSchema, mapping: dict[str, InputForDestField], branch: Branch, db: InfrahubDatabase
|
|
93
|
-
) -> Node:
|
|
94
|
-
"""Delete the node and return the new created one. If creation fails, the node is not deleted, and raise an error.
|
|
95
|
-
An extra check is performed on input node peers relationships to make sure they are still valid."""
|
|
96
|
-
|
|
97
|
-
node_schema = node.get_schema()
|
|
98
|
-
if not isinstance(node_schema, NodeSchema):
|
|
99
|
-
raise ValueError(f"Only a node with a NodeSchema can be converted, got {type(node_schema)}")
|
|
100
|
-
|
|
101
|
-
async with db.start_transaction() as dbt:
|
|
102
|
-
deleted_node_out_rels_peer_ids = await get_out_rels_peers_ids(node=node, db=dbt)
|
|
103
|
-
deleted_node_unidir_rels_peer_ids = await get_unidirectional_rels_peers_ids(node=node, db=dbt, branch=branch)
|
|
104
|
-
|
|
105
|
-
# Delete the node, so we delete relationships with peers as well, which might temporarily break cardinality constraints
|
|
106
|
-
# but they should be restored when creating the new node.
|
|
107
|
-
deleted_nodes = await NodeManager.delete(db=dbt, branch=branch, nodes=[node], cascade_delete=False)
|
|
108
|
-
if len(deleted_nodes) != 1:
|
|
109
|
-
raise ValueError(f"Deleted {len(deleted_nodes)} nodes instead of 1")
|
|
110
|
-
|
|
111
|
-
data_new_node = await build_data_new_node(dbt, mapping, node)
|
|
112
|
-
node_created = await create_node(
|
|
113
|
-
data=data_new_node,
|
|
114
|
-
db=dbt,
|
|
115
|
-
branch=branch,
|
|
116
|
-
schema=target_schema,
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
# Make sure relationships with constraints are not broken by retrieving them
|
|
120
|
-
peers_ids = deleted_node_out_rels_peer_ids + deleted_node_unidir_rels_peer_ids
|
|
121
|
-
peers = await NodeManager.get_many(ids=peers_ids, db=dbt, prefetch_relationships=True, branch=branch)
|
|
122
|
-
for peer in peers.values():
|
|
123
|
-
peer.validate_relationships()
|
|
124
|
-
|
|
125
|
-
# If the node had some value reserved in any Pools / Resource Manager, we need to change the identifier of the reservation(s)
|
|
126
|
-
query = await PoolChangeReserved.init(
|
|
127
|
-
db=dbt,
|
|
128
|
-
existing_identifier=node.get_id(),
|
|
129
|
-
new_identifier=node_created.get_id(),
|
|
130
|
-
branch=branch,
|
|
131
|
-
)
|
|
132
|
-
await query.execute(db=dbt)
|
|
133
|
-
|
|
134
|
-
return node_created
|
|
File without changes
|
|
File without changes
|
|
File without changes
|