infrahub-server 1.1.6__py3-none-any.whl → 1.2.0b1__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/artifact.py +16 -4
- infrahub/api/dependencies.py +8 -0
- infrahub/api/oauth2.py +0 -1
- infrahub/api/oidc.py +0 -1
- infrahub/api/query.py +18 -7
- infrahub/api/schema.py +32 -6
- infrahub/api/transformation.py +12 -5
- infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +5 -3
- infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +26 -25
- infrahub/cli/__init__.py +0 -2
- infrahub/cli/db.py +6 -7
- infrahub/cli/events.py +8 -3
- infrahub/cli/git_agent.py +9 -7
- infrahub/cli/tasks.py +4 -6
- infrahub/computed_attribute/models.py +1 -1
- infrahub/computed_attribute/tasks.py +64 -17
- infrahub/computed_attribute/triggers.py +90 -0
- infrahub/config.py +1 -1
- infrahub/context.py +39 -0
- infrahub/core/account.py +5 -8
- infrahub/core/attribute.py +54 -22
- infrahub/core/branch/models.py +4 -4
- infrahub/core/branch/tasks.py +137 -129
- infrahub/core/changelog/__init__.py +0 -0
- infrahub/core/changelog/diff.py +283 -0
- infrahub/core/changelog/models.py +499 -0
- infrahub/core/constants/__init__.py +43 -2
- infrahub/core/constants/infrahubkind.py +1 -0
- infrahub/core/constants/schema.py +2 -0
- infrahub/core/diff/combiner.py +12 -8
- infrahub/core/diff/coordinator.py +49 -70
- infrahub/core/diff/data_check_synchronizer.py +86 -7
- infrahub/core/diff/enricher/aggregated.py +3 -3
- infrahub/core/diff/enricher/cardinality_one.py +7 -7
- infrahub/core/diff/enricher/hierarchy.py +22 -7
- infrahub/core/diff/enricher/labels.py +19 -4
- infrahub/core/diff/enricher/path_identifier.py +7 -9
- infrahub/core/diff/enricher/summary_counts.py +3 -1
- infrahub/core/diff/merger/merger.py +8 -4
- infrahub/core/diff/model/path.py +76 -35
- infrahub/core/diff/parent_node_adder.py +78 -0
- infrahub/core/diff/payload_builder.py +13 -2
- infrahub/core/diff/query/all_conflicts.py +6 -3
- infrahub/core/diff/query/artifact.py +1 -1
- infrahub/core/diff/query/delete_query.py +1 -1
- infrahub/core/diff/query/diff_get.py +3 -2
- infrahub/core/diff/query/diff_summary.py +1 -1
- infrahub/core/diff/query/field_specifiers.py +3 -1
- infrahub/core/diff/query/field_summary.py +3 -2
- infrahub/core/diff/query/filters.py +14 -3
- infrahub/core/diff/query/get_conflict_query.py +1 -1
- infrahub/core/diff/query/has_conflicts_query.py +6 -3
- infrahub/core/diff/query/merge.py +3 -3
- infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +4 -4
- infrahub/core/diff/query/roots_metadata.py +9 -2
- infrahub/core/diff/query/save.py +233 -142
- infrahub/core/diff/query/summary_counts_enricher.py +267 -0
- infrahub/core/diff/query/time_range_query.py +3 -2
- infrahub/core/diff/query/update_conflict_query.py +1 -1
- infrahub/core/diff/query_parser.py +49 -24
- infrahub/core/diff/repository/deserializer.py +32 -28
- infrahub/core/diff/repository/repository.py +215 -41
- infrahub/core/diff/tasks.py +13 -12
- infrahub/core/enums.py +1 -1
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/index.py +3 -0
- infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
- infrahub/core/ipam/reconciler.py +1 -1
- infrahub/core/ipam/tasks.py +2 -3
- infrahub/core/manager.py +20 -15
- infrahub/core/merge.py +5 -2
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
- infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
- infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
- infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
- infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
- infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
- infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
- infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
- infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
- infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
- infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
- infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
- infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
- infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
- infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
- infrahub/core/migrations/graph/m020_add_generate_template_attr.py +48 -0
- infrahub/core/migrations/query/attribute_add.py +1 -1
- infrahub/core/migrations/query/attribute_rename.py +1 -1
- infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
- infrahub/core/migrations/query/node_duplicate.py +39 -19
- infrahub/core/migrations/query/relationship_duplicate.py +1 -1
- infrahub/core/migrations/query/schema_attribute_update.py +1 -1
- infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
- infrahub/core/migrations/schema/node_remove.py +27 -13
- infrahub/core/migrations/schema/tasks.py +5 -5
- infrahub/core/migrations/shared.py +4 -4
- infrahub/core/models.py +7 -8
- infrahub/core/node/__init__.py +170 -46
- infrahub/core/node/base.py +1 -1
- infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
- infrahub/core/node/delete_validator.py +4 -4
- infrahub/core/node/ipam.py +13 -8
- infrahub/core/node/permissions.py +4 -0
- infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
- infrahub/core/node/standard.py +3 -5
- infrahub/core/property.py +1 -1
- infrahub/core/protocols.py +6 -0
- infrahub/core/protocols_base.py +4 -2
- infrahub/core/query/__init__.py +2 -5
- infrahub/core/query/attribute.py +9 -9
- infrahub/core/query/branch.py +5 -5
- infrahub/core/query/delete.py +1 -1
- infrahub/core/query/diff.py +45 -7
- infrahub/core/query/ipam.py +4 -4
- infrahub/core/query/node.py +19 -14
- infrahub/core/query/relationship.py +213 -26
- infrahub/core/query/resource_manager.py +13 -11
- infrahub/core/query/standard_node.py +6 -6
- infrahub/core/query/task.py +3 -3
- infrahub/core/query/task_log.py +1 -1
- infrahub/core/query/utils.py +5 -5
- infrahub/core/registry.py +0 -2
- infrahub/core/relationship/constraints/count.py +1 -1
- infrahub/core/relationship/constraints/peer_kind.py +1 -1
- infrahub/core/relationship/model.py +76 -38
- infrahub/core/schema/__init__.py +6 -4
- infrahub/core/schema/attribute_schema.py +8 -0
- infrahub/core/schema/basenode_schema.py +13 -3
- infrahub/core/schema/definitions/core/__init__.py +153 -0
- infrahub/core/schema/definitions/core/account.py +168 -0
- infrahub/core/schema/definitions/core/artifact.py +127 -0
- infrahub/core/schema/definitions/core/builtin.py +21 -0
- infrahub/core/schema/definitions/core/check.py +60 -0
- infrahub/core/schema/definitions/core/generator.py +96 -0
- infrahub/core/schema/definitions/core/graphql_query.py +77 -0
- infrahub/core/schema/definitions/core/group.py +105 -0
- infrahub/core/schema/definitions/core/ipam.py +252 -0
- infrahub/core/schema/definitions/core/lineage.py +17 -0
- infrahub/core/schema/definitions/core/menu.py +46 -0
- infrahub/core/schema/definitions/core/permission.py +161 -0
- infrahub/core/schema/definitions/core/profile.py +29 -0
- infrahub/core/schema/definitions/core/propose_change.py +88 -0
- infrahub/core/schema/definitions/core/propose_change_comment.py +188 -0
- infrahub/core/schema/definitions/core/propose_change_validator.py +326 -0
- infrahub/core/schema/definitions/core/repository.py +280 -0
- infrahub/core/schema/definitions/core/resource_pool.py +180 -0
- infrahub/core/schema/definitions/core/template.py +12 -0
- infrahub/core/schema/definitions/core/transform.py +87 -0
- infrahub/core/schema/definitions/core/webhook.py +108 -0
- infrahub/core/schema/definitions/internal.py +16 -0
- infrahub/core/schema/generated/genericnode_schema.py +5 -0
- infrahub/core/schema/generated/node_schema.py +5 -0
- infrahub/core/schema/generic_schema.py +5 -1
- infrahub/core/schema/manager.py +45 -42
- infrahub/core/schema/node_schema.py +4 -0
- infrahub/core/schema/profile_schema.py +4 -0
- infrahub/core/schema/relationship_schema.py +10 -2
- infrahub/core/schema/schema_branch.py +260 -16
- infrahub/core/schema/template_schema.py +36 -0
- infrahub/core/task/user_task.py +7 -5
- infrahub/core/timestamp.py +3 -3
- infrahub/core/utils.py +3 -2
- infrahub/core/validators/attribute/choices.py +1 -1
- infrahub/core/validators/attribute/enum.py +1 -1
- infrahub/core/validators/attribute/kind.py +1 -1
- infrahub/core/validators/attribute/length.py +1 -1
- infrahub/core/validators/attribute/optional.py +1 -1
- infrahub/core/validators/attribute/regex.py +1 -1
- infrahub/core/validators/attribute/unique.py +1 -1
- infrahub/core/validators/checks_runner.py +37 -0
- infrahub/core/validators/node/generate_profile.py +1 -1
- infrahub/core/validators/node/hierarchy.py +1 -1
- infrahub/core/validators/query.py +1 -1
- infrahub/core/validators/relationship/count.py +1 -1
- infrahub/core/validators/relationship/optional.py +1 -1
- infrahub/core/validators/relationship/peer.py +1 -1
- infrahub/core/validators/tasks.py +8 -6
- infrahub/core/validators/uniqueness/query.py +20 -17
- infrahub/database/__init__.py +16 -2
- infrahub/database/memgraph.py +1 -1
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
- infrahub/dependencies/builder/diff/combiner.py +1 -1
- infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
- infrahub/dependencies/builder/diff/coordinator.py +0 -2
- infrahub/dependencies/builder/diff/deserializer.py +4 -2
- infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
- infrahub/dependencies/builder/diff/enricher/summary_counts.py +1 -1
- infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
- infrahub/events/artifact_action.py +76 -0
- infrahub/events/branch_action.py +50 -21
- infrahub/events/group_action.py +117 -0
- infrahub/events/models.py +164 -51
- infrahub/events/node_action.py +70 -8
- infrahub/events/repository_action.py +8 -8
- infrahub/events/schema_action.py +21 -8
- infrahub/exceptions.py +9 -0
- infrahub/generators/models.py +1 -0
- infrahub/generators/tasks.py +34 -15
- infrahub/git/base.py +3 -5
- infrahub/git/constants.py +0 -1
- infrahub/git/integrator.py +60 -36
- infrahub/git/models.py +80 -1
- infrahub/git/repository.py +7 -8
- infrahub/git/tasks.py +432 -112
- infrahub/git_credential/helper.py +2 -3
- infrahub/graphql/analyzer.py +572 -11
- infrahub/graphql/app.py +34 -26
- infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
- infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
- infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
- infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
- infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
- infrahub/graphql/context.py +33 -0
- infrahub/graphql/enums.py +1 -1
- infrahub/graphql/initialization.py +5 -1
- infrahub/graphql/loaders/node.py +2 -2
- infrahub/graphql/manager.py +63 -63
- infrahub/graphql/mutations/account.py +20 -13
- infrahub/graphql/mutations/artifact_definition.py +16 -12
- infrahub/graphql/mutations/branch.py +86 -40
- infrahub/graphql/mutations/computed_attribute.py +24 -13
- infrahub/graphql/mutations/diff.py +54 -14
- infrahub/graphql/mutations/diff_conflict.py +14 -8
- infrahub/graphql/mutations/generator.py +83 -0
- infrahub/graphql/mutations/graphql_query.py +19 -11
- infrahub/graphql/mutations/ipam.py +25 -23
- infrahub/graphql/mutations/main.py +243 -50
- infrahub/graphql/mutations/menu.py +10 -10
- infrahub/graphql/mutations/proposed_change.py +36 -28
- infrahub/graphql/mutations/relationship.py +343 -104
- infrahub/graphql/mutations/repository.py +41 -35
- infrahub/graphql/mutations/resource_manager.py +26 -26
- infrahub/graphql/mutations/schema.py +66 -33
- infrahub/graphql/mutations/tasks.py +16 -10
- infrahub/graphql/parser.py +1 -1
- infrahub/graphql/permissions.py +3 -10
- infrahub/graphql/queries/account.py +22 -18
- infrahub/graphql/queries/branch.py +6 -4
- infrahub/graphql/queries/diff/tree.py +63 -52
- infrahub/graphql/queries/event.py +115 -0
- infrahub/graphql/queries/internal.py +3 -3
- infrahub/graphql/queries/ipam.py +23 -18
- infrahub/graphql/queries/relationship.py +11 -10
- infrahub/graphql/queries/resource_manager.py +43 -27
- infrahub/graphql/queries/search.py +9 -8
- infrahub/graphql/queries/status.py +12 -9
- infrahub/graphql/queries/task.py +11 -9
- infrahub/graphql/resolvers/resolver.py +69 -43
- infrahub/graphql/resolvers/single_relationship.py +16 -10
- infrahub/graphql/schema.py +4 -0
- infrahub/graphql/subscription/__init__.py +1 -1
- infrahub/graphql/subscription/events.py +1 -1
- infrahub/graphql/subscription/graphql_query.py +8 -8
- infrahub/graphql/types/branch.py +2 -2
- infrahub/graphql/types/common.py +6 -1
- infrahub/graphql/types/context.py +12 -0
- infrahub/graphql/types/enums.py +2 -0
- infrahub/graphql/types/event.py +158 -0
- infrahub/graphql/types/interface.py +2 -2
- infrahub/graphql/types/node.py +3 -3
- infrahub/graphql/types/permission.py +2 -2
- infrahub/graphql/types/relationship.py +3 -3
- infrahub/graphql/types/standard_node.py +9 -11
- infrahub/graphql/utils.py +28 -182
- infrahub/groups/tasks.py +2 -3
- infrahub/lock.py +21 -21
- infrahub/menu/generator.py +0 -1
- infrahub/menu/menu.py +116 -138
- infrahub/menu/models.py +4 -4
- infrahub/message_bus/__init__.py +11 -13
- infrahub/message_bus/messages/__init__.py +0 -14
- infrahub/message_bus/messages/check_generator_run.py +1 -3
- infrahub/message_bus/messages/event_branch_merge.py +3 -0
- infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
- infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
- infrahub/message_bus/messages/send_echo_request.py +1 -1
- infrahub/message_bus/operations/__init__.py +4 -13
- infrahub/message_bus/operations/check/__init__.py +2 -2
- infrahub/message_bus/operations/check/generator.py +1 -3
- infrahub/message_bus/operations/event/branch.py +7 -3
- infrahub/message_bus/operations/event/schema.py +1 -1
- infrahub/message_bus/operations/event/worker.py +0 -3
- infrahub/message_bus/operations/finalize/validator.py +1 -1
- infrahub/message_bus/operations/git/file.py +2 -2
- infrahub/message_bus/operations/git/repository.py +1 -1
- infrahub/message_bus/operations/requests/__init__.py +0 -4
- infrahub/message_bus/operations/requests/generator_definition.py +2 -4
- infrahub/message_bus/operations/requests/proposed_change.py +37 -20
- infrahub/message_bus/operations/send/echo.py +1 -1
- infrahub/message_bus/types.py +1 -1
- infrahub/permissions/__init__.py +2 -1
- infrahub/permissions/globals.py +15 -0
- infrahub/permissions/types.py +26 -0
- infrahub/pools/prefix.py +29 -165
- infrahub/prefect_server/__init__.py +0 -0
- infrahub/prefect_server/app.py +18 -0
- infrahub/prefect_server/database.py +20 -0
- infrahub/prefect_server/events.py +28 -0
- infrahub/prefect_server/models.py +46 -0
- infrahub/proposed_change/models.py +18 -1
- infrahub/proposed_change/tasks.py +195 -53
- infrahub/pytest_plugin.py +4 -4
- infrahub/server.py +13 -12
- infrahub/services/__init__.py +148 -63
- infrahub/services/adapters/cache/__init__.py +11 -11
- infrahub/services/adapters/cache/nats.py +42 -25
- infrahub/services/adapters/cache/redis.py +3 -11
- infrahub/services/adapters/event/__init__.py +10 -18
- infrahub/services/adapters/http/__init__.py +0 -5
- infrahub/services/adapters/http/httpx.py +22 -15
- infrahub/services/adapters/message_bus/__init__.py +25 -8
- infrahub/services/adapters/message_bus/local.py +9 -7
- infrahub/services/adapters/message_bus/nats.py +14 -8
- infrahub/services/adapters/message_bus/rabbitmq.py +23 -10
- infrahub/services/adapters/workflow/__init__.py +11 -8
- infrahub/services/adapters/workflow/local.py +27 -6
- infrahub/services/adapters/workflow/worker.py +23 -7
- infrahub/services/component.py +43 -40
- infrahub/services/protocols.py +7 -7
- infrahub/services/scheduler.py +30 -29
- infrahub/storage.py +2 -4
- infrahub/task_manager/constants.py +1 -1
- infrahub/task_manager/event.py +261 -0
- infrahub/task_manager/models.py +147 -3
- infrahub/task_manager/task.py +1 -1
- infrahub/tasks/artifact.py +19 -18
- infrahub/tasks/registry.py +1 -1
- infrahub/tasks/telemetry.py +13 -14
- infrahub/transformations/tasks.py +3 -5
- infrahub/trigger/__init__.py +0 -0
- infrahub/trigger/catalogue.py +16 -0
- infrahub/trigger/constants.py +9 -0
- infrahub/trigger/models.py +105 -0
- infrahub/trigger/tasks.py +91 -0
- infrahub/types.py +1 -1
- infrahub/utils.py +1 -1
- infrahub/webhook/constants.py +0 -2
- infrahub/webhook/models.py +161 -40
- infrahub/webhook/tasks.py +123 -202
- infrahub/webhook/triggers.py +27 -0
- infrahub/workers/infrahub_async.py +36 -25
- infrahub/workers/utils.py +63 -0
- infrahub/workflows/catalogue.py +71 -52
- infrahub/workflows/initialization.py +14 -8
- infrahub/workflows/models.py +28 -4
- infrahub/workflows/utils.py +1 -1
- infrahub_sdk/client.py +8 -0
- infrahub_sdk/ctl/branch.py +3 -2
- infrahub_sdk/ctl/check.py +3 -3
- infrahub_sdk/ctl/cli_commands.py +16 -11
- infrahub_sdk/ctl/exceptions.py +0 -6
- infrahub_sdk/ctl/exporter.py +1 -1
- infrahub_sdk/ctl/generator.py +5 -5
- infrahub_sdk/ctl/importer.py +3 -2
- infrahub_sdk/ctl/menu.py +1 -1
- infrahub_sdk/ctl/object.py +1 -1
- infrahub_sdk/ctl/repository.py +23 -15
- infrahub_sdk/ctl/schema.py +2 -2
- infrahub_sdk/ctl/utils.py +4 -19
- infrahub_sdk/ctl/validate.py +2 -1
- infrahub_sdk/exceptions.py +12 -0
- infrahub_sdk/generator.py +3 -0
- infrahub_sdk/node.py +4 -4
- infrahub_sdk/protocols.py +21 -8
- infrahub_sdk/schema/__init__.py +14 -2
- infrahub_sdk/schema/main.py +7 -0
- infrahub_sdk/task/__init__.py +1 -0
- infrahub_sdk/task/constants.py +3 -0
- infrahub_sdk/task/exceptions.py +25 -0
- infrahub_sdk/task/manager.py +545 -0
- infrahub_sdk/task/models.py +74 -0
- infrahub_sdk/timestamp.py +134 -33
- infrahub_sdk/utils.py +39 -1
- infrahub_sdk/yaml.py +2 -3
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/METADATA +47 -12
- infrahub_server-1.2.0b1.dist-info/RECORD +725 -0
- infrahub_testcontainers/container.py +14 -6
- infrahub_testcontainers/docker-compose.test.yml +24 -5
- infrahub_testcontainers/haproxy.cfg +43 -0
- infrahub_testcontainers/helpers.py +85 -1
- infrahub/core/branch/constants.py +0 -2
- infrahub/core/schema/definitions/core.py +0 -2274
- infrahub/graphql/query.py +0 -52
- infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
- infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
- infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
- infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
- infrahub/message_bus/messages/request_repository_checks.py +0 -12
- infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
- infrahub/message_bus/operations/check/repository.py +0 -293
- infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
- infrahub/message_bus/operations/requests/repository.py +0 -133
- infrahub/schema/constants.py +0 -1
- infrahub/schema/tasks.py +0 -76
- infrahub/services/adapters/database/__init__.py +0 -9
- infrahub_sdk/ctl/_file.py +0 -13
- infrahub_server-1.1.6.dist-info/RECORD +0 -681
- /infrahub/{schema → artifacts}/__init__.py +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/WHEEL +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/entry_points.txt +0 -0
|
@@ -12,6 +12,7 @@ from typing_extensions import Self
|
|
|
12
12
|
|
|
13
13
|
from infrahub.computed_attribute.constants import VALID_KINDS as VALID_COMPUTED_ATTRIBUTE_KINDS
|
|
14
14
|
from infrahub.core.constants import (
|
|
15
|
+
OBJECT_TEMPLATE_NAME_ATTR,
|
|
15
16
|
RESERVED_ATTR_GEN_NAMES,
|
|
16
17
|
RESERVED_ATTR_REL_NAMES,
|
|
17
18
|
RESTRICTED_NAMESPACES,
|
|
@@ -43,6 +44,7 @@ from infrahub.core.schema import (
|
|
|
43
44
|
RelationshipSchema,
|
|
44
45
|
SchemaAttributePath,
|
|
45
46
|
SchemaRoot,
|
|
47
|
+
TemplateSchema,
|
|
46
48
|
)
|
|
47
49
|
from infrahub.core.schema.definitions.core import core_profile_schema_definition
|
|
48
50
|
from infrahub.core.validators import CONSTRAINT_VALIDATOR_MAP
|
|
@@ -53,6 +55,7 @@ from infrahub.types import ATTRIBUTE_TYPES
|
|
|
53
55
|
from infrahub.utils import format_label
|
|
54
56
|
from infrahub.visuals import select_color
|
|
55
57
|
|
|
58
|
+
from ..constants.schema import PARENT_CHILD_IDENTIFIER
|
|
56
59
|
from .constants import INTERNAL_SCHEMA_NODE_KINDS, SchemaNamespace
|
|
57
60
|
from .schema_branch_computed import ComputedAttributes
|
|
58
61
|
|
|
@@ -62,9 +65,6 @@ if TYPE_CHECKING:
|
|
|
62
65
|
from pydantic import ValidationInfo
|
|
63
66
|
|
|
64
67
|
|
|
65
|
-
# pylint: disable=redefined-builtin,too-many-public-methods,too-many-lines
|
|
66
|
-
|
|
67
|
-
|
|
68
68
|
class SchemaBranch:
|
|
69
69
|
def __init__(
|
|
70
70
|
self,
|
|
@@ -78,19 +78,21 @@ class SchemaBranch:
|
|
|
78
78
|
self.nodes: dict[str, str] = {}
|
|
79
79
|
self.generics: dict[str, str] = {}
|
|
80
80
|
self.profiles: dict[str, str] = {}
|
|
81
|
+
self.templates: dict[str, str] = {}
|
|
81
82
|
self.computed_attributes = computed_attributes or ComputedAttributes()
|
|
82
83
|
|
|
83
84
|
if data:
|
|
84
85
|
self.nodes = data.get("nodes", {})
|
|
85
86
|
self.generics = data.get("generics", {})
|
|
86
87
|
self.profiles = data.get("profiles", {})
|
|
88
|
+
self.templates = data.get("templates", {})
|
|
87
89
|
|
|
88
90
|
@classmethod
|
|
89
91
|
def __get_validators__(cls) -> Iterator[Callable[..., Any]]: # noqa: PLW3201
|
|
90
92
|
yield cls.validate
|
|
91
93
|
|
|
92
94
|
@classmethod
|
|
93
|
-
def validate(cls, v: Any, info: ValidationInfo) -> Self: #
|
|
95
|
+
def validate(cls, v: Any, info: ValidationInfo) -> Self: # noqa: ARG003
|
|
94
96
|
if isinstance(v, cls):
|
|
95
97
|
return v
|
|
96
98
|
if isinstance(v, dict):
|
|
@@ -109,6 +111,10 @@ class SchemaBranch:
|
|
|
109
111
|
def profile_names(self) -> list[str]:
|
|
110
112
|
return list(self.profiles.keys())
|
|
111
113
|
|
|
114
|
+
@property
|
|
115
|
+
def template_names(self) -> list[str]:
|
|
116
|
+
return list(self.templates.keys())
|
|
117
|
+
|
|
112
118
|
def get_all_kind_id_map(self, exclude_profiles: bool = False) -> dict[str, str]:
|
|
113
119
|
kind_id_map = {}
|
|
114
120
|
if exclude_profiles:
|
|
@@ -124,7 +130,7 @@ class SchemaBranch:
|
|
|
124
130
|
|
|
125
131
|
@property
|
|
126
132
|
def all_names(self) -> list[str]:
|
|
127
|
-
return self.node_names + self.generic_names + self.profile_names
|
|
133
|
+
return self.node_names + self.generic_names + self.profile_names + self.template_names
|
|
128
134
|
|
|
129
135
|
def get_hash(self) -> str:
|
|
130
136
|
"""Calculate the hash for this objects based on the content of nodes and generics.
|
|
@@ -142,13 +148,14 @@ class SchemaBranch:
|
|
|
142
148
|
return SchemaBranchHash(main=self.get_hash(), nodes=self.nodes, generics=self.generics)
|
|
143
149
|
|
|
144
150
|
def to_dict(self) -> dict[str, Any]:
|
|
145
|
-
return {"nodes": self.nodes, "generics": self.generics, "profiles": self.profiles}
|
|
151
|
+
return {"nodes": self.nodes, "generics": self.generics, "profiles": self.profiles, "templates": self.templates}
|
|
146
152
|
|
|
147
153
|
def to_dict_schema_object(self, duplicate: bool = False) -> dict[str, dict[str, MainSchemaTypes]]:
|
|
148
154
|
return {
|
|
149
155
|
"nodes": {name: self.get(name, duplicate=duplicate) for name in self.nodes},
|
|
150
156
|
"profiles": {name: self.get(name, duplicate=duplicate) for name in self.profiles},
|
|
151
157
|
"generics": {name: self.get(name, duplicate=duplicate) for name in self.generics},
|
|
158
|
+
"templates": {name: self.get(name, duplicate=duplicate) for name in self.templates},
|
|
152
159
|
}
|
|
153
160
|
|
|
154
161
|
@classmethod
|
|
@@ -157,10 +164,11 @@ class SchemaBranch:
|
|
|
157
164
|
"nodes": NodeSchema,
|
|
158
165
|
"generics": GenericSchema,
|
|
159
166
|
"profiles": ProfileSchema,
|
|
167
|
+
"templates": TemplateSchema,
|
|
160
168
|
}
|
|
161
169
|
|
|
162
170
|
cache: dict[str, MainSchemaTypes] = {}
|
|
163
|
-
nodes: dict[str, dict[str, str]] = {"nodes": {}, "generics": {}, "profiles": {}}
|
|
171
|
+
nodes: dict[str, dict[str, str]] = {"nodes": {}, "generics": {}, "profiles": {}, "templates": {}}
|
|
164
172
|
|
|
165
173
|
for node_type, node_class in type_mapping.items():
|
|
166
174
|
for node_name, node_data in data[node_type].items():
|
|
@@ -281,6 +289,8 @@ class SchemaBranch:
|
|
|
281
289
|
self.generics[name] = schema_hash
|
|
282
290
|
elif "Profile" in schema.__class__.__name__:
|
|
283
291
|
self.profiles[name] = schema_hash
|
|
292
|
+
elif "Template" in schema.__class__.__name__:
|
|
293
|
+
self.templates[name] = schema_hash
|
|
284
294
|
|
|
285
295
|
return schema_hash
|
|
286
296
|
|
|
@@ -292,6 +302,7 @@ class SchemaBranch:
|
|
|
292
302
|
|
|
293
303
|
If duplicate is set to false, the real object will be returned.
|
|
294
304
|
"""
|
|
305
|
+
|
|
295
306
|
key = None
|
|
296
307
|
if name in self.nodes:
|
|
297
308
|
key = self.nodes[name]
|
|
@@ -299,6 +310,8 @@ class SchemaBranch:
|
|
|
299
310
|
key = self.generics[name]
|
|
300
311
|
elif name in self.profiles:
|
|
301
312
|
key = self.profiles[name]
|
|
313
|
+
elif name in self.templates:
|
|
314
|
+
key = self.templates[name]
|
|
302
315
|
|
|
303
316
|
if key and duplicate:
|
|
304
317
|
return self._cache[key].duplicate()
|
|
@@ -330,6 +343,13 @@ class SchemaBranch:
|
|
|
330
343
|
raise ValueError(f"{name!r} is not of type ProfileSchema")
|
|
331
344
|
return item
|
|
332
345
|
|
|
346
|
+
def get_template(self, name: str, duplicate: bool = True) -> TemplateSchema:
|
|
347
|
+
"""Access a specific TemplateSchema, defined by its kind."""
|
|
348
|
+
item = self.get(name=name, duplicate=duplicate)
|
|
349
|
+
if not isinstance(item, TemplateSchema):
|
|
350
|
+
raise ValueError(f"{name!r} is not of type TemplateSchema")
|
|
351
|
+
return item
|
|
352
|
+
|
|
333
353
|
def delete(self, name: str) -> None:
|
|
334
354
|
if name in self.nodes:
|
|
335
355
|
del self.nodes[name]
|
|
@@ -337,6 +357,8 @@ class SchemaBranch:
|
|
|
337
357
|
del self.generics[name]
|
|
338
358
|
elif name in self.profiles:
|
|
339
359
|
del self.profiles[name]
|
|
360
|
+
elif name in self.templates:
|
|
361
|
+
del self.templates[name]
|
|
340
362
|
else:
|
|
341
363
|
raise SchemaNotFoundError(
|
|
342
364
|
branch_name=self.name, identifier=name, message=f"Unable to find the schema {name!r} in the registry"
|
|
@@ -431,7 +453,7 @@ class SchemaBranch:
|
|
|
431
453
|
|
|
432
454
|
def generate_fields_for_display_label(self, name: str) -> Optional[dict]:
|
|
433
455
|
node = self.get(name=name, duplicate=False)
|
|
434
|
-
if isinstance(node,
|
|
456
|
+
if isinstance(node, NodeSchema | ProfileSchema | TemplateSchema):
|
|
435
457
|
return node.generate_fields_for_display_label()
|
|
436
458
|
|
|
437
459
|
fields: dict[str, Union[str, None, dict[str, None]]] = {}
|
|
@@ -490,6 +512,8 @@ class SchemaBranch:
|
|
|
490
512
|
self.process_inheritance()
|
|
491
513
|
self.process_hierarchy()
|
|
492
514
|
self.process_branch_support()
|
|
515
|
+
self.manage_object_template_schemas()
|
|
516
|
+
self.manage_object_template_relationships()
|
|
493
517
|
self.manage_profile_schemas()
|
|
494
518
|
self.manage_profile_relationships()
|
|
495
519
|
self.add_hierarchy_generic()
|
|
@@ -520,6 +544,9 @@ class SchemaBranch:
|
|
|
520
544
|
self.process_relationships()
|
|
521
545
|
self.process_human_friendly_id()
|
|
522
546
|
|
|
547
|
+
def _generate_identifier_string(self, node_kind: str, peer_kind: str) -> str:
|
|
548
|
+
return "__".join(sorted([node_kind, peer_kind])).lower()
|
|
549
|
+
|
|
523
550
|
def generate_identifiers(self) -> None:
|
|
524
551
|
"""Generate the identifier for all relationships if it's not already present."""
|
|
525
552
|
for name in self.all_names:
|
|
@@ -532,7 +559,7 @@ class SchemaBranch:
|
|
|
532
559
|
for rel in node.relationships:
|
|
533
560
|
if rel.identifier:
|
|
534
561
|
continue
|
|
535
|
-
rel.identifier =
|
|
562
|
+
rel.identifier = self._generate_identifier_string(node.kind, rel.peer)
|
|
536
563
|
self.set(name=name, schema=node)
|
|
537
564
|
|
|
538
565
|
def validate_identifiers(self) -> None:
|
|
@@ -1267,7 +1294,6 @@ class SchemaBranch:
|
|
|
1267
1294
|
|
|
1268
1295
|
if either node on a relationship support branch, the relationship must be branch aware.
|
|
1269
1296
|
"""
|
|
1270
|
-
# pylint: disable=too-many-branches
|
|
1271
1297
|
|
|
1272
1298
|
for name in self.all_names:
|
|
1273
1299
|
node = self.get(name=name, duplicate=False)
|
|
@@ -1329,7 +1355,6 @@ class SchemaBranch:
|
|
|
1329
1355
|
|
|
1330
1356
|
def process_cardinality_counts(self) -> None:
|
|
1331
1357
|
"""Ensure that all relationships with a cardinality of ONE have a min_count and max_count of 1."""
|
|
1332
|
-
# pylint: disable=too-many-branches
|
|
1333
1358
|
|
|
1334
1359
|
for name in self.all_names:
|
|
1335
1360
|
node = self.get(name=name, duplicate=False)
|
|
@@ -1416,7 +1441,6 @@ class SchemaBranch:
|
|
|
1416
1441
|
self.set(name=name, schema=node)
|
|
1417
1442
|
|
|
1418
1443
|
def cleanup_inherited_elements(self) -> None:
|
|
1419
|
-
# pylint: disable=too-many-branches
|
|
1420
1444
|
for name in self.node_names:
|
|
1421
1445
|
node = self.get_node(name=name, duplicate=False)
|
|
1422
1446
|
|
|
@@ -1512,7 +1536,7 @@ class SchemaBranch:
|
|
|
1512
1536
|
def _get_hierarchy_child_rel(self, peer: str, hierarchical: str | None, read_only: bool) -> RelationshipSchema:
|
|
1513
1537
|
return RelationshipSchema(
|
|
1514
1538
|
name="children",
|
|
1515
|
-
identifier=
|
|
1539
|
+
identifier=PARENT_CHILD_IDENTIFIER,
|
|
1516
1540
|
peer=peer,
|
|
1517
1541
|
kind=RelationshipKind.HIERARCHY,
|
|
1518
1542
|
cardinality=RelationshipCardinality.MANY,
|
|
@@ -1527,7 +1551,7 @@ class SchemaBranch:
|
|
|
1527
1551
|
) -> RelationshipSchema:
|
|
1528
1552
|
return RelationshipSchema(
|
|
1529
1553
|
name="parent",
|
|
1530
|
-
identifier=
|
|
1554
|
+
identifier=PARENT_CHILD_IDENTIFIER,
|
|
1531
1555
|
peer=peer,
|
|
1532
1556
|
kind=RelationshipKind.HIERARCHY,
|
|
1533
1557
|
cardinality=RelationshipCardinality.ONE,
|
|
@@ -1642,7 +1666,7 @@ class SchemaBranch:
|
|
|
1642
1666
|
|
|
1643
1667
|
if new_used_by_profile:
|
|
1644
1668
|
core_profile_schema = self.get(name=InfrahubKind.PROFILE, duplicate=True)
|
|
1645
|
-
core_profile_schema.used_by = sorted(
|
|
1669
|
+
core_profile_schema.used_by = sorted(profile_schema_kinds)
|
|
1646
1670
|
self.set(name=InfrahubKind.PROFILE, schema=core_profile_schema)
|
|
1647
1671
|
|
|
1648
1672
|
if self.has(name=InfrahubKind.NODE):
|
|
@@ -1653,7 +1677,7 @@ class SchemaBranch:
|
|
|
1653
1677
|
if new_used_by_node:
|
|
1654
1678
|
core_node_schema = self.get(name=InfrahubKind.NODE, duplicate=True)
|
|
1655
1679
|
updated_used_by_node = set(chain(profile_schema_kinds, set(core_node_schema.used_by)))
|
|
1656
|
-
core_node_schema.used_by = sorted(
|
|
1680
|
+
core_node_schema.used_by = sorted(updated_used_by_node)
|
|
1657
1681
|
self.set(name=InfrahubKind.NODE, schema=core_node_schema)
|
|
1658
1682
|
|
|
1659
1683
|
def manage_profile_relationships(self) -> None:
|
|
@@ -1746,3 +1770,223 @@ class SchemaBranch:
|
|
|
1746
1770
|
profile.attributes.append(attr)
|
|
1747
1771
|
|
|
1748
1772
|
return profile
|
|
1773
|
+
|
|
1774
|
+
def _get_object_template_kind(self, node_kind: str) -> str:
|
|
1775
|
+
return f"Template{node_kind}"
|
|
1776
|
+
|
|
1777
|
+
def manage_object_template_relationships(self) -> None:
|
|
1778
|
+
"""Add an `object_template` relationship to all nodes that can be created from object templates.
|
|
1779
|
+
|
|
1780
|
+
This relationship allows to record from which template an object has been created.
|
|
1781
|
+
"""
|
|
1782
|
+
for node_name in self.node_names + self.generic_names:
|
|
1783
|
+
node = self.get(name=node_name, duplicate=False)
|
|
1784
|
+
|
|
1785
|
+
if (
|
|
1786
|
+
node.namespace in RESTRICTED_NAMESPACES
|
|
1787
|
+
or not node.generate_template
|
|
1788
|
+
or node.state == HashableModelState.ABSENT
|
|
1789
|
+
):
|
|
1790
|
+
continue
|
|
1791
|
+
|
|
1792
|
+
template_rel_settings: dict[str, Any] = {
|
|
1793
|
+
"name": "object_template",
|
|
1794
|
+
"identifier": "node__objecttemplate",
|
|
1795
|
+
"peer": self._get_object_template_kind(node.kind),
|
|
1796
|
+
"kind": RelationshipKind.TEMPLATE,
|
|
1797
|
+
"cardinality": RelationshipCardinality.ONE,
|
|
1798
|
+
"branch": BranchSupportType.AWARE,
|
|
1799
|
+
"order_weight": 1,
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
# Add relationship between node and template
|
|
1803
|
+
if "object_template" not in node.relationship_names:
|
|
1804
|
+
node_schema = self.get(name=node_name, duplicate=True)
|
|
1805
|
+
|
|
1806
|
+
node_schema.relationships.append(RelationshipSchema(**template_rel_settings))
|
|
1807
|
+
self.set(name=node_name, schema=node_schema)
|
|
1808
|
+
else:
|
|
1809
|
+
has_changes: bool = False
|
|
1810
|
+
rel_template = node.get_relationship(name="object_template")
|
|
1811
|
+
for name, value in template_rel_settings.items():
|
|
1812
|
+
if getattr(rel_template, name) != value:
|
|
1813
|
+
has_changes = True
|
|
1814
|
+
|
|
1815
|
+
if not has_changes:
|
|
1816
|
+
continue
|
|
1817
|
+
|
|
1818
|
+
node_schema = self.get(name=node_name, duplicate=True)
|
|
1819
|
+
rel_template = node_schema.get_relationship(name="object_template")
|
|
1820
|
+
for name, value in template_rel_settings.items():
|
|
1821
|
+
if getattr(rel_template, name) != value:
|
|
1822
|
+
setattr(rel_template, name, value)
|
|
1823
|
+
|
|
1824
|
+
self.set(name=node_name, schema=node_schema)
|
|
1825
|
+
|
|
1826
|
+
def add_relationships_to_template(self, node: NodeSchema) -> None:
|
|
1827
|
+
template_schema = self.get(name=self._get_object_template_kind(node_kind=node.kind), duplicate=False)
|
|
1828
|
+
# Remove previous relationships to account for new ones
|
|
1829
|
+
template_schema.relationships = [
|
|
1830
|
+
r for r in template_schema.relationships if r.kind == RelationshipKind.TEMPLATE
|
|
1831
|
+
]
|
|
1832
|
+
|
|
1833
|
+
for relationship in node.relationships:
|
|
1834
|
+
if relationship.peer in [
|
|
1835
|
+
InfrahubKind.GENERICGROUP,
|
|
1836
|
+
InfrahubKind.PROFILE,
|
|
1837
|
+
] or relationship.kind not in [
|
|
1838
|
+
RelationshipKind.COMPONENT,
|
|
1839
|
+
RelationshipKind.PARENT,
|
|
1840
|
+
RelationshipKind.ATTRIBUTE,
|
|
1841
|
+
RelationshipKind.GENERIC,
|
|
1842
|
+
]:
|
|
1843
|
+
continue
|
|
1844
|
+
|
|
1845
|
+
rel_template_peer = (
|
|
1846
|
+
self._get_object_template_kind(node_kind=relationship.peer)
|
|
1847
|
+
if relationship.kind not in [RelationshipKind.ATTRIBUTE, RelationshipKind.GENERIC]
|
|
1848
|
+
else relationship.peer
|
|
1849
|
+
)
|
|
1850
|
+
template_schema.relationships.append(
|
|
1851
|
+
RelationshipSchema(
|
|
1852
|
+
name=relationship.name,
|
|
1853
|
+
peer=rel_template_peer,
|
|
1854
|
+
kind=relationship.kind,
|
|
1855
|
+
optional=relationship.kind
|
|
1856
|
+
in [RelationshipKind.COMPONENT, RelationshipKind.ATTRIBUTE, RelationshipKind.GENERIC],
|
|
1857
|
+
cardinality=relationship.cardinality,
|
|
1858
|
+
branch=relationship.branch,
|
|
1859
|
+
identifier=self._generate_identifier_string(template_schema.kind, rel_template_peer),
|
|
1860
|
+
min_count=relationship.min_count,
|
|
1861
|
+
max_count=relationship.max_count,
|
|
1862
|
+
label=f"{relationship.name} template".title()
|
|
1863
|
+
if relationship.kind in [RelationshipKind.COMPONENT, RelationshipKind.PARENT]
|
|
1864
|
+
else relationship.name.title(),
|
|
1865
|
+
)
|
|
1866
|
+
)
|
|
1867
|
+
|
|
1868
|
+
def generate_object_template_from_node(self, node: NodeSchema) -> TemplateSchema:
|
|
1869
|
+
core_template_schema = self.get(name=InfrahubKind.OBJECTTEMPLATE, duplicate=False)
|
|
1870
|
+
core_name_attr = core_template_schema.get_attribute(name=OBJECT_TEMPLATE_NAME_ATTR)
|
|
1871
|
+
template_name_attr = AttributeSchema(
|
|
1872
|
+
**core_name_attr.model_dump(exclude=["id", "inherited"]),
|
|
1873
|
+
)
|
|
1874
|
+
template_name_attr.branch = node.branch
|
|
1875
|
+
|
|
1876
|
+
template = TemplateSchema(
|
|
1877
|
+
name=node.kind,
|
|
1878
|
+
namespace="Template",
|
|
1879
|
+
label=f"Object template {node.label}",
|
|
1880
|
+
description=f"Object template for {node.kind}",
|
|
1881
|
+
branch=node.branch,
|
|
1882
|
+
include_in_menu=False,
|
|
1883
|
+
display_labels=["template_name__value"],
|
|
1884
|
+
inherit_from=[InfrahubKind.LINEAGESOURCE, InfrahubKind.OBJECTTEMPLATE, InfrahubKind.NODE],
|
|
1885
|
+
human_friendly_id=["template_name__value"],
|
|
1886
|
+
default_filter="template_name__value",
|
|
1887
|
+
attributes=[template_name_attr],
|
|
1888
|
+
relationships=[
|
|
1889
|
+
RelationshipSchema(
|
|
1890
|
+
name="related_nodes",
|
|
1891
|
+
identifier="node__objecttemplate",
|
|
1892
|
+
peer=node.kind,
|
|
1893
|
+
kind=RelationshipKind.TEMPLATE,
|
|
1894
|
+
cardinality=RelationshipCardinality.MANY,
|
|
1895
|
+
branch=BranchSupportType.AWARE,
|
|
1896
|
+
)
|
|
1897
|
+
],
|
|
1898
|
+
)
|
|
1899
|
+
|
|
1900
|
+
for node_attr in node.attributes:
|
|
1901
|
+
if node_attr.unique:
|
|
1902
|
+
continue
|
|
1903
|
+
|
|
1904
|
+
attr = AttributeSchema(
|
|
1905
|
+
optional=True, **node_attr.model_dump(exclude=["id", "unique", "optional", "read_only", "inherited"])
|
|
1906
|
+
)
|
|
1907
|
+
template.attributes.append(attr)
|
|
1908
|
+
|
|
1909
|
+
return template
|
|
1910
|
+
|
|
1911
|
+
def identify_required_object_templates(
|
|
1912
|
+
self, node_schema: NodeSchema | GenericSchema, identified: set[NodeSchema | GenericSchema]
|
|
1913
|
+
) -> set[NodeSchema]:
|
|
1914
|
+
"""Identify all templates required to turn a given node into a template."""
|
|
1915
|
+
if node_schema in identified:
|
|
1916
|
+
return identified
|
|
1917
|
+
|
|
1918
|
+
identified.add(node_schema)
|
|
1919
|
+
|
|
1920
|
+
for relationship in node_schema.relationships:
|
|
1921
|
+
if relationship.peer in [
|
|
1922
|
+
InfrahubKind.GENERICGROUP,
|
|
1923
|
+
InfrahubKind.PROFILE,
|
|
1924
|
+
] or relationship.kind not in [RelationshipKind.COMPONENT, RelationshipKind.PARENT]:
|
|
1925
|
+
continue
|
|
1926
|
+
|
|
1927
|
+
peer_schema = self.get(name=relationship.peer, duplicate=False)
|
|
1928
|
+
if not isinstance(peer_schema, NodeSchema | GenericSchema) or peer_schema in identified:
|
|
1929
|
+
continue
|
|
1930
|
+
|
|
1931
|
+
identified |= self.identify_required_object_templates(node_schema=peer_schema, identified=identified)
|
|
1932
|
+
|
|
1933
|
+
return identified
|
|
1934
|
+
|
|
1935
|
+
def manage_object_template_schemas(self) -> None:
|
|
1936
|
+
need_templates: set[NodeSchema | GenericSchema] = set()
|
|
1937
|
+
template_schema_kinds: set[str] = set()
|
|
1938
|
+
|
|
1939
|
+
for node_name in self.node_names + self.generic_names:
|
|
1940
|
+
node = self.get(name=node_name, duplicate=False)
|
|
1941
|
+
|
|
1942
|
+
# Delete old object templates if schemas were removed
|
|
1943
|
+
if (
|
|
1944
|
+
node.namespace in RESTRICTED_NAMESPACES
|
|
1945
|
+
or not node.generate_template
|
|
1946
|
+
or node.state == HashableModelState.ABSENT
|
|
1947
|
+
):
|
|
1948
|
+
try:
|
|
1949
|
+
self.delete(name=self._get_object_template_kind(node_kind=node.kind))
|
|
1950
|
+
except SchemaNotFoundError:
|
|
1951
|
+
...
|
|
1952
|
+
continue
|
|
1953
|
+
|
|
1954
|
+
need_templates |= self.identify_required_object_templates(node_schema=node, identified=need_templates)
|
|
1955
|
+
|
|
1956
|
+
# Generate templates with their attributes
|
|
1957
|
+
for node in need_templates:
|
|
1958
|
+
template = self.generate_object_template_from_node(node=node)
|
|
1959
|
+
self.set(name=template.kind, schema=template)
|
|
1960
|
+
template_schema_kinds.add(template.kind)
|
|
1961
|
+
|
|
1962
|
+
# Go back on templates and add relationships to them
|
|
1963
|
+
for node in need_templates:
|
|
1964
|
+
self.add_relationships_to_template(node=node)
|
|
1965
|
+
|
|
1966
|
+
for previous_template in list(self.templates.keys()):
|
|
1967
|
+
# Ensure that we remove previous object template schemas if a node has been renamed
|
|
1968
|
+
if previous_template not in template_schema_kinds:
|
|
1969
|
+
self.delete(name=previous_template)
|
|
1970
|
+
|
|
1971
|
+
if not template_schema_kinds:
|
|
1972
|
+
return
|
|
1973
|
+
|
|
1974
|
+
core_template_schema = self.get(name=InfrahubKind.OBJECTTEMPLATE, duplicate=False)
|
|
1975
|
+
current_used_by_template = set(core_template_schema.used_by)
|
|
1976
|
+
new_used_by_template = template_schema_kinds - current_used_by_template
|
|
1977
|
+
|
|
1978
|
+
if new_used_by_template:
|
|
1979
|
+
core_template_schema = self.get(name=InfrahubKind.OBJECTTEMPLATE, duplicate=True)
|
|
1980
|
+
core_template_schema.used_by = sorted(template_schema_kinds)
|
|
1981
|
+
self.set(name=InfrahubKind.OBJECTTEMPLATE, schema=core_template_schema)
|
|
1982
|
+
|
|
1983
|
+
if self.has(name=InfrahubKind.NODE):
|
|
1984
|
+
core_node_schema = self.get(name=InfrahubKind.NODE, duplicate=False)
|
|
1985
|
+
current_used_by_node = set(core_node_schema.used_by)
|
|
1986
|
+
new_used_by_node = template_schema_kinds - current_used_by_node
|
|
1987
|
+
|
|
1988
|
+
if new_used_by_node:
|
|
1989
|
+
core_node_schema = self.get(name=InfrahubKind.NODE, duplicate=True)
|
|
1990
|
+
updated_used_by_node = set(chain(template_schema_kinds, set(core_node_schema.used_by)))
|
|
1991
|
+
core_node_schema.used_by = sorted(updated_used_by_node)
|
|
1992
|
+
self.set(name=InfrahubKind.NODE, schema=core_node_schema)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from infrahub.core.constants import InfrahubKind
|
|
6
|
+
from infrahub.core.schema.basenode_schema import BaseNodeSchema
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TemplateSchema(BaseNodeSchema):
|
|
10
|
+
inherit_from: list[str] = Field(
|
|
11
|
+
default_factory=list, description="List of Generic Kind that this template is inheriting from"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def is_node_schema(self) -> bool:
|
|
16
|
+
return False
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def is_generic_schema(self) -> bool:
|
|
20
|
+
return False
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def is_profile_schema(self) -> bool:
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def is_template_schema(self) -> bool:
|
|
28
|
+
return True
|
|
29
|
+
|
|
30
|
+
def get_labels(self) -> list[str]:
|
|
31
|
+
"""Return the labels for this object, composed of the kind and the list of Generic this object is inheriting from."""
|
|
32
|
+
|
|
33
|
+
labels: list[str] = [self.kind] + self.inherit_from
|
|
34
|
+
if self.namespace not in ["Schema", "Internal"] and InfrahubKind.GENERICGROUP not in self.inherit_from:
|
|
35
|
+
labels.append(InfrahubKind.OBJECTTEMPLATE)
|
|
36
|
+
return labels
|
infrahub/core/task/user_task.py
CHANGED
|
@@ -80,14 +80,16 @@ class UserTask:
|
|
|
80
80
|
|
|
81
81
|
@classmethod
|
|
82
82
|
def from_graphql_context(
|
|
83
|
-
cls, title: str,
|
|
83
|
+
cls, title: str, graphql_context: GraphqlContext, logger: Optional[Union[BoundLogger, InfrahubLogger]] = None
|
|
84
84
|
) -> Self:
|
|
85
|
-
if not
|
|
85
|
+
if not graphql_context.db or not graphql_context.account_session:
|
|
86
86
|
raise ValueError("db and account_session must be provided to initialize a GraphQLTaskReport")
|
|
87
87
|
|
|
88
|
-
if not logger and
|
|
89
|
-
logger =
|
|
90
|
-
return cls(
|
|
88
|
+
if not logger and graphql_context.service and graphql_context.service.log:
|
|
89
|
+
logger = graphql_context.service.log
|
|
90
|
+
return cls(
|
|
91
|
+
title=title, account_id=graphql_context.account_session.account_id, db=graphql_context.db, logger=logger
|
|
92
|
+
)
|
|
91
93
|
|
|
92
94
|
async def __aenter__(self) -> Self:
|
|
93
95
|
await self.create_task()
|
infrahub/core/timestamp.py
CHANGED
|
@@ -5,12 +5,12 @@ from typing import TYPE_CHECKING, Any
|
|
|
5
5
|
from infrahub_sdk.timestamp import Timestamp as BaseTimestamp
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
|
-
from
|
|
8
|
+
from datetime import datetime
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class Timestamp(BaseTimestamp):
|
|
12
|
-
async def to_graphql(self, *args: Any, **kwargs: Any) ->
|
|
13
|
-
return self.
|
|
12
|
+
async def to_graphql(self, *args: Any, **kwargs: Any) -> datetime: # noqa: ARG002
|
|
13
|
+
return self.to_datetime()
|
|
14
14
|
|
|
15
15
|
def get_query_filter_path(self, rel_name: str = "r") -> tuple[str, dict]:
|
|
16
16
|
"""
|
infrahub/core/utils.py
CHANGED
|
@@ -72,6 +72,7 @@ async def update_relationships_to(ids: list[str], db: InfrahubDatabase, to: Time
|
|
|
72
72
|
query = """
|
|
73
73
|
MATCH ()-[r]->()
|
|
74
74
|
WHERE %(id_func)s(r) IN $ids
|
|
75
|
+
AND r.to IS NULL
|
|
75
76
|
SET r.to = $to
|
|
76
77
|
RETURN %(id_func)s(r)
|
|
77
78
|
""" % {"id_func": db.get_id_function_name()}
|
|
@@ -184,7 +185,7 @@ def parse_node_kind(kind: str) -> NodeKind:
|
|
|
184
185
|
def convert_ip_to_binary_str(
|
|
185
186
|
obj: Union[ipaddress.IPv6Network, ipaddress.IPv4Network, ipaddress.IPv4Interface, ipaddress.IPv6Interface],
|
|
186
187
|
) -> str:
|
|
187
|
-
if isinstance(obj,
|
|
188
|
+
if isinstance(obj, ipaddress.IPv6Network | ipaddress.IPv4Network):
|
|
188
189
|
prefix_bin = f"{int(obj.network_address):b}"
|
|
189
190
|
return prefix_bin.zfill(obj.max_prefixlen)
|
|
190
191
|
|
|
@@ -204,7 +205,7 @@ def build_regex_attr(value: str | int | bool) -> str:
|
|
|
204
205
|
"""
|
|
205
206
|
if isinstance(value, str):
|
|
206
207
|
return f'"{value}"'
|
|
207
|
-
if isinstance(value,
|
|
208
|
+
if isinstance(value, bool | int):
|
|
208
209
|
value_str = str(value).lower()
|
|
209
210
|
return rf'(?<=[^\w"\d]){value_str}(?=[^\w"\d])'
|
|
210
211
|
|
|
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
18
18
|
class AttributeChoicesUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
19
19
|
name: str = "attribute_constraints_choices_validator"
|
|
20
20
|
|
|
21
|
-
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
|
|
21
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
22
22
|
if self.attribute_schema.choices is None:
|
|
23
23
|
return
|
|
24
24
|
|
|
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
18
18
|
class AttributeEnumUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
19
19
|
name: str = "attribute_constraints_enum_validator"
|
|
20
20
|
|
|
21
|
-
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
|
|
21
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
22
22
|
if self.attribute_schema.enum is None:
|
|
23
23
|
return
|
|
24
24
|
|
|
@@ -28,7 +28,7 @@ class NodeAttributeValue:
|
|
|
28
28
|
class AttributeKindUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
29
29
|
name: str = "attribute_constraints_kind_validator"
|
|
30
30
|
|
|
31
|
-
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
|
|
31
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
32
32
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
33
33
|
self.params.update(branch_params)
|
|
34
34
|
|
|
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
18
18
|
class AttributeLengthUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
19
19
|
name: str = "attribute_constraints_length_validator"
|
|
20
20
|
|
|
21
|
-
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
|
|
21
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
22
22
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
23
23
|
self.params.update(branch_params)
|
|
24
24
|
|
|
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
18
18
|
class AttributeOptionalUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
19
19
|
name: str = "attribute_constraints_optional_validator"
|
|
20
20
|
|
|
21
|
-
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
|
|
21
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
22
22
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
23
23
|
self.params.update(branch_params)
|
|
24
24
|
|
|
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
18
18
|
class AttributeRegexUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
19
19
|
name: str = "attribute_constraints_regex_validator"
|
|
20
20
|
|
|
21
|
-
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
|
|
21
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
22
22
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
23
23
|
self.params.update(branch_params)
|
|
24
24
|
|
|
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
18
18
|
class AttributeUniqueUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
19
19
|
name: str = "attribute_constraints_unique_validator"
|
|
20
20
|
|
|
21
|
-
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
|
|
21
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
22
22
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string(), is_isolated=False)
|
|
23
23
|
self.params.update(branch_params)
|
|
24
24
|
|