Skip to content

Commit f3c3893

Browse files
committed
fix: when the database is read-only
It can happen that the database could be read-only but running commands like gridtk list should still work.
1 parent 4e76bd8 commit f3c3893

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

src/gridtk/cli.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,14 @@ def _job_filters_decorator(function):
142142
"--database",
143143
help="Path to the database file.",
144144
default=Path("jobs.sql3"),
145-
type=click.Path(path_type=Path, file_okay=True, dir_okay=False, writable=True),
145+
type=click.Path(path_type=Path, file_okay=True, dir_okay=False),
146146
)
147147
@click.option(
148148
"-l",
149149
"--logs-dir",
150150
help="Path to the logs directory.",
151151
default=Path("logs"),
152-
type=click.Path(path_type=Path, file_okay=False, dir_okay=True, writable=True),
152+
type=click.Path(path_type=Path, file_okay=False, dir_okay=True),
153153
)
154154
@click.pass_context
155155
def cli(ctx, database, logs_dir):

src/gridtk/manager.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
from collections.abc import Iterable
2727
from pathlib import Path
28-
from typing import Any
28+
from typing import Any, Optional
2929

3030
import sqlalchemy
3131

@@ -98,15 +98,26 @@ def get_dependent_jobs_recursive(jobs: Iterable[Job]) -> list[Job]:
9898
class JobManager:
9999
"""Implements a job manager for Slurm."""
100100

101-
def __init__(self, database: Path, logs_dir: Path) -> None:
101+
def __init__(
102+
self, database: Path, logs_dir: Path, read_only: Optional[bool] = None
103+
) -> None:
102104
self.database = Path(database)
105+
# check if database exists and is read-only
106+
if (
107+
read_only is None
108+
and self.database.exists()
109+
and not os.access(self.database, os.W_OK)
110+
):
111+
read_only = True
112+
self.read_only = read_only
103113
self.engine = create_engine(f"sqlite:///{self.database}", echo=False)
104114
self.logs_dir = Path(logs_dir)
105115
self.logs_dir.mkdir(exist_ok=True)
106116

107117
def __enter__(self):
108118
# opens a new session and returns it
109-
Base.metadata.create_all(self.engine)
119+
if not self.read_only:
120+
Base.metadata.create_all(self.engine)
110121
self._session = Session(self.engine)
111122
self._session.begin()
112123
return self._session
@@ -165,6 +176,8 @@ def submit_job(self, name, command, array, dependencies):
165176

166177
def update_jobs(self) -> None:
167178
"""Update the status of all jobs."""
179+
if self.read_only:
180+
return
168181
jobs_by_grid_id: dict[int, Job] = dict()
169182
query = self.session.query(Job)
170183
for job in query.all():

tests/test_gridtk.py

+19
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
# SPDX-License-Identifier: GPL-3.0-or-later
55

66
import json
7+
import stat
78
import traceback
89

10+
from pathlib import Path
911
from unittest.mock import Mock, patch
1012

1113
import pytest
@@ -240,6 +242,23 @@ def test_list_jobs(mock_check_output, runner):
240242
)
241243

242244

245+
@patch("subprocess.check_output")
246+
def test_list_jobs_readonly_database(mock_check_output, runner):
247+
with runner.isolated_filesystem():
248+
submit_job_id = 9876543
249+
_submit_job(
250+
runner=runner, mock_check_output=mock_check_output, job_id=submit_job_id
251+
)
252+
# Simulate a readonly database
253+
mock_check_output.side_effect = []
254+
Path("jobs.sql3").chmod(stat.S_IREAD)
255+
result = runner.invoke(cli, ["list"])
256+
assert_click_runner_result(result)
257+
# The job should be UNKNOWN because we can't query the slurm when the
258+
# database is read-only
259+
assert "UNKNOWN" in result.output
260+
261+
243262
@patch("subprocess.check_output")
244263
def test_report_job(mock_check_output, runner):
245264
with runner.isolated_filesystem():

0 commit comments

Comments
 (0)