From 53e6738e5f380d0085538d866340bc6808e4a273 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Mon, 10 Jul 2023 10:45:48 +1200 Subject: [PATCH 1/3] add annotations to all storage model objects --- subiquity/models/filesystem.py | 177 +++++++++++++++++---------------- 1 file changed, 93 insertions(+), 84 deletions(-) diff --git a/subiquity/models/filesystem.py b/subiquity/models/filesystem.py index b8e58405e..21216d3a1 100644 --- a/subiquity/models/filesystem.py +++ b/subiquity/models/filesystem.py @@ -26,6 +26,7 @@ import pathlib import platform import tempfile +from typing import List, Optional, Set, Union import more_itertools @@ -140,6 +141,9 @@ def wrapper(c): c.type = attributes.const(typ) c.id = attr.ib(default=None) c._m = attr.ib(repr=None, default=None) + c.__annotations__['id'] = str + c.__annotations__['_m'] = "FilesystemModel" + c.__annotations__['type'] = str c = attr.s(eq=False, repr=False)(c) c.__repr__ = fsobj__repr _type_to_cls[typ] = c @@ -452,10 +456,8 @@ class _Formattable(ABC): # Base class for anything that can be formatted and mounted, # e.g. a disk or a RAID or a partition. - # Filesystem - _fs = attributes.backlink() - # Raid or LVM_VolGroup or ZPool for now, but one day BCache... - _constructed_device = attributes.backlink() + _fs: Optional["Filesystem"] = attributes.backlink() + _constructed_device: Optional["ConstructedDevice"] = attributes.backlink() def _is_entirely_used(self): return self._fs is not None or self._constructed_device is not None @@ -519,7 +521,8 @@ def size(self): pass # [Partition] - _partitions = attributes.backlink(default=attr.Factory(list)) + _partitions: List["Partition"] = attributes.backlink( + default=attr.Factory(list)) def dasd(self): return None @@ -593,28 +596,28 @@ def renumber_logical_partitions(self, removed_partition): @fsobj("dasd") class Dasd: - device_id = attr.ib() - blocksize = attr.ib() - disk_layout = attr.ib() - label = attr.ib(default=None) - mode = attr.ib(default=None) - preserve = attr.ib(default=False) + device_id: str = attr.ib() + blocksize: int = attr.ib() + disk_layout: str = attr.ib() + label: Optional[str] = attr.ib(default=None) + mode: Optional[str] = attr.ib(default=None) + preserve: bool = attr.ib(default=False) @fsobj("disk") class Disk(_Device): - ptable = attributes.ptable() - serial = attr.ib(default=None) - wwn = attr.ib(default=None) - multipath = attr.ib(default=None) - path = attr.ib(default=None) - wipe = attr.ib(default=None) - preserve = attr.ib(default=False) - name = attr.ib(default="") - grub_device = attr.ib(default=False) - device_id = attr.ib(default=None) - - _info = attr.ib(default=None) + ptable: Optional[str] = attributes.ptable() + serial: str = attr.ib(default=None) + wwn: str = attr.ib(default=None) + multipath: str = attr.ib(default=None) + path: str = attr.ib(default=None) + wipe: Optional[str] = attr.ib(default=None) + preserve: str = attr.ib(default=False) + name: str = attr.ib(default="") + grub_device: bool = attr.ib(default=False) + device_id: str = attr.ib(default=None) + + _info: Optional[StorageInfo] = attr.ib(default=None) @property def available_for_partitions(self): @@ -709,21 +712,21 @@ def _decode_id(self, id): @fsobj("partition") class Partition(_Formattable): - device = attributes.ref(backlink="_partitions") # Disk - size = attributes.size() - - wipe = attr.ib(default=None) - flag = attr.ib(default=None) - number = attr.ib(default=None) - preserve = attr.ib(default=False) - grub_device = attr.ib(default=False) - name = attr.ib(default=None) - multipath = attr.ib(default=None) - offset = attr.ib(default=None) - resize = attr.ib(default=None) - partition_type = attr.ib(default=None) - partition_name = attr.ib(default=None) - path = attr.ib(default=None) + device: _Device = attributes.ref(backlink="_partitions") + size: int = attributes.size() + + wipe: Optional[str] = attr.ib(default=None) + flag: Optional[str] = attr.ib(default=None) + number: Optional[int] = attr.ib(default=None) + preserve: bool = attr.ib(default=False) + grub_device: bool = attr.ib(default=False) + name: Optional[str] = attr.ib(default=None) + multipath: Optional[str] = attr.ib(default=None) + offset: Optional[int] = attr.ib(default=None) + resize: Optional[bool] = attr.ib(default=None) + partition_type: Optional[str] = attr.ib(default=None) + partition_name: Optional[str] = attr.ib(default=None) + path: Optional[str] = attr.ib(default=None) def __post_init__(self): if self.number is not None: @@ -813,9 +816,9 @@ def is_logical(self): @fsobj("raid") class Raid(_Device): - name = attr.ib() + name: str = attr.ib() raidlevel: str = attr.ib(converter=lambda x: raidlevels_by_value[x].value) - devices = attributes.reflist( + devices: Set[Union[Disk, Partition, "Raid"]] = attributes.reflist( backlink="_constructed_device", default=attr.Factory(set)) def serialize_devices(self): @@ -824,16 +827,17 @@ def serialize_devices(self): # way get_raid_size does. return {'devices': [d.id for d in raid_device_sort(self.devices)]} - spare_devices = attributes.reflist( + spare_devices: Set[Union[Disk, Partition, "Raid"]] = attributes.reflist( backlink="_constructed_device", default=attr.Factory(set)) - preserve = attr.ib(default=False) - wipe = attr.ib(default=None) - ptable = attributes.ptable() - metadata = attr.ib(default=None) - _path = attr.ib(default=None) - container = attributes.ref(backlink="_subvolumes", default=None) # Raid - _subvolumes = attributes.backlink(default=attr.Factory(list)) + preserve: bool = attr.ib(default=False) + wipe: Optional[str] = attr.ib(default=None) + ptable: Optional[str] = attributes.ptable() + metadata: Optional[str] = attr.ib(default=None) + _path: Optional[str] = attr.ib(default=None) + container: Optional["Raid"] = attributes.ref( + backlink="_subvolumes", default=None) + _subvolumes: List["Raid"] = attributes.backlink(default=attr.Factory(list)) @property def path(self): @@ -897,10 +901,11 @@ def ok_for_lvm_vg(self): @fsobj("lvm_volgroup") class LVM_VolGroup(_Device): - name = attr.ib() - devices = attributes.reflist(backlink="_constructed_device") + name: str = attr.ib() + devices: List[Union[Disk, Partition, Raid]] = attributes.reflist( + backlink="_constructed_device") - preserve = attr.ib(default=False) + preserve: bool = attr.ib(default=False) @property def size(self): @@ -920,13 +925,13 @@ def available_for_partitions(self): @fsobj("lvm_partition") class LVM_LogicalVolume(_Formattable): - name = attr.ib() - volgroup = attributes.ref(backlink="_partitions") # LVM_VolGroup - size = attributes.size(default=None) - wipe = attr.ib(default=None) + name: str = attr.ib() + volgroup: LVM_VolGroup = attributes.ref(backlink="_partitions") + size: int = attributes.size(default=None) + wipe: Optional[str] = attr.ib(default=None) - preserve = attr.ib(default=False) - path = attr.ib(default=None) + preserve: bool = attr.ib(default=False) + path: Optional[str] = attr.ib(default=None) def serialize_size(self): if self.size is None: @@ -954,10 +959,10 @@ def flag(self): @fsobj("dm_crypt") class DM_Crypt: - volume = attributes.ref(backlink="_constructed_device") # _Formattable - key = attr.ib(metadata={'redact': True}, default=None) - keyfile = attr.ib(default=None) - path = attr.ib(default=None) + volume: _Formattable = attributes.ref(backlink="_constructed_device") + key: Optional[str] = attr.ib(metadata={'redact': True}, default=None) + keyfile: Optional[str] = attr.ib(default=None) + path: Optional[str] = attr.ib(default=None) def serialize_key(self): if self.key and not self.keyfile: @@ -969,10 +974,10 @@ def serialize_key(self): else: return {} - dm_name = attr.ib(default=None) - preserve = attr.ib(default=False) + dm_name: Optional[str] = attr.ib(default=None) + preserve: bool = attr.ib(default=False) - _constructed_device = attributes.backlink() + _constructed_device: Optional["ConstructedDevice"] = attributes.backlink() def constructed_device(self): return self._constructed_device @@ -984,8 +989,8 @@ def size(self): @fsobj("device") class ArbitraryDevice(_Device): - ptable = attr.ib(default=None) - path = attr.ib(default=None) + ptable: Optional[str] = attr.ib(default=None) + path: Optional[str] = attr.ib(default=None) @property def size(self): @@ -997,15 +1002,15 @@ def size(self): @fsobj("format") class Filesystem: - fstype = attr.ib() - volume = attributes.ref(backlink="_fs") # _Formattable + fstype: str = attr.ib() + volume: _Formattable = attributes.ref(backlink="_fs") - label = attr.ib(default=None) - uuid = attr.ib(default=None) - preserve = attr.ib(default=False) - extra_options = attr.ib(default=None) + label: Optional[str] = attr.ib(default=None) + uuid: Optional[str] = attr.ib(default=None) + preserve: bool = attr.ib(default=False) + extra_options: Optional[List[str]] = attr.ib(default=None) - _mount = attributes.backlink() + _mount: Optional["Mount"] = attributes.backlink() def mount(self): return self._mount @@ -1023,11 +1028,11 @@ def _available(self): @fsobj("mount") class Mount: - path = attr.ib() - device = attributes.ref(backlink="_mount", default=None) # Filesystem - fstype = attr.ib(default=None) - options = attr.ib(default=None) - spec = attr.ib(default=None) + path: str = attr.ib() + device: Filesystem = attributes.ref(backlink="_mount", default=None) + fstype: Optional[str] = attr.ib(default=None) + options: Optional[str] = attr.ib(default=None) + spec: Optional[str] = attr.ib(default=None) def can_delete(self): from subiquity.common.filesystem import boot @@ -1046,16 +1051,17 @@ def can_delete(self): @fsobj("zpool") class ZPool: - vdevs = attributes.reflist(backlink="_constructed_device") + vdevs: List[Union[Disk, Partition]] = attributes.reflist( + backlink="_constructed_device") pool: str = attr.ib() mountpoint: str = attr.ib() - _zfses = attributes.backlink(default=attr.Factory(list)) + _zfses: List["ZFS"] = attributes.backlink(default=attr.Factory(list)) # storage options on the pool - pool_properties: dict = attr.ib(default=None) + pool_properties: Optional[dict] = attr.ib(default=None) # default dataset options for the zfses in the pool - fs_properties: dict = attr.ib(default=None) + fs_properties: Optional[dict] = attr.ib(default=None) async def pre_shutdown(self, command_runner): await command_runner.run(['zpool', 'export', self.pool]) @@ -1063,10 +1069,13 @@ async def pre_shutdown(self, command_runner): @fsobj("zfs") class ZFS: - pool = attributes.ref(backlink="_zfses") + pool: ZPool = attributes.ref(backlink="_zfses") volume: str = attr.ib() # options to pass to zfs dataset creation - properties: dict = attr.ib(default=None) + properties: Optional[dict] = attr.ib(default=None) + + +ConstructedDevice = Union[Raid, LVM_VolGroup, ZPool] def align_up(size, block_size=1 << 20): From 678f73093725f319e58aa490ffeb7eec084afadb Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Mon, 10 Jul 2023 10:51:41 +1200 Subject: [PATCH 2/3] set kw_only and auto_attribs for all storage model objects --- subiquity/models/filesystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subiquity/models/filesystem.py b/subiquity/models/filesystem.py index 21216d3a1..9346ffa90 100644 --- a/subiquity/models/filesystem.py +++ b/subiquity/models/filesystem.py @@ -144,7 +144,7 @@ def wrapper(c): c.__annotations__['id'] = str c.__annotations__['_m'] = "FilesystemModel" c.__annotations__['type'] = str - c = attr.s(eq=False, repr=False)(c) + c = attr.s(eq=False, repr=False, auto_attribs=True, kw_only=True)(c) c.__repr__ = fsobj__repr _type_to_cls[typ] = c return c From 06977b3b90b4360a6cf40fe985414985e0e2f7ce Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Mon, 10 Jul 2023 10:57:07 +1200 Subject: [PATCH 3/3] remove redundant attr.ib objects --- subiquity/models/filesystem.py | 122 ++++++++++++++++----------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/subiquity/models/filesystem.py b/subiquity/models/filesystem.py index 9346ffa90..8ae058338 100644 --- a/subiquity/models/filesystem.py +++ b/subiquity/models/filesystem.py @@ -596,28 +596,28 @@ def renumber_logical_partitions(self, removed_partition): @fsobj("dasd") class Dasd: - device_id: str = attr.ib() - blocksize: int = attr.ib() - disk_layout: str = attr.ib() - label: Optional[str] = attr.ib(default=None) - mode: Optional[str] = attr.ib(default=None) - preserve: bool = attr.ib(default=False) + device_id: str + blocksize: int + disk_layout: str + label: Optional[str] = None + mode: Optional[str] = None + preserve: bool = False @fsobj("disk") class Disk(_Device): ptable: Optional[str] = attributes.ptable() - serial: str = attr.ib(default=None) - wwn: str = attr.ib(default=None) - multipath: str = attr.ib(default=None) - path: str = attr.ib(default=None) - wipe: Optional[str] = attr.ib(default=None) - preserve: str = attr.ib(default=False) - name: str = attr.ib(default="") - grub_device: bool = attr.ib(default=False) - device_id: str = attr.ib(default=None) - - _info: Optional[StorageInfo] = attr.ib(default=None) + serial: str = None + wwn: str = None + multipath: str = None + path: str = None + wipe: Optional[str] = None + preserve: str = False + name: str = "" + grub_device: bool = False + device_id: str = None + + _info: Optional[StorageInfo] = None @property def available_for_partitions(self): @@ -715,18 +715,18 @@ class Partition(_Formattable): device: _Device = attributes.ref(backlink="_partitions") size: int = attributes.size() - wipe: Optional[str] = attr.ib(default=None) - flag: Optional[str] = attr.ib(default=None) - number: Optional[int] = attr.ib(default=None) - preserve: bool = attr.ib(default=False) - grub_device: bool = attr.ib(default=False) - name: Optional[str] = attr.ib(default=None) - multipath: Optional[str] = attr.ib(default=None) - offset: Optional[int] = attr.ib(default=None) - resize: Optional[bool] = attr.ib(default=None) - partition_type: Optional[str] = attr.ib(default=None) - partition_name: Optional[str] = attr.ib(default=None) - path: Optional[str] = attr.ib(default=None) + wipe: Optional[str] = None + flag: Optional[str] = None + number: Optional[int] = None + preserve: bool = False + grub_device: bool = False + name: Optional[str] = None + multipath: Optional[str] = None + offset: Optional[int] = None + resize: Optional[bool] = None + partition_type: Optional[str] = None + partition_name: Optional[str] = None + path: Optional[str] = None def __post_init__(self): if self.number is not None: @@ -816,7 +816,7 @@ def is_logical(self): @fsobj("raid") class Raid(_Device): - name: str = attr.ib() + name: str raidlevel: str = attr.ib(converter=lambda x: raidlevels_by_value[x].value) devices: Set[Union[Disk, Partition, "Raid"]] = attributes.reflist( backlink="_constructed_device", default=attr.Factory(set)) @@ -830,11 +830,11 @@ def serialize_devices(self): spare_devices: Set[Union[Disk, Partition, "Raid"]] = attributes.reflist( backlink="_constructed_device", default=attr.Factory(set)) - preserve: bool = attr.ib(default=False) - wipe: Optional[str] = attr.ib(default=None) + preserve: bool = False + wipe: Optional[str] = None ptable: Optional[str] = attributes.ptable() - metadata: Optional[str] = attr.ib(default=None) - _path: Optional[str] = attr.ib(default=None) + metadata: Optional[str] = None + _path: Optional[str] = None container: Optional["Raid"] = attributes.ref( backlink="_subvolumes", default=None) _subvolumes: List["Raid"] = attributes.backlink(default=attr.Factory(list)) @@ -901,11 +901,11 @@ def ok_for_lvm_vg(self): @fsobj("lvm_volgroup") class LVM_VolGroup(_Device): - name: str = attr.ib() + name: str devices: List[Union[Disk, Partition, Raid]] = attributes.reflist( backlink="_constructed_device") - preserve: bool = attr.ib(default=False) + preserve: bool = False @property def size(self): @@ -925,13 +925,13 @@ def available_for_partitions(self): @fsobj("lvm_partition") class LVM_LogicalVolume(_Formattable): - name: str = attr.ib() + name: str volgroup: LVM_VolGroup = attributes.ref(backlink="_partitions") size: int = attributes.size(default=None) - wipe: Optional[str] = attr.ib(default=None) + wipe: Optional[str] = None - preserve: bool = attr.ib(default=False) - path: Optional[str] = attr.ib(default=None) + preserve: bool = False + path: Optional[str] = None def serialize_size(self): if self.size is None: @@ -961,8 +961,8 @@ def flag(self): class DM_Crypt: volume: _Formattable = attributes.ref(backlink="_constructed_device") key: Optional[str] = attr.ib(metadata={'redact': True}, default=None) - keyfile: Optional[str] = attr.ib(default=None) - path: Optional[str] = attr.ib(default=None) + keyfile: Optional[str] = None + path: Optional[str] = None def serialize_key(self): if self.key and not self.keyfile: @@ -974,8 +974,8 @@ def serialize_key(self): else: return {} - dm_name: Optional[str] = attr.ib(default=None) - preserve: bool = attr.ib(default=False) + dm_name: Optional[str] = None + preserve: bool = False _constructed_device: Optional["ConstructedDevice"] = attributes.backlink() @@ -989,8 +989,8 @@ def size(self): @fsobj("device") class ArbitraryDevice(_Device): - ptable: Optional[str] = attr.ib(default=None) - path: Optional[str] = attr.ib(default=None) + ptable: Optional[str] = None + path: Optional[str] = None @property def size(self): @@ -1002,13 +1002,13 @@ def size(self): @fsobj("format") class Filesystem: - fstype: str = attr.ib() + fstype: str volume: _Formattable = attributes.ref(backlink="_fs") - label: Optional[str] = attr.ib(default=None) - uuid: Optional[str] = attr.ib(default=None) - preserve: bool = attr.ib(default=False) - extra_options: Optional[List[str]] = attr.ib(default=None) + label: Optional[str] = None + uuid: Optional[str] = None + preserve: bool = False + extra_options: Optional[List[str]] = None _mount: Optional["Mount"] = attributes.backlink() @@ -1028,11 +1028,11 @@ def _available(self): @fsobj("mount") class Mount: - path: str = attr.ib() + path: str device: Filesystem = attributes.ref(backlink="_mount", default=None) - fstype: Optional[str] = attr.ib(default=None) - options: Optional[str] = attr.ib(default=None) - spec: Optional[str] = attr.ib(default=None) + fstype: Optional[str] = None + options: Optional[str] = None + spec: Optional[str] = None def can_delete(self): from subiquity.common.filesystem import boot @@ -1053,15 +1053,15 @@ def can_delete(self): class ZPool: vdevs: List[Union[Disk, Partition]] = attributes.reflist( backlink="_constructed_device") - pool: str = attr.ib() - mountpoint: str = attr.ib() + pool: str + mountpoint: str _zfses: List["ZFS"] = attributes.backlink(default=attr.Factory(list)) # storage options on the pool - pool_properties: Optional[dict] = attr.ib(default=None) + pool_properties: Optional[dict] = None # default dataset options for the zfses in the pool - fs_properties: Optional[dict] = attr.ib(default=None) + fs_properties: Optional[dict] = None async def pre_shutdown(self, command_runner): await command_runner.run(['zpool', 'export', self.pool]) @@ -1070,9 +1070,9 @@ async def pre_shutdown(self, command_runner): @fsobj("zfs") class ZFS: pool: ZPool = attributes.ref(backlink="_zfses") - volume: str = attr.ib() + volume: str # options to pass to zfs dataset creation - properties: Optional[dict] = attr.ib(default=None) + properties: Optional[dict] = None ConstructedDevice = Union[Raid, LVM_VolGroup, ZPool]