Skip to content

Commit 1e0632b

Browse files
use_multi_tenancy_endpoints_II: tests running (#208)
* use_multi_tenancy_endpoints_II: tests running * use_multi_tenancy_endpoints_II: use bump manifesto model in rollback * use_multi_tenancy_endpoints_II: format
1 parent 30a02c5 commit 1e0632b

File tree

14 files changed

+158
-116
lines changed

14 files changed

+158
-116
lines changed

job_executor/adapter/datastore_api/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ def is_system_paused() -> bool:
105105
return maintenance_status.paused
106106

107107

108+
def get_datastores() -> list[str]:
109+
"""Get a list of all datastore rdns on this tenant"""
110+
request_url = f"{DATASTORE_API_URL}/datastores"
111+
return execute_request("GET", request_url, True).json()
112+
113+
108114
def get_datastore_directory(rdn: str) -> Path:
109115
request_url = f"{DATASTORE_API_URL}/datastores/{rdn}"
110116
response = execute_request("GET", request_url, True)

job_executor/adapter/fs/datastore_files.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ def save_temporary_backup(self) -> None:
240240
draft_version = json.load(f)
241241
with open(self.draft_metadata_all_path, encoding="utf-8") as f:
242242
metadata_all_draft = json.load(f)
243-
tmp_dir = self.root_dir / "tmp"
243+
tmp_dir = self.metadata_dir / "tmp"
244244
if os.path.isdir(tmp_dir):
245245
raise LocalStorageError("tmp directory already exists")
246246
os.mkdir(tmp_dir)
@@ -263,7 +263,7 @@ def restore_from_temporary_backup(self) -> str | None:
263263
Returns None if no released version in backup, else returns the
264264
latest release version number as dotted four part version.
265265
"""
266-
tmp_dir = Path(self.root_dir) / "tmp"
266+
tmp_dir = self.metadata_dir / "tmp"
267267
draft_version_backup = tmp_dir / "draft_version.json"
268268
metadata_all_draft_backup = tmp_dir / "metadata_all__DRAFT.json"
269269
datastore_versions_backup = tmp_dir / "datastore_versions.json"
@@ -294,10 +294,10 @@ def archive_temporary_backup(self) -> None:
294294
exists. Raises `LocalStorageError` if there are any unrecognized files
295295
in the directory.
296296
"""
297-
tmp_dir = Path(self.root_dir) / "tmp"
297+
tmp_dir = self.metadata_dir / "tmp"
298298
os.makedirs(self.archive_dir, exist_ok=True)
299299

300-
if not os.path.isdir(Path(self.root_dir) / "tmp"):
300+
if not os.path.isdir(tmp_dir):
301301
raise LocalStorageError(
302302
"Could not find a tmp directory to archive."
303303
)
@@ -312,20 +312,18 @@ def archive_temporary_backup(self) -> None:
312312
"directory. Aborting tmp archiving."
313313
)
314314
timestamp = datetime.now(UTC).replace(tzinfo=None)
315-
shutil.move(
316-
self.root_dir / "tmp", self.archive_dir / f"tmp_{timestamp}"
317-
)
315+
shutil.move(tmp_dir, self.archive_dir / f"tmp_{timestamp}")
318316

319317
def delete_temporary_backup(self) -> None:
320318
"""
321319
Deletes the tmp directory within the datastore if the directory
322320
exists. Raises `LocalStorageError` if there are any unrecognized files
323321
in the directory.
324322
"""
325-
tmp_dir = Path(self.root_dir) / "tmp"
323+
tmp_dir = self.metadata_dir / "tmp"
326324
os.makedirs(self.archive_dir, exist_ok=True)
327325

328-
if not os.path.isdir(Path(self.root_dir) / "tmp"):
326+
if not os.path.isdir(tmp_dir):
329327
raise LocalStorageError("Could not find a tmp directory to delete.")
330328
for content in os.listdir(tmp_dir):
331329
if content not in [
@@ -337,13 +335,13 @@ def delete_temporary_backup(self) -> None:
337335
"Found unrecognized files and/or directories in the tmp "
338336
"directory. Aborting tmp deleting."
339337
)
340-
shutil.rmtree(self.root_dir / "tmp")
338+
shutil.rmtree(tmp_dir)
341339

342340
def temporary_backup_exists(self) -> bool:
343341
"""
344342
Returns a boolean representing if the tmp directory exists.
345343
"""
346-
tmp_dir = self.root_dir / "tmp"
344+
tmp_dir = self.metadata_dir / "tmp"
347345
return os.path.isdir(tmp_dir)
348346

349347
def archive_draft_version(self, version: str) -> None:

job_executor/app.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818

1919
def initialize_app() -> None:
2020
try:
21-
local_storage = LocalStorageAdapter(Path(environment.datastore_dir))
2221
rollback.fix_interrupted_jobs()
23-
if local_storage.datastore_dir.temporary_backup_exists():
24-
raise StartupException("tmp directory exists")
22+
rdns = datastore_api.get_datastores()
23+
for rdn in rdns:
24+
local_storage = LocalStorageAdapter(Path(environment.datastore_dir))
25+
if local_storage.datastore_dir.temporary_backup_exists():
26+
raise StartupException(f"tmp directory exists for {rdn}")
2527
except Exception as e:
2628
raise StartupException("Exception when initializing") from e
2729

job_executor/domain/datastores.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,12 @@ def patch_metadata(
214214
except PatchingError as e:
215215
logger.error(f"{job.job_id}: Patching error occured")
216216
logger.exception(f"{job.job_id}: {str(e)}", exc_info=e)
217-
rollback_manager_phase_import_job(
218-
job.job_id, "PATCH_METADATA", dataset_name
219-
)
217+
rollback_manager_phase_import_job(job, "PATCH_METADATA", dataset_name)
220218
datastore_api.update_job_status(job.job_id, JobStatus.FAILED, str(e))
221219
except Exception as e:
222220
logger.error(f"{job.job_id}: An unexpected error occured")
223221
logger.exception(f"{job.job_id}: {str(e)}", exc_info=e)
224-
rollback_manager_phase_import_job(
225-
job.job_id, "PATCH_METADATA", dataset_name
226-
)
222+
rollback_manager_phase_import_job(job, "PATCH_METADATA", dataset_name)
227223
datastore_api.update_job_status(job.job_id, JobStatus.FAILED)
228224

229225

@@ -273,7 +269,7 @@ def add(
273269
except Exception as e:
274270
logger.error(f"{job.job_id}: An unexpected error occured")
275271
logger.exception(f"{job.job_id}: {str(e)}", exc_info=e)
276-
rollback_manager_phase_import_job(job.job_id, "ADD", dataset_name)
272+
rollback_manager_phase_import_job(job, "ADD", dataset_name)
277273
datastore_api.update_job_status(job.job_id, JobStatus.FAILED)
278274

279275

@@ -325,7 +321,7 @@ def change(
325321
except Exception as e:
326322
logger.error(f"{job.job_id}: An unexpected error occured")
327323
logger.exception(f"{job.job_id}: {str(e)}", exc_info=e)
328-
rollback_manager_phase_import_job(job.job_id, "CHANGE", dataset_name)
324+
rollback_manager_phase_import_job(job, "CHANGE", dataset_name)
329325
datastore_api.update_job_status(job.job_id, JobStatus.FAILED)
330326

331327

@@ -564,8 +560,8 @@ def bump_version(
564560
logger.error(f"{job.job_id}: An unexpected error occured")
565561
logger.exception(f"{job.job_id}: {str(e)}", exc_info=e)
566562
rollback_bump(
567-
job.job_id,
568-
bump_manifesto.model_dump(by_alias=True, exclude_none=True),
563+
job,
564+
bump_manifesto,
569565
)
570566
datastore_api.update_job_status(job.job_id, JobStatus.FAILED)
571567

job_executor/domain/rollback.py

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
from pathlib import Path
55

66
from job_executor.adapter import datastore_api
7-
from job_executor.adapter.datastore_api.models import Job, JobStatus
7+
from job_executor.adapter.datastore_api.models import (
8+
DatastoreVersion,
9+
Job,
10+
JobStatus,
11+
)
812
from job_executor.adapter.fs import LocalStorageAdapter
913
from job_executor.adapter.fs.models.datastore_versions import (
1014
bump_dotted_version_number,
@@ -16,28 +20,30 @@
1620
RollbackException,
1721
StartupException,
1822
)
19-
from job_executor.config import environment
2023

21-
WORKING_DIR_PATH = Path(environment.datastore_dir + "_working")
2224
logger = logging.getLogger()
2325

2426

25-
def rollback_bump(job_id: str, bump_manifesto: dict) -> None:
26-
local_storage = LocalStorageAdapter(Path(environment.datastore_dir))
27+
def rollback_bump(job: Job, bump_manifesto: DatastoreVersion) -> None:
28+
job_id = job.job_id
29+
local_storage = LocalStorageAdapter(
30+
datastore_api.get_datastore_directory(job.datastore_rdn)
31+
)
2732
try:
2833
logger.info(f"{job_id}: Restoring files from temporary backup")
2934
restored_version_number = (
3035
local_storage.datastore_dir.restore_from_temporary_backup()
3136
)
32-
update_type = bump_manifesto["updateType"]
33-
bumped_version_number = (
34-
"1.0.0.0"
35-
if restored_version_number is None
36-
else bump_dotted_version_number(
37+
bumped_version_number = "1.0.0.0"
38+
update_type = bump_manifesto.update_type
39+
if restored_version_number is not None:
40+
assert update_type is not None
41+
bumped_version_number = bump_dotted_version_number(
3742
underscored_to_dotted_version(restored_version_number),
3843
update_type,
3944
)
40-
)
45+
else:
46+
update_type = "MAJOR"
4147
logger.warning(
4248
f"{job_id}: Rolling back to {restored_version_number} "
4349
f"from bump to {bumped_version_number}"
@@ -47,9 +53,9 @@ def rollback_bump(job_id: str, bump_manifesto: dict) -> None:
4753
)
4854
bumped_version_data = "_".join(bumped_version_metadata.split("_")[:-1])
4955
manifesto_datasets = [
50-
dataset["name"]
51-
for dataset in bump_manifesto["dataStructureUpdates"]
52-
if dataset["releaseStatus"] != "DRAFT"
56+
dataset.name
57+
for dataset in bump_manifesto.data_structure_updates
58+
if dataset.release_status != "DRAFT"
5359
]
5460
logger.info(
5561
f"{job_id}: Found {len(manifesto_datasets)} "
@@ -127,9 +133,12 @@ def rollback_bump(job_id: str, bump_manifesto: dict) -> None:
127133

128134

129135
def rollback_worker_phase_import_job(
130-
job_id: str, operation: str, dataset_name: str
136+
job: Job, operation: str, dataset_name: str
131137
) -> None:
132-
local_storage = LocalStorageAdapter(Path(environment.datastore_dir))
138+
job_id = job.job_id
139+
local_storage = LocalStorageAdapter(
140+
datastore_api.get_datastore_directory(job.datastore_rdn)
141+
)
133142
logger.warning(
134143
f"{job_id}: Rolling back worker job "
135144
f'with target: "{dataset_name}" and operation "{operation}"'
@@ -154,17 +163,19 @@ def rollback_worker_phase_import_job(
154163

155164
if operation in ["ADD", "CHANGE"]:
156165
for file in generated_data_files:
157-
filepath = WORKING_DIR_PATH / file
166+
filepath = local_storage.working_dir.path / file
158167
if filepath.exists():
159168
logger.info(f'{job_id}: Deleting data file "{filepath}"')
160169
os.remove(filepath)
161-
parquet_directory = WORKING_DIR_PATH / generated_data_directory
170+
parquet_directory = (
171+
local_storage.working_dir.path / generated_data_directory
172+
)
162173
if parquet_directory.exists() and os.path.isdir(parquet_directory):
163174
logger.info(
164175
f'{job_id}: Deleting data directory "{parquet_directory}"'
165176
)
166177
shutil.rmtree(parquet_directory)
167-
dataset_directory = WORKING_DIR_PATH / dataset_name
178+
dataset_directory = local_storage.working_dir.path / dataset_name
168179
if dataset_directory.exists() and os.path.isdir(dataset_directory):
169180
logger.info(
170181
f'{job_id}: Deleting dataset directory "{dataset_directory}"'
@@ -173,14 +184,17 @@ def rollback_worker_phase_import_job(
173184

174185

175186
def rollback_manager_phase_import_job(
176-
job_id: str, operation: str, dataset_name: str
187+
job: Job, operation: str, dataset_name: str
177188
) -> None:
178189
"""
179190
Rolls back manager phase import job.
180191
Exceptions are not handled here on purpose. It is a catastrophic thing
181192
if a rollback fails.
182193
"""
183-
local_storage = LocalStorageAdapter(Path(environment.datastore_dir))
194+
job_id = job.job_id
195+
local_storage = LocalStorageAdapter(
196+
datastore_api.get_datastore_directory(job.datastore_rdn)
197+
)
184198
logger.warning(
185199
f"{job_id}: Rolling back import job "
186200
f'with target: "{dataset_name}" and operation "{operation}"'
@@ -218,7 +232,7 @@ def fix_interrupted_job(job: Job) -> None:
218232
if job_operation in ["ADD", "CHANGE", "PATCH_METADATA"]:
219233
if job.status == "importing":
220234
rollback_manager_phase_import_job(
221-
job.job_id, job_operation, job.parameters.target
235+
job, job_operation, job.parameters.target
222236
)
223237
logger.info(
224238
f"{job.job_id}: Rolled back importing of job with "
@@ -232,7 +246,7 @@ def fix_interrupted_job(job: Job) -> None:
232246
)
233247
else:
234248
rollback_worker_phase_import_job(
235-
job.job_id, job_operation, job.parameters.target
249+
job, job_operation, job.parameters.target
236250
)
237251
logger.info(
238252
f'{job.job_id}: Setting status to "failed" for interrupted job'
@@ -262,7 +276,7 @@ def fix_interrupted_job(job: Job) -> None:
262276
bump_manifesto = job.parameters.bump_manifesto
263277
if bump_manifesto is None:
264278
raise RollbackException("No bump manifesto available")
265-
rollback_bump(job.job_id, bump_manifesto.model_dump())
279+
rollback_bump(job, bump_manifesto)
266280
except Exception as exc:
267281
error_message = f"Failed rollback for {job.job_id}"
268282
logger.exception(error_message, exc_info=exc)

tests/resources/datastores/ROLLBACK_DATASTORE/tmp/datastore_versions.json renamed to tests/resources/datastores/ROLLBACK_DATASTORE/datastore/tmp/datastore_versions.json

File renamed without changes.

tests/resources/datastores/ROLLBACK_DATASTORE/tmp/draft_version.json renamed to tests/resources/datastores/ROLLBACK_DATASTORE/datastore/tmp/draft_version.json

File renamed without changes.

tests/resources/datastores/ROLLBACK_DATASTORE/tmp/metadata_all__DRAFT.json renamed to tests/resources/datastores/ROLLBACK_DATASTORE/datastore/tmp/metadata_all__DRAFT.json

File renamed without changes.

tests/resources/datastores/ROLLBACK_DATASTORE_PATCH/tmp/datastore_versions.json renamed to tests/resources/datastores/ROLLBACK_DATASTORE_PATCH/datastore/tmp/datastore_versions.json

File renamed without changes.

tests/resources/datastores/ROLLBACK_DATASTORE_PATCH/tmp/draft_version.json renamed to tests/resources/datastores/ROLLBACK_DATASTORE_PATCH/datastore/tmp/draft_version.json

File renamed without changes.

0 commit comments

Comments
 (0)