infrahub-server 1.2.11__py3-none-any.whl → 1.3.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/constants.py +130 -0
- infrahub/actions/gather.py +114 -0
- infrahub/actions/models.py +243 -0
- infrahub/actions/parsers.py +104 -0
- infrahub/actions/schema.py +393 -0
- infrahub/actions/tasks.py +119 -0
- infrahub/actions/triggers.py +21 -0
- infrahub/branch/__init__.py +0 -0
- infrahub/branch/tasks.py +29 -0
- infrahub/branch/triggers.py +22 -0
- infrahub/cli/db.py +3 -4
- infrahub/computed_attribute/gather.py +3 -1
- infrahub/computed_attribute/tasks.py +23 -29
- infrahub/core/account.py +24 -47
- infrahub/core/attribute.py +13 -15
- infrahub/core/constants/__init__.py +10 -0
- infrahub/core/constants/database.py +1 -0
- infrahub/core/constants/infrahubkind.py +9 -0
- infrahub/core/constraint/node/runner.py +3 -1
- infrahub/core/convert_object_type/__init__.py +0 -0
- infrahub/core/convert_object_type/conversion.py +124 -0
- infrahub/core/convert_object_type/schema_mapping.py +56 -0
- infrahub/core/diff/coordinator.py +8 -1
- infrahub/core/diff/query/all_conflicts.py +1 -5
- infrahub/core/diff/query/artifact.py +10 -20
- infrahub/core/diff/query/delete_query.py +8 -4
- infrahub/core/diff/query/diff_get.py +3 -6
- infrahub/core/diff/query/field_specifiers.py +1 -1
- infrahub/core/diff/query/field_summary.py +2 -4
- infrahub/core/diff/query/merge.py +72 -125
- infrahub/core/diff/query/save.py +83 -68
- infrahub/core/diff/query/summary_counts_enricher.py +34 -54
- infrahub/core/diff/query/time_range_query.py +0 -1
- infrahub/core/diff/repository/repository.py +4 -0
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/manager.py +14 -11
- infrahub/core/migrations/graph/__init__.py +6 -0
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +1 -2
- infrahub/core/migrations/graph/m012_convert_account_generic.py +1 -1
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +2 -6
- infrahub/core/migrations/graph/m015_diff_format_update.py +1 -2
- infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -2
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +11 -22
- infrahub/core/migrations/graph/m020_duplicate_edges.py +3 -6
- infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +1 -2
- infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +2 -2
- infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py +1 -2
- infrahub/core/migrations/graph/m028_delete_diffs.py +1 -2
- infrahub/core/migrations/graph/m029_duplicates_cleanup.py +662 -0
- infrahub/core/migrations/graph/m030_illegal_edges.py +82 -0
- infrahub/core/migrations/query/attribute_add.py +14 -11
- infrahub/core/migrations/query/attribute_rename.py +6 -11
- infrahub/core/migrations/query/delete_element_in_schema.py +19 -17
- infrahub/core/migrations/query/node_duplicate.py +19 -21
- infrahub/core/migrations/query/relationship_duplicate.py +19 -18
- infrahub/core/migrations/schema/node_attribute_remove.py +4 -8
- infrahub/core/migrations/schema/node_remove.py +19 -20
- infrahub/core/models.py +29 -2
- infrahub/core/node/__init__.py +131 -28
- infrahub/core/node/base.py +1 -1
- infrahub/core/node/create.py +211 -0
- infrahub/core/node/resource_manager/number_pool.py +31 -5
- infrahub/core/node/standard.py +6 -1
- infrahub/core/path.py +15 -1
- infrahub/core/protocols.py +57 -0
- infrahub/core/protocols_base.py +3 -0
- infrahub/core/query/__init__.py +2 -2
- infrahub/core/query/delete.py +3 -3
- infrahub/core/query/diff.py +19 -32
- infrahub/core/query/ipam.py +10 -20
- infrahub/core/query/node.py +29 -47
- infrahub/core/query/relationship.py +55 -34
- infrahub/core/query/resource_manager.py +1 -2
- infrahub/core/query/standard_node.py +19 -5
- infrahub/core/query/subquery.py +2 -4
- infrahub/core/relationship/constraints/count.py +10 -9
- infrahub/core/relationship/constraints/interface.py +2 -1
- infrahub/core/relationship/constraints/peer_kind.py +2 -1
- infrahub/core/relationship/constraints/peer_parent.py +56 -0
- infrahub/core/relationship/constraints/peer_relatives.py +72 -0
- infrahub/core/relationship/constraints/profiles_kind.py +1 -1
- infrahub/core/relationship/model.py +4 -1
- infrahub/core/schema/__init__.py +2 -1
- infrahub/core/schema/attribute_parameters.py +160 -0
- infrahub/core/schema/attribute_schema.py +130 -7
- infrahub/core/schema/basenode_schema.py +27 -3
- infrahub/core/schema/definitions/core/__init__.py +29 -1
- infrahub/core/schema/definitions/core/group.py +45 -0
- infrahub/core/schema/definitions/core/resource_pool.py +9 -0
- infrahub/core/schema/definitions/internal.py +43 -5
- infrahub/core/schema/generated/attribute_schema.py +16 -3
- infrahub/core/schema/generated/relationship_schema.py +11 -1
- infrahub/core/schema/manager.py +7 -2
- infrahub/core/schema/schema_branch.py +109 -12
- infrahub/core/validators/__init__.py +15 -2
- infrahub/core/validators/attribute/choices.py +1 -3
- infrahub/core/validators/attribute/enum.py +1 -3
- infrahub/core/validators/attribute/kind.py +1 -3
- infrahub/core/validators/attribute/length.py +13 -7
- infrahub/core/validators/attribute/min_max.py +118 -0
- infrahub/core/validators/attribute/number_pool.py +106 -0
- infrahub/core/validators/attribute/optional.py +1 -4
- infrahub/core/validators/attribute/regex.py +5 -6
- infrahub/core/validators/attribute/unique.py +1 -3
- infrahub/core/validators/determiner.py +18 -2
- infrahub/core/validators/enum.py +12 -0
- infrahub/core/validators/node/hierarchy.py +3 -6
- infrahub/core/validators/query.py +1 -3
- infrahub/core/validators/relationship/count.py +6 -12
- infrahub/core/validators/relationship/optional.py +2 -4
- infrahub/core/validators/relationship/peer.py +177 -12
- infrahub/core/validators/tasks.py +1 -1
- infrahub/core/validators/uniqueness/query.py +5 -9
- infrahub/database/__init__.py +12 -4
- infrahub/database/validation.py +100 -0
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +4 -0
- infrahub/dependencies/builder/constraint/relationship_manager/peer_parent.py +8 -0
- infrahub/dependencies/builder/constraint/relationship_manager/peer_relatives.py +8 -0
- infrahub/dependencies/builder/constraint/schema/aggregated.py +2 -0
- infrahub/dependencies/builder/constraint/schema/relationship_peer.py +8 -0
- infrahub/dependencies/builder/diff/deserializer.py +1 -1
- infrahub/dependencies/registry.py +4 -0
- infrahub/events/group_action.py +1 -0
- infrahub/events/models.py +1 -1
- infrahub/git/base.py +5 -3
- infrahub/git/integrator.py +96 -5
- infrahub/git/tasks.py +1 -0
- infrahub/graphql/analyzer.py +139 -18
- infrahub/graphql/manager.py +4 -0
- infrahub/graphql/mutations/action.py +164 -0
- infrahub/graphql/mutations/convert_object_type.py +71 -0
- infrahub/graphql/mutations/main.py +25 -176
- infrahub/graphql/mutations/proposed_change.py +20 -17
- infrahub/graphql/mutations/relationship.py +32 -0
- infrahub/graphql/mutations/resource_manager.py +63 -7
- infrahub/graphql/queries/convert_object_type_mapping.py +34 -0
- infrahub/graphql/queries/resource_manager.py +7 -1
- infrahub/graphql/resolvers/many_relationship.py +1 -1
- infrahub/graphql/resolvers/resolver.py +2 -2
- infrahub/graphql/resolvers/single_relationship.py +1 -1
- infrahub/graphql/schema.py +6 -0
- infrahub/menu/menu.py +34 -2
- infrahub/message_bus/messages/__init__.py +0 -10
- infrahub/message_bus/operations/__init__.py +0 -8
- infrahub/message_bus/operations/refresh/registry.py +4 -7
- infrahub/patch/queries/delete_duplicated_edges.py +45 -39
- infrahub/pools/models.py +14 -0
- infrahub/pools/number.py +5 -3
- infrahub/pools/registration.py +22 -0
- infrahub/pools/tasks.py +126 -0
- infrahub/prefect_server/models.py +1 -19
- infrahub/proposed_change/models.py +68 -3
- infrahub/proposed_change/tasks.py +911 -34
- infrahub/schema/__init__.py +0 -0
- infrahub/schema/tasks.py +27 -0
- infrahub/schema/triggers.py +23 -0
- infrahub/task_manager/models.py +10 -6
- infrahub/trigger/catalogue.py +6 -0
- infrahub/trigger/models.py +23 -6
- infrahub/trigger/setup.py +26 -2
- infrahub/trigger/tasks.py +4 -2
- infrahub/types.py +6 -0
- infrahub/webhook/tasks.py +6 -9
- infrahub/workflows/catalogue.py +103 -1
- infrahub_sdk/client.py +43 -10
- infrahub_sdk/ctl/generator.py +4 -4
- infrahub_sdk/ctl/repository.py +1 -1
- infrahub_sdk/node/__init__.py +39 -0
- infrahub_sdk/node/attribute.py +122 -0
- infrahub_sdk/node/constants.py +21 -0
- infrahub_sdk/{node.py → node/node.py} +158 -803
- infrahub_sdk/node/parsers.py +15 -0
- infrahub_sdk/node/property.py +24 -0
- infrahub_sdk/node/related_node.py +266 -0
- infrahub_sdk/node/relationship.py +302 -0
- infrahub_sdk/protocols.py +112 -0
- infrahub_sdk/protocols_base.py +34 -2
- infrahub_sdk/pytest_plugin/items/python_transform.py +2 -1
- infrahub_sdk/query_groups.py +17 -5
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/schema/repository.py +16 -0
- infrahub_sdk/spec/object.py +1 -1
- infrahub_sdk/store.py +1 -1
- infrahub_sdk/testing/schemas/car_person.py +1 -0
- infrahub_sdk/utils.py +7 -20
- infrahub_sdk/yaml.py +6 -5
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/METADATA +5 -5
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/RECORD +197 -168
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/WHEEL +1 -1
- infrahub_testcontainers/container.py +239 -65
- infrahub_testcontainers/docker-compose-cluster.test.yml +321 -0
- infrahub_testcontainers/docker-compose.test.yml +2 -1
- infrahub_testcontainers/helpers.py +23 -3
- infrahub_testcontainers/plugin.py +9 -0
- infrahub/message_bus/messages/check_generator_run.py +0 -26
- infrahub/message_bus/messages/finalize_validator_execution.py +0 -15
- infrahub/message_bus/messages/proposed_change/base_with_diff.py +0 -16
- infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +0 -11
- infrahub/message_bus/messages/request_generatordefinition_check.py +0 -20
- infrahub/message_bus/messages/request_proposedchange_pipeline.py +0 -23
- infrahub/message_bus/operations/check/__init__.py +0 -3
- infrahub/message_bus/operations/check/generator.py +0 -156
- infrahub/message_bus/operations/finalize/__init__.py +0 -3
- infrahub/message_bus/operations/finalize/validator.py +0 -133
- infrahub/message_bus/operations/requests/__init__.py +0 -9
- infrahub/message_bus/operations/requests/generator_definition.py +0 -140
- infrahub/message_bus/operations/requests/proposed_change.py +0 -629
- infrahub/patch/queries/consolidate_duplicated_nodes.py +0 -109
- /infrahub/{message_bus/messages/proposed_change → actions}/__init__.py +0 -0
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -28,7 +28,6 @@ INFRAHUB_SERVICES: dict[str, ContainerService] = {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
PROJECT_ENV_VARIABLES: dict[str, str] = {
|
|
31
|
-
"NEO4J_DOCKER_IMAGE": "neo4j:5.20.0-community",
|
|
32
31
|
"MESSAGE_QUEUE_DOCKER_IMAGE": "rabbitmq:3.13.7-management",
|
|
33
32
|
"CACHE_DOCKER_IMAGE": "redis:7.2.4",
|
|
34
33
|
"INFRAHUB_TESTING_DOCKER_IMAGE": "registry.opsmill.io/opsmill/infrahub",
|
|
@@ -67,9 +66,12 @@ PROJECT_ENV_VARIABLES: dict[str, str] = {
|
|
|
67
66
|
class InfrahubDockerCompose(DockerCompose):
|
|
68
67
|
project_name: str | None = None
|
|
69
68
|
env_vars: dict[str, str] = field(default_factory=dict)
|
|
69
|
+
deployment_type: str | None = None
|
|
70
70
|
|
|
71
71
|
@classmethod
|
|
72
|
-
def init(
|
|
72
|
+
def init(
|
|
73
|
+
cls, directory: Path | None = None, version: str | None = None, deployment_type: str | None = None
|
|
74
|
+
) -> Self:
|
|
73
75
|
if not directory:
|
|
74
76
|
directory = Path.cwd()
|
|
75
77
|
|
|
@@ -80,7 +82,7 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
80
82
|
if version == "local" and infrahub_image_version:
|
|
81
83
|
version = infrahub_image_version
|
|
82
84
|
|
|
83
|
-
compose = cls(project_name=cls.generate_project_name(), context=directory)
|
|
85
|
+
compose = cls(project_name=cls.generate_project_name(), context=directory, deployment_type=deployment_type)
|
|
84
86
|
compose.create_docker_file(directory=directory)
|
|
85
87
|
compose.create_env_file(directory=directory, version=version)
|
|
86
88
|
|
|
@@ -112,7 +114,10 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
112
114
|
|
|
113
115
|
def create_docker_file(self, directory: Path) -> Path:
|
|
114
116
|
current_directory = Path(__file__).resolve().parent
|
|
115
|
-
|
|
117
|
+
compose_file_name = (
|
|
118
|
+
"docker-compose-cluster.test.yml" if self.deployment_type == "cluster" else "docker-compose.test.yml"
|
|
119
|
+
)
|
|
120
|
+
compose_file = current_directory / compose_file_name
|
|
116
121
|
|
|
117
122
|
test_compose_file = directory / "docker-compose.yml"
|
|
118
123
|
test_compose_file.write_bytes(compose_file.read_bytes())
|
|
@@ -161,7 +166,7 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
161
166
|
cmd.extend(self.services)
|
|
162
167
|
self._run_command(cmd=cmd)
|
|
163
168
|
|
|
164
|
-
def start_container(self, service_name: str) -> None:
|
|
169
|
+
def start_container(self, service_name: str | list[str]) -> None:
|
|
165
170
|
"""
|
|
166
171
|
Starts a specific service of the docker compose environment.
|
|
167
172
|
|
|
@@ -171,7 +176,11 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
171
176
|
|
|
172
177
|
# pull means running a separate command before starting
|
|
173
178
|
if self.pull:
|
|
174
|
-
pull_cmd = [*base_cmd, "pull"
|
|
179
|
+
pull_cmd = [*base_cmd, "pull"]
|
|
180
|
+
if isinstance(service_name, list):
|
|
181
|
+
pull_cmd.extend(service_name)
|
|
182
|
+
else:
|
|
183
|
+
pull_cmd.append(service_name)
|
|
175
184
|
self._run_command(cmd=pull_cmd)
|
|
176
185
|
|
|
177
186
|
up_cmd = [*base_cmd, "up"]
|
|
@@ -186,7 +195,10 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
186
195
|
# we run in detached mode instead of blocking
|
|
187
196
|
up_cmd.append("--detach")
|
|
188
197
|
|
|
189
|
-
|
|
198
|
+
if isinstance(service_name, list):
|
|
199
|
+
up_cmd.extend(service_name)
|
|
200
|
+
else:
|
|
201
|
+
up_cmd.append(service_name)
|
|
190
202
|
self._run_command(cmd=up_cmd)
|
|
191
203
|
|
|
192
204
|
# TODO would be good to the support for project_name upstream
|
|
@@ -234,7 +246,7 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
234
246
|
dest_dir / backup_name,
|
|
235
247
|
)
|
|
236
248
|
|
|
237
|
-
def database_restore_backup(self, backup_file: Path) -> None:
|
|
249
|
+
def database_restore_backup(self, backup_file: Path) -> None: # noqa: PLR0915
|
|
238
250
|
assert self.use_neo4j_enterprise
|
|
239
251
|
|
|
240
252
|
shutil.copy(
|
|
@@ -243,52 +255,35 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
243
255
|
)
|
|
244
256
|
service_name = "database"
|
|
245
257
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
self.exec_in_container(
|
|
253
|
-
command=["cypher-shell", "-u", "neo4j", "-p", "admin", "STOP DATABASE neo4j;"],
|
|
254
|
-
service_name=service_name,
|
|
255
|
-
)
|
|
258
|
+
if self.deployment_type != "cluster": # noqa: PLR1702
|
|
259
|
+
try:
|
|
260
|
+
self.get_container(service_name=service_name)
|
|
261
|
+
except ContainerIsNotRunning:
|
|
262
|
+
self.start_container(service_name=service_name)
|
|
256
263
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
"restore",
|
|
262
|
-
"--overwrite-destination",
|
|
263
|
-
"--from-path",
|
|
264
|
-
str(self.internal_backup_dir / backup_file.name),
|
|
265
|
-
],
|
|
266
|
-
service_name=service_name,
|
|
267
|
-
)
|
|
264
|
+
self.exec_in_container(
|
|
265
|
+
command=["cypher-shell", "-u", "neo4j", "-p", "admin", "STOP DATABASE neo4j;"],
|
|
266
|
+
service_name=service_name,
|
|
267
|
+
)
|
|
268
268
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
self.exec_in_container(
|
|
270
|
+
command=[
|
|
271
|
+
"neo4j-admin",
|
|
272
|
+
"database",
|
|
273
|
+
"restore",
|
|
274
|
+
"--overwrite-destination",
|
|
275
|
+
"--from-path",
|
|
276
|
+
str(self.internal_backup_dir / backup_file.name),
|
|
277
|
+
],
|
|
278
|
+
service_name=service_name,
|
|
279
|
+
)
|
|
273
280
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
"plain",
|
|
279
|
-
"-d",
|
|
280
|
-
"system",
|
|
281
|
-
"-u",
|
|
282
|
-
"neo4j",
|
|
283
|
-
"-p",
|
|
284
|
-
"admin",
|
|
285
|
-
"START DATABASE neo4j;",
|
|
286
|
-
],
|
|
287
|
-
service_name=service_name,
|
|
288
|
-
)
|
|
281
|
+
self.exec_in_container(
|
|
282
|
+
command=["chown", "-R", "neo4j:neo4j", "/data"],
|
|
283
|
+
service_name=service_name,
|
|
284
|
+
)
|
|
289
285
|
|
|
290
|
-
|
|
291
|
-
(stdout, _, _) = self.exec_in_container(
|
|
286
|
+
(restore_output, _, _) = self.exec_in_container(
|
|
292
287
|
command=[
|
|
293
288
|
"cypher-shell",
|
|
294
289
|
"--format",
|
|
@@ -299,26 +294,205 @@ class InfrahubDockerCompose(DockerCompose):
|
|
|
299
294
|
"neo4j",
|
|
300
295
|
"-p",
|
|
301
296
|
"admin",
|
|
302
|
-
"
|
|
297
|
+
"START DATABASE neo4j;",
|
|
303
298
|
],
|
|
304
299
|
service_name=service_name,
|
|
305
300
|
)
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
301
|
+
|
|
302
|
+
for _ in range(3):
|
|
303
|
+
(stdout, _, _) = self.exec_in_container(
|
|
304
|
+
command=[
|
|
305
|
+
"cypher-shell",
|
|
306
|
+
"--format",
|
|
307
|
+
"plain",
|
|
308
|
+
"-d",
|
|
309
|
+
"system",
|
|
310
|
+
"-u",
|
|
311
|
+
"neo4j",
|
|
312
|
+
"-p",
|
|
313
|
+
"admin",
|
|
314
|
+
"SHOW DATABASES WHERE name = 'neo4j' AND currentStatus = 'online';",
|
|
315
|
+
],
|
|
316
|
+
service_name=service_name,
|
|
317
|
+
)
|
|
318
|
+
if stdout:
|
|
319
|
+
break
|
|
320
|
+
time.sleep(5)
|
|
321
|
+
else:
|
|
322
|
+
(debug_logs, _, _) = self.exec_in_container(
|
|
323
|
+
command=["cat", "logs/debug.log"],
|
|
324
|
+
service_name=service_name,
|
|
325
|
+
)
|
|
326
|
+
raise Exception(f"Failed to restore database:\n{restore_output}\nDebug logs:\n{debug_logs}")
|
|
327
|
+
|
|
328
|
+
old_services = self.services
|
|
329
|
+
self.services = ["infrahub-server", "task-worker"]
|
|
330
|
+
self.stop(down=False)
|
|
331
|
+
try:
|
|
332
|
+
self.start()
|
|
333
|
+
except Exception as exc:
|
|
334
|
+
stdout, stderr = self.get_logs()
|
|
335
|
+
raise Exception(f"Failed to start docker compose:\nStdout:\n{stdout}\nStderr:\n{stderr}") from exc
|
|
336
|
+
self.services = old_services
|
|
309
337
|
else:
|
|
310
|
-
(
|
|
311
|
-
|
|
338
|
+
print("Cluster mode detected")
|
|
339
|
+
try:
|
|
340
|
+
self.get_container(service_name=service_name)
|
|
341
|
+
self.get_container(service_name="database-core2")
|
|
342
|
+
self.get_container(service_name="database-core3")
|
|
343
|
+
except ContainerIsNotRunning:
|
|
344
|
+
self.start_container("database", "database-core2", "database-core3")
|
|
345
|
+
|
|
346
|
+
# Waiting for cluster to stabilize...
|
|
347
|
+
time.sleep(10)
|
|
348
|
+
|
|
349
|
+
self.exec_in_container(
|
|
350
|
+
command=["cypher-shell", "-u", "neo4j", "-p", "admin", "DROP DATABASE neo4j;"],
|
|
351
|
+
service_name=service_name,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
self.exec_in_container(
|
|
355
|
+
command=["rm", "-rf", "/data/databases/neo4j"],
|
|
356
|
+
service_name=service_name,
|
|
357
|
+
)
|
|
358
|
+
self.exec_in_container(
|
|
359
|
+
command=["rm", "-rf", "/data/transactions/neo4j"],
|
|
360
|
+
service_name=service_name,
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
self.exec_in_container(
|
|
364
|
+
command=[
|
|
365
|
+
"neo4j-admin",
|
|
366
|
+
"database",
|
|
367
|
+
"restore",
|
|
368
|
+
"--from-path",
|
|
369
|
+
str(self.internal_backup_dir / backup_file.name),
|
|
370
|
+
"neo4j",
|
|
371
|
+
],
|
|
312
372
|
service_name=service_name,
|
|
313
373
|
)
|
|
314
|
-
raise Exception(f"Failed to restore database:\n{restore_output}\nDebug logs:\n{debug_logs}")
|
|
315
374
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
375
|
+
cmd = self.compose_command_property[:]
|
|
376
|
+
cmd += ["restart", "database"]
|
|
377
|
+
self._run_command(cmd=cmd)
|
|
378
|
+
|
|
379
|
+
main_node = service_name
|
|
380
|
+
cluster_nodes = ["database", "database-core2", "database-core3"]
|
|
381
|
+
|
|
382
|
+
for attempt in range(3):
|
|
383
|
+
try:
|
|
384
|
+
(stdout, _, _) = self.exec_in_container(
|
|
385
|
+
command=[
|
|
386
|
+
"cypher-shell",
|
|
387
|
+
"--format",
|
|
388
|
+
"plain",
|
|
389
|
+
"-d",
|
|
390
|
+
"system",
|
|
391
|
+
"-u",
|
|
392
|
+
"neo4j",
|
|
393
|
+
"-p",
|
|
394
|
+
"admin",
|
|
395
|
+
"SHOW DATABASES YIELD name, address, currentStatus WHERE name = 'system' RETURN address, currentStatus",
|
|
396
|
+
],
|
|
397
|
+
service_name=main_node,
|
|
398
|
+
)
|
|
399
|
+
except Exception:
|
|
400
|
+
time.sleep(10)
|
|
401
|
+
continue
|
|
402
|
+
|
|
403
|
+
raw_output = stdout
|
|
404
|
+
nodes_status = dict.fromkeys(cluster_nodes, False)
|
|
405
|
+
online_count = 0
|
|
406
|
+
total_entries = 0
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
for line_raw in stdout.splitlines():
|
|
410
|
+
line = line_raw.strip()
|
|
411
|
+
if not line or line.startswith("address"):
|
|
412
|
+
continue
|
|
413
|
+
|
|
414
|
+
total_entries += 1
|
|
415
|
+
if "online" in line:
|
|
416
|
+
online_count += 1
|
|
417
|
+
for node in cluster_nodes:
|
|
418
|
+
node_pattern = f'"{node}:'
|
|
419
|
+
if node_pattern in line:
|
|
420
|
+
nodes_status[node] = True
|
|
421
|
+
break
|
|
422
|
+
if all(nodes_status.values()) and online_count == len(cluster_nodes):
|
|
423
|
+
break
|
|
424
|
+
except Exception as e:
|
|
425
|
+
print(f"Error parsing database status on attempt {attempt + 1}: {e}")
|
|
426
|
+
|
|
427
|
+
print(f"Waiting for all nodes to be online. Current status: {nodes_status}")
|
|
428
|
+
time.sleep(5)
|
|
429
|
+
else:
|
|
430
|
+
debug_logs = {}
|
|
431
|
+
for node in cluster_nodes:
|
|
432
|
+
try:
|
|
433
|
+
(logs, _, _) = self.exec_in_container(
|
|
434
|
+
command=["cat", "logs/debug.log"],
|
|
435
|
+
service_name=node,
|
|
436
|
+
)
|
|
437
|
+
debug_logs[node] = logs
|
|
438
|
+
except Exception as e:
|
|
439
|
+
debug_logs[node] = f"Could not retrieve logs: {str(e)}"
|
|
440
|
+
|
|
441
|
+
debug_info = f"Raw output from SHOW DATABASES command:\n{raw_output}\n\n"
|
|
442
|
+
debug_info += f"Final node status: {nodes_status}\n\n"
|
|
443
|
+
|
|
444
|
+
status_str = ", ".join(
|
|
445
|
+
[f"{node}: {'online' if status else 'offline'}" for node, status in nodes_status.items()]
|
|
446
|
+
)
|
|
447
|
+
logs_str = debug_info + "\n\n".join(
|
|
448
|
+
[f"--- {node} logs ---\n{logs}" for node, logs in debug_logs.items()]
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
raise Exception(
|
|
452
|
+
f"Failed to restore database cluster. Node status: {status_str}\nDebug logs:\n{logs_str}"
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
server_id = None
|
|
456
|
+
try:
|
|
457
|
+
stdout, _, _ = self.exec_in_container(
|
|
458
|
+
command=[
|
|
459
|
+
"cypher-shell",
|
|
460
|
+
"--format",
|
|
461
|
+
"plain",
|
|
462
|
+
"-d",
|
|
463
|
+
"system",
|
|
464
|
+
"-u",
|
|
465
|
+
"neo4j",
|
|
466
|
+
"-p",
|
|
467
|
+
"admin",
|
|
468
|
+
'SHOW SERVERS YIELD name, address WHERE address = "database:7687" RETURN name;',
|
|
469
|
+
],
|
|
470
|
+
service_name=service_name,
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
lines = stdout.splitlines()
|
|
474
|
+
for line_raw in lines:
|
|
475
|
+
line = line_raw.strip()
|
|
476
|
+
if not line or line == "name" or line.startswith("+"):
|
|
477
|
+
continue
|
|
478
|
+
server_id = line.strip('"')
|
|
479
|
+
break
|
|
480
|
+
except Exception as e:
|
|
481
|
+
print(f"Error retrieving server ID with direct query: {e}")
|
|
482
|
+
|
|
483
|
+
if server_id:
|
|
484
|
+
self.exec_in_container(
|
|
485
|
+
command=[
|
|
486
|
+
"cypher-shell",
|
|
487
|
+
"-d",
|
|
488
|
+
"system",
|
|
489
|
+
"-u",
|
|
490
|
+
"neo4j",
|
|
491
|
+
"-p",
|
|
492
|
+
"admin",
|
|
493
|
+
f"CREATE DATABASE neo4j TOPOLOGY 3 PRIMARIES OPTIONS {{ existingData: 'use', existingDataSeedInstance: '{server_id}' }};",
|
|
494
|
+
],
|
|
495
|
+
service_name=service_name,
|
|
496
|
+
)
|
|
320
497
|
self.start()
|
|
321
|
-
|
|
322
|
-
stdout, stderr = self.get_logs()
|
|
323
|
-
raise Exception(f"Failed to start docker compose:\nStdout:\n{stdout}\nStderr:\n{stderr}") from exc
|
|
324
|
-
self.services = old_services
|
|
498
|
+
print("Database restored successfully")
|