Skip to content

Commit

Permalink
NAS-132736 / 25.04 / Convert pool.scrub to new api style (#15045)
Browse files Browse the repository at this point in the history
* pause

* test

* fix CRUDService.query call

* don't fail in @job if args are not provided (fail in @api_method instead)

* exclude pool_name from pool.scrub.update args
  • Loading branch information
creatorcary authored Nov 27, 2024
1 parent feca45d commit 90d1f68
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 44 deletions.
1 change: 1 addition & 0 deletions src/middlewared/middlewared/api/v25_04_0/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from .iscsi_extent import * # noqa
from .keychain import * # noqa
from .netdata import * # noqa
from .pool_scrub import * # noqa
from .pool import * # noqa
from .privilege import * # noqa
from .reporting import * # noqa
Expand Down
81 changes: 81 additions & 0 deletions src/middlewared/middlewared/api/v25_04_0/pool_scrub.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from typing import Annotated, Literal

from pydantic import Field, PositiveInt

from middlewared.api.base import BaseModel, Excluded, excluded_field, ForUpdateMetaclass
from .common import CronModel


__all__ = [
"PoolScrubEntry", "PoolScrubCreateArgs", "PoolScrubCreateResult", "PoolScrubUpdateArgs", "PoolScrubUpdateResult",
"PoolScrubDeleteArgs", "PoolScrubDeleteResult", "PoolScrubScrubArgs", "PoolScrubScrubResult", "PoolScrubRunArgs",
"PoolScrubRunResult"
]


class PoolScrubCron(CronModel):
minute: str = "00"
hour: str = "00"
dow: str = "7"


class PoolScrubEntry(BaseModel):
pool: PositiveInt
threshold: Annotated[int, Field(ge=0)]
description: str
schedule: PoolScrubCron
enabled: bool = True
id: int
pool_name: str


class PoolScrubCreate(PoolScrubEntry):
id: Excluded = excluded_field()
pool_name: Excluded = excluded_field()


class PoolScrubUpdate(PoolScrubCreate, metaclass=ForUpdateMetaclass):
pass


class PoolScrubCreateArgs(BaseModel):
data: PoolScrubCreate


class PoolScrubCreateResult(BaseModel):
result: PoolScrubEntry


class PoolScrubUpdateArgs(BaseModel):
id_: int
data: PoolScrubUpdate


class PoolScrubUpdateResult(BaseModel):
result: PoolScrubEntry


class PoolScrubDeleteArgs(BaseModel):
id_: int


class PoolScrubDeleteResult(BaseModel):
result: Literal[True]


class PoolScrubScrubArgs(BaseModel):
name: str
action: Literal["START", "STOP", "PAUSE"] = "START"


class PoolScrubScrubResult(BaseModel):
result: None


class PoolScrubRunArgs(BaseModel):
name: str
threshold: int = 35


class PoolScrubRunResult(BaseModel):
result: None
60 changes: 16 additions & 44 deletions src/middlewared/middlewared/plugins/pool_/scrub.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
import re
import shlex

import middlewared.sqlalchemy as sa

from middlewared.schema import accepts, Bool, Cron, Dict, Int, Patch, returns, Str
from middlewared.api import api_method
from middlewared.api.current import (
PoolScrubEntry, PoolScrubCreateArgs, PoolScrubCreateResult, PoolScrubUpdateArgs, PoolScrubUpdateResult,
PoolScrubDeleteArgs, PoolScrubDeleteResult, PoolScrubScrubArgs, PoolScrubScrubResult, PoolScrubRunArgs,
PoolScrubRunResult
)
from middlewared.schema import Cron
from middlewared.service import CallError, CRUDService, job, private, ValidationErrors
import middlewared.sqlalchemy as sa
from middlewared.utils import run
from middlewared.validators import Range


RE_HISTORY_ZPOOL_SCRUB_CREATE = re.compile(r'^([0-9\.\:\-]{19})\s+(py-libzfs: )?zpool (scrub|create)', re.MULTILINE)
Expand Down Expand Up @@ -42,26 +46,7 @@ class Config:
namespace = 'pool.scrub'
cli_namespace = 'storage.scrub'
role_prefix = 'POOL_SCRUB'

ENTRY = Dict(
'pool_scrub_entry',
Int('pool', validators=[Range(min_=1)], required=True),
Int('threshold', validators=[Range(min_=0)], required=True),
Str('description', required=True),
Cron(
'schedule',
defaults={
'minute': '00',
'hour': '00',
'dow': '7'
},
required=True,
),
Bool('enabled', default=True, required=True),
Int('id', required=True),
Str('pool_name', required=True),
register=True
)
entry = PoolScrubEntry

@private
async def pool_scrub_extend(self, data):
Expand Down Expand Up @@ -96,7 +81,7 @@ async def validate_data(self, data, schema):
pool_pk != data['original_pool_id']
)
):
scrub_obj = await self.query(filters=[('pool', '=', pool_pk)])
scrub_obj = await self.query([('pool', '=', pool_pk)])
if len(scrub_obj) != 0:
verrors.add(
f'{schema}.pool',
Expand All @@ -105,16 +90,7 @@ async def validate_data(self, data, schema):

return verrors, data

@accepts(
Patch(
'pool_scrub_entry', 'pool_scrub_entry',
('rm', {'name': 'id'}),
('rm', {'name': 'pool_name'}),
('edit', {'name': 'threshold', 'method': lambda x: setattr(x, 'required', False)}),
('edit', {'name': 'schedule', 'method': lambda x: setattr(x, 'required', False)}),
('edit', {'name': 'description', 'method': lambda x: setattr(x, 'required', False)}),
)
)
@api_method(PoolScrubCreateArgs, PoolScrubCreateResult)
async def do_create(self, data):
"""
Create a scrub task for a pool.
Expand Down Expand Up @@ -159,6 +135,7 @@ async def do_create(self, data):

return await self.get_instance(data['id'])

@api_method(PoolScrubUpdateArgs, PoolScrubUpdateResult)
async def do_update(self, id_, data):
"""
Update scrub task of `id`.
Expand Down Expand Up @@ -191,7 +168,7 @@ async def do_update(self, id_, data):

return await self.get_instance(id_)

@accepts(Int('id'))
@api_method(PoolScrubDeleteArgs, PoolScrubDeleteResult)
async def do_delete(self, id_):
"""
Delete scrub task of `id`.
Expand All @@ -205,17 +182,13 @@ async def do_delete(self, id_):
await self.middleware.call('service.restart', 'cron')
return response

@accepts(
Str('name', required=True),
Str('action', enum=['START', 'STOP', 'PAUSE'], default='START')
)
@returns()
@api_method(PoolScrubScrubArgs, PoolScrubScrubResult)
@job(
description=lambda name, action="START": (
f"Scrub of pool {name!r}" if action == "START"
else f"{action.title()} scrubbing pool {name!r}"
),
lock=lambda i: f'{i[0]}-{i[1] if len(i) >= 2 else "START"}',
lock=lambda i: f'{i[0]}-{i[1] if len(i) >= 2 else "START"}' if i else '',
)
async def scrub(self, job, name, action):
"""
Expand Down Expand Up @@ -246,8 +219,7 @@ async def scrub(self, job, name, action):

await asyncio.sleep(1)

@accepts(Str('name'), Int('threshold', default=35))
@returns()
@api_method(PoolScrubRunArgs, PoolScrubRunResult)
async def run(self, name, threshold):
"""
Initiate a scrub of a pool `name` if last scrub was performed more than `threshold` days before.
Expand Down

0 comments on commit 90d1f68

Please sign in to comment.