refactor
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
from pathlib import Path
|
||||
|
||||
from ._core import CommandInterface
|
||||
from ..pool import Pool
|
||||
from ..misc import assert_type
|
||||
from ..time import Time
|
||||
|
||||
|
||||
class ZPool(CommandInterface):
|
||||
_BINARY = Path("/usr/bin/zpool")
|
||||
|
||||
class _Subcommands:
|
||||
# -N: no mount
|
||||
# -d: directory to search the pool in
|
||||
import_ = ["import", "-N", "-d"]
|
||||
export = ["export"]
|
||||
scrub = ["scrub"]
|
||||
status = ["status"]
|
||||
wait = ["wait", "-t", "scrub"]
|
||||
|
||||
@classmethod
|
||||
def import_from_directory(cls, pool: Pool, directory: Path) -> None:
|
||||
"""Search `directory` for `pool` and import it."""
|
||||
assert_type(pool, Pool, "Can only import Pool objects")
|
||||
cls._run_command(*cls._Subcommands.import_, str(directory), pool.name)
|
||||
|
||||
@classmethod
|
||||
def export(cls, pool: Pool) -> None:
|
||||
"""Export the pool."""
|
||||
assert_type(pool, Pool, "Can only export Pool objects")
|
||||
cls._run_command(*cls._Subcommands.export, pool.name)
|
||||
|
||||
@classmethod
|
||||
def scrub(
|
||||
cls,
|
||||
pool: Pool,
|
||||
*,
|
||||
skip_if_recently_scrubbed: bool,
|
||||
recent_scrub_timedelta: timedelta,
|
||||
wait_for_finish: bool = True,
|
||||
) -> None:
|
||||
"""Scrub the pool.
|
||||
|
||||
Waits for the scrub to finish. Raise an IOError if the pool reports as not healthy after the scrub."""
|
||||
assert_type(pool, Pool, "Can only scrub pools.")
|
||||
cls._scrub_if_necessary(pool, skip_if_recently_scrubbed, recent_scrub_timedelta)
|
||||
if wait_for_finish:
|
||||
cls._run_command(*cls._Subcommands.wait, pool.name)
|
||||
if not cls._is_healthy(pool):
|
||||
raise IOError(f"Pool {pool.name} is not healthy.")
|
||||
|
||||
@classmethod
|
||||
def _scrub_if_necessary(
|
||||
cls,
|
||||
pool: Pool,
|
||||
skip_if_recently_scrubbed: bool,
|
||||
recent_scrub_timedelta: timedelta,
|
||||
) -> None:
|
||||
"""Scrub the pool. If"""
|
||||
|
||||
def do_scrub():
|
||||
cls._run_command(*cls._Subcommands.scrub, pool.name)
|
||||
|
||||
if cls._scrub_in_progress(pool):
|
||||
return
|
||||
if not skip_if_recently_scrubbed:
|
||||
do_scrub()
|
||||
else:
|
||||
if not cls._recently_scrubbed(pool, recent_scrub_timedelta):
|
||||
do_scrub()
|
||||
|
||||
@classmethod
|
||||
def _recently_scrubbed(cls, pool: Pool, recent_scrub_timedelta: timedelta) -> bool:
|
||||
"""Is the interval after the last scrub smaller than the minimum timedelta?"""
|
||||
return datetime.now() - cls._last_scrub(pool) < recent_scrub_timedelta
|
||||
|
||||
@classmethod
|
||||
def _scrub_in_progress(cls, pool: Pool) -> bool:
|
||||
return "scrub in progress" in cls._get_pool_status_output(pool)
|
||||
|
||||
@classmethod
|
||||
def _is_healthy(cls, pool: Pool) -> bool:
|
||||
return "ONLINE" in cls._get_pool_status_output(pool)
|
||||
|
||||
@classmethod
|
||||
def _get_pool_status_output(cls, pool: Pool) -> str:
|
||||
"""Return output of `zpool status [pool]`."""
|
||||
return cls._get_output(*cls._Subcommands.status, pool.name)
|
||||
|
||||
@classmethod
|
||||
def _last_scrub(cls, pool: Pool) -> datetime:
|
||||
"""Get time of the last scrub."""
|
||||
return Time.get_last_scrub_from_status_output(cls._get_pool_status_output(pool))
|
||||
Reference in New Issue
Block a user