FreeNAS/freenas a510b66src/middlewared/middlewared/api/v25_10_0 pool.py

NAS-134689 / 25.10 / Do not allow users to create pool with whitespaces in name (#15984)

## Context

We had added validation earlier to not allow users to set a pool for
incus which has whitespaces in it's name because incus is not able to
handle pool names which have whitespaces in it. Now we are adding
changes to not allow user to create/import a pool with a name which
contains whitespaces.
DeltaFile
+21-5src/middlewared/middlewared/api/v25_10_0/pool.py
+21-51 files

UnifiedSplitRaw

src/middlewared/middlewared/api/v25_10_0/pool.py
@@ -1,9 +1,11 @@
-from typing import Annotated, Literal+import re
+from typing import Annotated, Literal, TypeAlias
-from pydantic import Field, PositiveInt, Secret+from pydantic import AfterValidator, Field, PositiveInt, Secret, StringConstraints
from middlewared.api.base import ( from middlewared.api.base import (
- BaseModel, Excluded, excluded_field, NonEmptyString, single_argument_args, LongString, ForUpdateMetaclass+ BaseModel, Excluded, excluded_field, match_validator, NonEmptyString, single_argument_args,
+ LongString, ForUpdateMetaclass,
) )
@@ -21,6 +23,20 @@ __all__ = [
] ]
+# Incus cannot consume a pool which has whitespaces in its name.
+# FIXME: Once this is fixed on incus side, we can remove this and keep on relying libzfs to do the validation only
+POOL_NAME: TypeAlias = Annotated[
+ NonEmptyString,
+ AfterValidator(
+ match_validator(
+ re.compile(r"^\S+$"),
+ "Pool name must not contain whitespace"
+ )
+ ),
+ StringConstraints(max_length=50)
+]
+
+
class PoolTopology(BaseModel): class PoolTopology(BaseModel):
data: list data: list
log: list log: list
@@ -171,7 +187,7 @@ class PoolCreateTopology(BaseModel):
class PoolCreate(BaseModel): class PoolCreate(BaseModel):
- name: Annotated[str, Field(max_length=50)]+ name: POOL_NAME
encryption: bool = False encryption: bool = False
"""If set, create a ZFS encrypted root dataset for this pool.""" """If set, create a ZFS encrypted root dataset for this pool."""
dedup_table_quota: Literal["AUTO", "CUSTOM", None] = "AUTO" dedup_table_quota: Literal["AUTO", "CUSTOM", None] = "AUTO"
@@ -360,7 +376,7 @@ class PoolImportFindResult(BaseModel):
@single_argument_args("pool_import") @single_argument_args("pool_import")
class PoolImportPoolArgs(BaseModel): class PoolImportPoolArgs(BaseModel):
guid: str guid: str
- name: str | None = None+ name: POOL_NAME | None = None
"""If specified, import the pool using this name.""" """If specified, import the pool using this name."""