-
Notifications
You must be signed in to change notification settings - Fork 494
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a common 'TcpPort' type. Fix tcp port exclude option. Convert bindip_choices to new api. Convert NFS share CRUD to new api. Adds a new pydantic type: Dir
- Loading branch information
Showing
7 changed files
with
363 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
from .fc import * # noqa | ||
from .filesystem import * # noqa | ||
from .iscsi import * # noqa | ||
from .network import * # noqa | ||
from .string import * # noqa | ||
from .user import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import functools | ||
from typing import Annotated | ||
from pydantic import Field | ||
|
||
__all__ = ["TcpPort", "exclude_tcp_ports"] | ||
|
||
|
||
def _exclude_port_validation(value: int, *, ports: list[int]) -> int: | ||
if value in ports: | ||
raise ValueError( | ||
f'{value} is a reserved for internal use. Please select another value.' | ||
) | ||
return value | ||
|
||
|
||
def exclude_tcp_ports(ports: list[int]): | ||
return functools.partial(_exclude_port_validation, ports=ports or []) | ||
|
||
|
||
TcpPort = Annotated[int, Field(ge=1, le=65535)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import re | ||
from typing import Annotated, Literal | ||
|
||
from pydantic import ( | ||
ConfigDict, Field, IPvAnyAddress, IPvAnyNetwork, | ||
AfterValidator, field_validator | ||
) | ||
|
||
from middlewared.api.base import ( | ||
BaseModel, Excluded, excluded_field, ForUpdateMetaclass, NonEmptyString, | ||
single_argument_args, single_argument_result, | ||
TcpPort, exclude_tcp_ports, Dir | ||
) | ||
|
||
__all__ = ["NfsEntry", | ||
"NfsUpdateArgs", "NfsUpdateResult", | ||
"NfsBindipChoicesArgs", "NfsBindipChoicesResult", | ||
"NfsShareEntry", | ||
"NfsShareCreateArgs", "NfsShareCreateResult", | ||
"NfsShareUpdateArgs", "NfsShareUpdateResult", | ||
"NfsShareDeleteArgs", "NfsShareDeleteResult"] | ||
|
||
NFS_protocols = Literal["NFSV3", "NFSV4"] | ||
NFS_RDMA_DEFAULT_PORT = 20049 | ||
EXCLUDED_PORTS = [NFS_RDMA_DEFAULT_PORT] | ||
|
||
|
||
class NfsEntry(BaseModel): | ||
id: int | ||
servers: Annotated[int | None, Field(ge=1, le=256)] | ||
""" Specify the number of nfsd. Default: Number of nfsd is equal number of CPU. """ | ||
allow_nonroot: bool | ||
""" Allow non-root mount requests. This equates to 'insecure' share option. """ | ||
protocols: list[NFS_protocols] | ||
""" Specify supported NFS protocols: NFSv3, NFSv4 or both can be listed. """ | ||
v4_krb: bool | ||
""" Force Kerberos authentication on NFS shares. """ | ||
v4_domain: str | ||
""" Specify a DNS domain (NFSv4 only) """ | ||
# NOTE: Using IPvAnyAddress in bindip will generate a JSON serialization error | ||
bindip: list[NonEmptyString] = Field(default_factory=[]) | ||
""" Limit the server IP addresses available for NFS """ | ||
mountd_port: Annotated[TcpPort | None, AfterValidator(exclude_tcp_ports(EXCLUDED_PORTS))] | ||
""" Specify the mountd port binding """ | ||
rpcstatd_port: Annotated[TcpPort | None, AfterValidator(exclude_tcp_ports(EXCLUDED_PORTS))] | ||
""" Specify the rpc.statd port binding """ | ||
rpclockd_port: Annotated[TcpPort | None, AfterValidator(exclude_tcp_ports(EXCLUDED_PORTS))] | ||
""" Specify the rpc.lockd port binding """ | ||
mountd_log: bool | ||
""" Enable or disable mountd logging """ | ||
statd_lockd_log: bool | ||
""" Enable or disable statd and lockd logging """ | ||
v4_krb_enabled: bool | ||
""" Status of NFSv4 authentication requirement (status only) """ | ||
userd_manage_gids: bool | ||
""" Enable to allow server to manage gids """ | ||
keytab_has_nfs_spn: bool | ||
""" Report status of NFS Principal Name in keytab (status only)""" | ||
managed_nfsd: bool | ||
""" Report status of 'servers' field. | ||
If True the number of nfsd are managed by the server. (status only)""" | ||
rdma: bool | ||
""" Enable or disable NFS over RDMA. Requires RDMA capable NIC """ | ||
|
||
@field_validator('bindip') | ||
@classmethod | ||
def check_bind_ip(cls, field_value: list): | ||
""" Custom validator for IP addresses to avoid JSON serialization errors """ | ||
all(isinstance(v, IPvAnyAddress) for v in field_value) | ||
return field_value | ||
|
||
|
||
@single_argument_args('nfs_update') | ||
class NfsUpdateArgs(NfsEntry, metaclass=ForUpdateMetaclass): | ||
id: Excluded = excluded_field() | ||
managed_nfsd: Excluded = excluded_field() | ||
v4_krb_enabled: Excluded = excluded_field() | ||
keytab_has_nfs_spn: Excluded = excluded_field() | ||
|
||
|
||
class NfsUpdateResult(BaseModel): | ||
result: NfsEntry | ||
|
||
|
||
class NfsBindipChoicesArgs(BaseModel): | ||
pass | ||
|
||
|
||
@single_argument_result | ||
class NfsBindipChoicesResult(BaseModel): | ||
""" Return a dictionary of IP addresses """ | ||
model_config = ConfigDict(extra='allow') | ||
|
||
|
||
class NfsShareCreate(BaseModel): | ||
path: Dir | ||
aliases: list[Dir] = [] | ||
comment: str = "" | ||
networks: list[IPvAnyNetwork] = [] | ||
hosts: list[str] = [] | ||
ro: bool = False | ||
maproot_user: str | None = None | ||
maproot_group: str | None = None | ||
mapall_user: str | None = None | ||
mapall_group: str | None = None | ||
security: list[Literal["SYS", "KRB5", "KRB5I", "KRB5P"]] = [] | ||
enabled: bool = False | ||
|
||
@field_validator('networks', 'hosts') | ||
@classmethod | ||
def check_unique(cls, field_value: list): | ||
""" Custom validator to confirm unique entries """ | ||
s = set() | ||
not_unique = [] | ||
for i, v in enumerate(field_value): | ||
if v in s: | ||
# verrors.add(f"{self.name}.{i}", "This value is not unique.") | ||
not_unique.append(v) | ||
s.add(v) | ||
if not_unique: | ||
raise ValueError(f"Entries must be unique, the following are not: {not_unique}") | ||
|
||
return field_value | ||
|
||
@field_validator('hosts') | ||
@classmethod | ||
def no_spaces_or_quotes(cls, field_value: list): | ||
""" Custom validator for host field: No spaces or quotes """ | ||
regex = re.compile(r'.*[\s"]') | ||
not_valid = [] | ||
for v in field_value: | ||
if v is not None and regex.match(v): | ||
not_valid.append(v) | ||
if not_valid: | ||
raise ValueError(f"Cannot contain spaces or quotes: {not_valid}") | ||
|
||
|
||
class NfsShareEntry(NfsShareCreate): | ||
id: int | ||
locked: bool | ||
|
||
|
||
class NfsShareCreateArgs(BaseModel): | ||
data: NfsShareCreate | ||
|
||
|
||
class NfsShareCreateResult(BaseModel): | ||
result: NfsShareEntry | ||
|
||
|
||
class NfsShareUpdateArgs(NfsShareCreate, metaclass=ForUpdateMetaclass): | ||
id: int | ||
|
||
|
||
class NfsShareUpdateResult(BaseModel): | ||
result: NfsShareEntry | ||
|
||
|
||
class NfsShareDeleteArgs(BaseModel): | ||
id: int | ||
|
||
|
||
class NfsShareDeleteResult(BaseModel): | ||
result: Literal[True] |
Oops, something went wrong.