|
|
@ -4,6 +4,8 @@ ZFS frontend API
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import logging
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
import stat
|
|
|
|
from typing import Dict, List, Optional, Union
|
|
|
|
from typing import Dict, List, Optional, Union
|
|
|
|
|
|
|
|
|
|
|
|
from .exceptions import (
|
|
|
|
from .exceptions import (
|
|
|
@ -52,8 +54,9 @@ class ZFS:
|
|
|
|
:param metadata_namespace: Default namespace
|
|
|
|
:param metadata_namespace: Default namespace
|
|
|
|
:param kwargs: Extra arguments, ignored
|
|
|
|
:param kwargs: Extra arguments, ignored
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
def __init__(self, *, metadata_namespace: Optional[str] = None, **kwargs) -> None:
|
|
|
|
def __init__(self, *, metadata_namespace: Optional[str] = None, mount_helper: Optional[str] = None, **kwargs) -> None:
|
|
|
|
self.metadata_namespace = metadata_namespace
|
|
|
|
self.metadata_namespace = metadata_namespace
|
|
|
|
|
|
|
|
self.mount_helper = mount_helper
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
@property
|
|
|
|
def metadata_namespace(self) -> Optional[str]:
|
|
|
|
def metadata_namespace(self) -> Optional[str]:
|
|
|
@ -71,6 +74,37 @@ class ZFS:
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
self._metadata_namespace = namespace
|
|
|
|
self._metadata_namespace = namespace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
|
|
def mount_helper(self) -> Optional[str]:
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
Returns the mount_helper, which may be None if not set.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
return self._mount_helper
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mount_helper.setter
|
|
|
|
|
|
|
|
def mount_helper(self, helper: Optional[str]) -> None:
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
Sets the mount helper. Some basic checks for existance and executablility are performed, but these are not
|
|
|
|
|
|
|
|
sufficient for secure operation and are provided to aid the user in configuring the library.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:note: This method does not follow symlinks.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:raises FileNotFoundError: if the script can't be found or is not executable.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
if helper is None:
|
|
|
|
|
|
|
|
log.debug('Mount helper is None')
|
|
|
|
|
|
|
|
self._mount_helper = None
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
candidate = helper.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mode = os.lstat(candidate).st_mode
|
|
|
|
|
|
|
|
if not stat.S_ISREG(mode):
|
|
|
|
|
|
|
|
raise FileNotFoundError('Mount helper must be a file')
|
|
|
|
|
|
|
|
if not os.access(candidate, os.X_OK):
|
|
|
|
|
|
|
|
raise FileNotFoundError('Mount helper must be executable')
|
|
|
|
|
|
|
|
log.debug(f'Setting mount helper to "{candidate}"')
|
|
|
|
|
|
|
|
self._mount_helper = candidate
|
|
|
|
|
|
|
|
|
|
|
|
def dataset_exists(self, name: str) -> bool:
|
|
|
|
def dataset_exists(self, name: str) -> bool:
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
Checks is a dataset exists. This is done by querying for its `type` property.
|
|
|
|
Checks is a dataset exists. This is done by querying for its `type` property.
|
|
|
@ -294,7 +328,6 @@ class ZFS:
|
|
|
|
mountpoint: str = None,
|
|
|
|
mountpoint: str = None,
|
|
|
|
properties: Dict[str, str] = None,
|
|
|
|
properties: Dict[str, str] = None,
|
|
|
|
metadata_properties: Dict[str, str] = None,
|
|
|
|
metadata_properties: Dict[str, str] = None,
|
|
|
|
mount_helper: str = None,
|
|
|
|
|
|
|
|
recursive: bool = True
|
|
|
|
recursive: bool = True
|
|
|
|
) -> Dataset:
|
|
|
|
) -> Dataset:
|
|
|
|
'''
|
|
|
|
'''
|
|
|
@ -306,7 +339,6 @@ class ZFS:
|
|
|
|
:param properties: Dict of native properties to set.
|
|
|
|
:param properties: Dict of native properties to set.
|
|
|
|
:param metadata_properties: Dict of native properties to set. For namespaces other than the default (or when
|
|
|
|
:param metadata_properties: Dict of native properties to set. For namespaces other than the default (or when
|
|
|
|
no default has been set, format the key using ``namespace:key``.
|
|
|
|
no default has been set, format the key using ``namespace:key``.
|
|
|
|
:param mount_helper: Mount helper for Linux when not running as root. See :ref:`the_mount_problem` for details.
|
|
|
|
|
|
|
|
:param recursive: Recursively create the parent fileset. Refer to the ZFS documentation about the `-p`
|
|
|
|
:param recursive: Recursively create the parent fileset. Refer to the ZFS documentation about the `-p`
|
|
|
|
parameter for ``zfs create``.
|
|
|
|
parameter for ``zfs create``.
|
|
|
|
:return: Info about the newly created dataset.
|
|
|
|
:return: Info about the newly created dataset.
|
|
|
@ -324,7 +356,6 @@ class ZFS:
|
|
|
|
dataset_type=DatasetType.FILESET,
|
|
|
|
dataset_type=DatasetType.FILESET,
|
|
|
|
properties=properties,
|
|
|
|
properties=properties,
|
|
|
|
metadata_properties=metadata_properties,
|
|
|
|
metadata_properties=metadata_properties,
|
|
|
|
mount_helper=mount_helper
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def create_volume(
|
|
|
|
def create_volume(
|
|
|
@ -376,7 +407,6 @@ class ZFS:
|
|
|
|
dataset_type: DatasetType = DatasetType.FILESET,
|
|
|
|
dataset_type: DatasetType = DatasetType.FILESET,
|
|
|
|
properties: Dict[str, str] = None,
|
|
|
|
properties: Dict[str, str] = None,
|
|
|
|
metadata_properties: Dict[str, str] = None,
|
|
|
|
metadata_properties: Dict[str, str] = None,
|
|
|
|
mount_helper: str = None,
|
|
|
|
|
|
|
|
sparse: bool = False,
|
|
|
|
sparse: bool = False,
|
|
|
|
size: Optional[int] = None,
|
|
|
|
size: Optional[int] = None,
|
|
|
|
recursive: bool = False
|
|
|
|
recursive: bool = False
|
|
|
@ -404,7 +434,6 @@ class ZFS:
|
|
|
|
:param properties: A dict containing the properties for this new dataset. These are the native properties.
|
|
|
|
:param properties: A dict containing the properties for this new dataset. These are the native properties.
|
|
|
|
:param metadata_properties: The metadata properties to set. To use a different namespace than the default (or
|
|
|
|
:param metadata_properties: The metadata properties to set. To use a different namespace than the default (or
|
|
|
|
when no default is set), use the ``namespace:key`` format for the dict keys.
|
|
|
|
when no default is set), use the ``namespace:key`` format for the dict keys.
|
|
|
|
:param mount_helper: An executable that has the permission to manipulate the namespace, aka mount the fileset.
|
|
|
|
|
|
|
|
:param sparse: For volumes, specifies whether a sparse (thin provisioned) or normal (thick provisioned) volume
|
|
|
|
:param sparse: For volumes, specifies whether a sparse (thin provisioned) or normal (thick provisioned) volume
|
|
|
|
should be created.
|
|
|
|
should be created.
|
|
|
|
:param size: For volumes, specifies the size in bytes.
|
|
|
|
:param size: For volumes, specifies the size in bytes.
|
|
|
@ -508,7 +537,7 @@ class ZFS:
|
|
|
|
|
|
|
|
|
|
|
|
# TODO
|
|
|
|
# TODO
|
|
|
|
|
|
|
|
|
|
|
|
return self._create_dataset(name, dataset_type=dataset_type, properties=properties, metadata_properties=_metadata_properties, mount_helper=mount_helper, sparse=sparse, size=size, recursive=recursive)
|
|
|
|
return self._create_dataset(name, dataset_type=dataset_type, properties=properties, metadata_properties=_metadata_properties, sparse=sparse, size=size, recursive=recursive)
|
|
|
|
|
|
|
|
|
|
|
|
def _create_dataset(
|
|
|
|
def _create_dataset(
|
|
|
|
self,
|
|
|
|
self,
|
|
|
@ -517,7 +546,6 @@ class ZFS:
|
|
|
|
dataset_type: DatasetType,
|
|
|
|
dataset_type: DatasetType,
|
|
|
|
properties: Dict[str, str] = None,
|
|
|
|
properties: Dict[str, str] = None,
|
|
|
|
metadata_properties: Dict[str, str] = None,
|
|
|
|
metadata_properties: Dict[str, str] = None,
|
|
|
|
mount_helper: str = None,
|
|
|
|
|
|
|
|
sparse: bool = False,
|
|
|
|
sparse: bool = False,
|
|
|
|
size: Optional[int] = None,
|
|
|
|
size: Optional[int] = None,
|
|
|
|
recursive: bool = False,
|
|
|
|
recursive: bool = False,
|
|
|
|