You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
6.3 KiB
Python
217 lines
6.3 KiB
Python
|
|
'''
|
|
Type declarations
|
|
'''
|
|
|
|
import os
|
|
from enum import Enum, unique
|
|
from typing import NamedTuple, Optional
|
|
|
|
from .validation import validate_dataset_path, validate_pool_name
|
|
|
|
|
|
@unique
|
|
class DatasetType(str, Enum):
|
|
'''
|
|
Enumeration of dataset types that ZFS supports.
|
|
'''
|
|
#: Dataset is an ordinary fileset
|
|
FILESET = 'fileset'
|
|
#: Dataset is a ZVOL
|
|
VOLUME = 'volume'
|
|
#: Dataset is a snapshot
|
|
SNAPSHOT = 'snapshot'
|
|
#: Dataset is a bookmark
|
|
BOOKMARK = 'bookmark'
|
|
|
|
@staticmethod
|
|
def from_string(value: str) -> 'DatasetType':
|
|
'''
|
|
Helper to convert a string to an instance.
|
|
|
|
:param value: The string to converts.
|
|
:returns: The enum value
|
|
:raises ValueError: If the supplied value is not found in the enumeration.
|
|
'''
|
|
if not isinstance(value, str):
|
|
raise ValueError('only string types allowed')
|
|
val = value.lower()
|
|
if val == 'fileset':
|
|
return DatasetType.FILESET
|
|
elif val == 'volume':
|
|
return DatasetType.VOLUME
|
|
elif val == 'snapshot':
|
|
return DatasetType.SNAPSHOT
|
|
elif val == 'bookmark':
|
|
return DatasetType.BOOKMARK
|
|
else:
|
|
raise ValueError(f'Value {value} is not a valid DatasetType')
|
|
|
|
|
|
class Dataset(NamedTuple):
|
|
'''
|
|
Container describing a single dataset.
|
|
'''
|
|
#: Name of the dataset (excluding the path)
|
|
name: str
|
|
#: Full path to and including the dataset itself
|
|
full_path: str
|
|
#: Pool name
|
|
pool: str
|
|
#: Parent dataset, or None for the topmost dataset (pool)
|
|
parent: Optional[str]
|
|
#: Dataset type
|
|
type: DatasetType
|
|
|
|
@staticmethod
|
|
def from_string(value: str) -> 'Dataset':
|
|
'''
|
|
Helper to convert a string to a Dataset.
|
|
|
|
:param value: The value to convert.
|
|
:raises ValidationError: if the value can't be converted.
|
|
:return: the dataset instance
|
|
'''
|
|
if '/' in value:
|
|
validate_dataset_path(value)
|
|
tokens = value.split('/')
|
|
ds_name = tokens[-1]
|
|
ds_parent = '/'.join(tokens[:-1]) # type: Optional[str]
|
|
ds_pool = tokens[0]
|
|
else:
|
|
validate_pool_name(value)
|
|
ds_name = value
|
|
ds_parent = None
|
|
ds_pool = value
|
|
|
|
if '@' in ds_name:
|
|
ds_type = DatasetType.SNAPSHOT
|
|
elif '#' in ds_name:
|
|
ds_type = DatasetType.BOOKMARK
|
|
elif os.path.exists(os.path.join('/dev/zvol', value)):
|
|
ds_type = DatasetType.VOLUME
|
|
else:
|
|
ds_type = DatasetType.FILESET
|
|
|
|
return Dataset(name=ds_name, parent=ds_parent, type=ds_type, full_path=value, pool=ds_pool)
|
|
|
|
|
|
@unique
|
|
class PropertySource(str, Enum):
|
|
'''
|
|
Enumeration of the valid property sources in ZFS.
|
|
'''
|
|
#: Property is at default
|
|
DEFAULT = 'default'
|
|
#: Property was inerited
|
|
INHERITED = 'inherited'
|
|
#: Property is temporary
|
|
TEMPORARY = 'temporary'
|
|
#: Property is set to the value that it had due to the sender of a "zfs send/receive" operation having it set this way.
|
|
RECEIVED = 'received'
|
|
#: Property is set on the dataset in question
|
|
NONE = 'none'
|
|
|
|
@staticmethod
|
|
def from_string(value: str) -> 'PropertySource':
|
|
'''
|
|
Helper to convert a string to an instance.
|
|
|
|
:param value: The string to convert.
|
|
:returns: The enum value.
|
|
:raises ValueError: If the supplied value is not found in the enumeration.
|
|
'''
|
|
if not isinstance(value, str):
|
|
raise ValueError('only string types allowed')
|
|
val = value.lower()
|
|
if val == 'default':
|
|
return PropertySource.DEFAULT
|
|
elif val == 'inherited':
|
|
return PropertySource.INHERITED
|
|
elif val == 'temporary':
|
|
return PropertySource.TEMPORARY
|
|
elif val == 'received':
|
|
return PropertySource.RECEIVED
|
|
elif val == 'none' or val == '-':
|
|
return PropertySource.NONE
|
|
else:
|
|
raise ValueError(f'Value {value} is not a valid PropertySource')
|
|
|
|
|
|
class Property(NamedTuple):
|
|
'''
|
|
Container for a single ZFS property.
|
|
'''
|
|
#: Key or name of the property (excluding namespace for non-native properties)
|
|
key: str
|
|
#: Value of the property
|
|
value: str
|
|
#: Source of the property value
|
|
source: PropertySource = PropertySource.NONE
|
|
#: Namespace name of the property, None for native properties
|
|
namespace: Optional[str] = None
|
|
|
|
|
|
class VDevType(str, Enum):
|
|
'''
|
|
Type of a vdev. vdevs are either one of two storages (disk or file) or one of the special parts (mirror, raidz*,
|
|
spare, log, dedup, special and cache).
|
|
When reading zpool output, it is not always clear what type a vdev is when it comes to "disk" vs. "file", so a
|
|
special type "DISK_OR_FILE" is used. This type is invalid when setting values.
|
|
'''
|
|
DISK = 'disk'
|
|
FILE = 'file'
|
|
DISK_OR_FILE = 'disk_or_file'
|
|
MIRROR = 'mirror'
|
|
RAIDZ1 = 'raidz1'
|
|
RAIDZ2 = 'raidz2'
|
|
RAIDZ3 = 'raidz3'
|
|
SPARE = 'spare'
|
|
LOG = 'log'
|
|
DEDUP = 'dedup'
|
|
SPECIAL = 'special'
|
|
CACHE = 'cache'
|
|
|
|
|
|
class ZPoolHealth(str, Enum):
|
|
'''
|
|
|
|
'''
|
|
ONLINE = 'ONLINE'
|
|
DEGRADED = 'DEGRADED'
|
|
FAULTED = 'FAULTED'
|
|
OFFLINE = 'OFFLINE'
|
|
UNAVAIL = 'UNAVAIL'
|
|
REMOVED = 'REMOVED'
|
|
#: This one is used for spares
|
|
AVAIL = 'AVAIL'
|
|
|
|
@staticmethod
|
|
def from_string(value: str) -> 'ZPoolHealth':
|
|
'''
|
|
Helper to convert a string to an instance.
|
|
|
|
:param value: The string to convert.
|
|
:returns: The enum value.
|
|
:raises ValueError: If the supplied value is not found in the enumeration.
|
|
'''
|
|
if not isinstance(value, str):
|
|
raise ValueError('only string types are allowed')
|
|
val = value.lower()
|
|
if val == 'online':
|
|
return ZPoolHealth.ONLINE
|
|
elif val == 'degraded':
|
|
return ZPoolHealth.DEGRADED
|
|
elif val == 'faulted':
|
|
return ZPoolHealth.FAULTED
|
|
elif val == 'offline':
|
|
return ZPoolHealth.OFFLINE
|
|
elif val == 'unavail':
|
|
return ZPoolHealth.UNAVAIL
|
|
elif val == 'removed':
|
|
return ZPoolHealth.REMOVED
|
|
elif val == 'avail':
|
|
return ZPoolHealth.AVAIL
|
|
else:
|
|
raise ValueError(f'Value {value} is not a valid ZPoolHealth')
|