introduce pylint and address some warnings

main
svalouch 4 years ago
parent 55c5f54f33
commit 2e2ead0c3c

@ -23,3 +23,12 @@ addopts =
omit = omit =
venv/* venv/*
tests/* tests/*
[pylint.FORMAT]
max-line-length = 120
[pylint.MESSAGES CONTROL]
disable=logging-fstring-interpolation
[pylint.REPORTS]
output-format = colorized

@ -12,49 +12,42 @@ class ZFSException(Exception):
:note: Some functions throw ordinary python base exceptions as well. :note: Some functions throw ordinary python base exceptions as well.
''' '''
pass
class DatasetNotFound(ZFSException): class DatasetNotFound(ZFSException):
''' '''
A dataset was not found. A dataset was not found.
''' '''
pass
class PermissionError(ZFSException): class PermissionError(ZFSException):
''' '''
Permissions are not sufficient to carry out the task. Permissions are not sufficient to carry out the task.
''' '''
pass
class PoolNotFound(ZFSException): class PoolNotFound(ZFSException):
''' '''
A pool was not found. A pool was not found.
''' '''
pass
class PropertyNotFound(ZFSException): class PropertyNotFound(ZFSException):
''' '''
A property was not found. A property was not found.
''' '''
pass
class ValidationError(ZFSException): class ValidationError(ZFSException):
''' '''
Indicates that a value failed validation. Indicates that a value failed validation.
''' '''
pass
class PEHelperException(ZFSException): class PEHelperException(ZFSException):
''' '''
Indicates a problem when running the PE helper. Indicates a problem when running the PE helper.
''' '''
pass
class ExternalPEHelperException(PEHelperException): class ExternalPEHelperException(PEHelperException):

@ -1,10 +1,14 @@
'''
Privilege escalation helpers
'''
import logging import logging
import os import os
import shutil import shutil
import stat import stat
import subprocess import subprocess
from typing import List, Optional from typing import List
from .exceptions import PEHelperException, ExternalPEHelperException, ValidationError from .exceptions import PEHelperException, ExternalPEHelperException, ValidationError
from .validation import validate_dataset_path, validate_pool_name from .validation import validate_dataset_path, validate_pool_name

@ -38,14 +38,13 @@ class DatasetType(str, Enum):
val = value.lower() val = value.lower()
if val == 'fileset': if val == 'fileset':
return DatasetType.FILESET return DatasetType.FILESET
elif val == 'volume': if val == 'volume':
return DatasetType.VOLUME return DatasetType.VOLUME
elif val == 'snapshot': if val == 'snapshot':
return DatasetType.SNAPSHOT return DatasetType.SNAPSHOT
elif val == 'bookmark': if val == 'bookmark':
return DatasetType.BOOKMARK return DatasetType.BOOKMARK
else: raise ValueError(f'Value {value} is not a valid DatasetType')
raise ValueError(f'Value {value} is not a valid DatasetType')
class Dataset(NamedTuple): class Dataset(NamedTuple):
@ -128,18 +127,17 @@ class PropertySource(str, Enum):
val = value.lower() val = value.lower()
if val == 'default': if val == 'default':
return PropertySource.DEFAULT return PropertySource.DEFAULT
elif val == 'local': if val == 'local':
return PropertySource.LOCAL return PropertySource.LOCAL
elif val == 'inherited': if val == 'inherited':
return PropertySource.INHERITED return PropertySource.INHERITED
elif val == 'temporary': if val == 'temporary':
return PropertySource.TEMPORARY return PropertySource.TEMPORARY
elif val == 'received': if val == 'received':
return PropertySource.RECEIVED return PropertySource.RECEIVED
elif val == 'none' or val == '-': if val in ('none', '-'):
return PropertySource.NONE return PropertySource.NONE
else: raise ValueError(f'Value {value} is not a valid PropertySource')
raise ValueError(f'Value {value} is not a valid PropertySource')
class Property(NamedTuple): class Property(NamedTuple):
@ -179,7 +177,7 @@ class VDevType(str, Enum):
class ZPoolHealth(str, Enum): class ZPoolHealth(str, Enum):
''' '''
Pool health.
''' '''
ONLINE = 'ONLINE' ONLINE = 'ONLINE'
DEGRADED = 'DEGRADED' DEGRADED = 'DEGRADED'
@ -204,17 +202,16 @@ class ZPoolHealth(str, Enum):
val = value.lower() val = value.lower()
if val == 'online': if val == 'online':
return ZPoolHealth.ONLINE return ZPoolHealth.ONLINE
elif val == 'degraded': if val == 'degraded':
return ZPoolHealth.DEGRADED return ZPoolHealth.DEGRADED
elif val == 'faulted': if val == 'faulted':
return ZPoolHealth.FAULTED return ZPoolHealth.FAULTED
elif val == 'offline': if val == 'offline':
return ZPoolHealth.OFFLINE return ZPoolHealth.OFFLINE
elif val == 'unavail': if val == 'unavail':
return ZPoolHealth.UNAVAIL return ZPoolHealth.UNAVAIL
elif val == 'removed': if val == 'removed':
return ZPoolHealth.REMOVED return ZPoolHealth.REMOVED
elif val == 'avail': if val == 'avail':
return ZPoolHealth.AVAIL return ZPoolHealth.AVAIL
else: raise ValueError(f'Value {value} is not a valid ZPoolHealth')
raise ValueError(f'Value {value} is not a valid ZPoolHealth')

@ -90,7 +90,7 @@ def validate_dataset_name(name: str, *, strict: bool = False) -> None:
match = DATASET_NAME_RE.match(name) match = DATASET_NAME_RE.match(name)
if not match: if not match:
raise ValidationError('name contains disallowed characters') raise ValidationError('name contains disallowed characters')
elif strict and match.group('detail') is not None: if strict and match.group('detail') is not None:
raise ValidationError('snapshot or bookmark identifier are not allowed in strict mode') raise ValidationError('snapshot or bookmark identifier are not allowed in strict mode')

@ -176,7 +176,7 @@ class ZFS:
try: try:
self.set_property(fileset, 'mountpoint', mountpoint) self.set_property(fileset, 'mountpoint', mountpoint)
except PermissionError as e: except PermissionError as exc:
if self.pe_helper is not None: if self.pe_helper is not None:
real_use_pe_helper = use_pe_helper if use_pe_helper is not None else self.use_pe_helper real_use_pe_helper = use_pe_helper if use_pe_helper is not None else self.use_pe_helper
@ -185,7 +185,7 @@ class ZFS:
self.pe_helper.zfs_set_mountpoint(fileset, mountpoint) self.pe_helper.zfs_set_mountpoint(fileset, mountpoint)
else: else:
log.error(f'Permission error when setting mountpoint for "{fileset}" and not using PE helper') log.error(f'Permission error when setting mountpoint for "{fileset}" and not using PE helper')
raise e raise exc
else: else:
log.error(f'Permission error when setting mountpoint for "{fileset}" and PE helper is not set') log.error(f'Permission error when setting mountpoint for "{fileset}" and PE helper is not set')
@ -421,6 +421,7 @@ class ZFS:
dataset_type=DatasetType.FILESET, dataset_type=DatasetType.FILESET,
properties=properties, properties=properties,
metadata_properties=metadata_properties, metadata_properties=metadata_properties,
recursive=recursive,
) )
def create_volume( def create_volume(
@ -537,26 +538,25 @@ class ZFS:
# check the syntax of the properties # check the syntax of the properties
if properties is not None: if properties is not None:
for k, v in properties.items(): for k, val in properties.items():
validate_native_property_name(k) validate_native_property_name(k)
validate_property_value(v) validate_property_value(val)
_metadata_properties = dict() # type: Dict[str, str] _metadata_properties = dict() # type: Dict[str, str]
if metadata_properties is not None: if metadata_properties is not None:
for k, v in metadata_properties.items(): for k, val in metadata_properties.items():
# if the name has no namespace, add the default one if set # if the name has no namespace, add the default one if set
if ':' not in k: if ':' not in k:
if not self._metadata_namespace: if not self._metadata_namespace:
raise ValidationError(f'Metadata property {k} has no namespace and none is set globally') raise ValidationError(f'Metadata property {k} has no namespace and none is set globally')
else: meta_name = f'{self._metadata_namespace}:{k}'
meta_name = f'{self._metadata_namespace}:{k}'
else: else:
meta_name = k meta_name = k
_metadata_properties[meta_name] = metadata_properties[k] _metadata_properties[meta_name] = metadata_properties[k]
validate_metadata_property_name(meta_name) validate_metadata_property_name(meta_name)
if type(v) != str: if type(val) != str:
_metadata_properties[meta_name] = f'{v}' _metadata_properties[meta_name] = f'{val}'
validate_property_value(_metadata_properties[meta_name]) validate_property_value(_metadata_properties[meta_name])
# sparse and size are reset for all but the VOLUME type # sparse and size are reset for all but the VOLUME type
@ -584,8 +584,8 @@ class ZFS:
raise ValidationError('Size must be specified for volumes') raise ValidationError('Size must be specified for volumes')
try: try:
size = int(size) size = int(size)
except ValueError as e: except ValueError as exc:
raise ValidationError('Size is not an integer') from e raise ValidationError('Size is not an integer') from exc
if size < 1: if size < 1:
raise ValidationError('Size is too low') raise ValidationError('Size is too low')
@ -593,8 +593,8 @@ class ZFS:
if properties and 'blocksize' in properties: if properties and 'blocksize' in properties:
try: try:
blocksize = int(properties['blocksize']) blocksize = int(properties['blocksize'])
except ValueError: except ValueError as exc:
raise ValidationError('blocksize must be an integer') raise ValidationError('blocksize must be an integer') from exc
if blocksize < 2 or blocksize > 128 * 1024: # zfs(8) version 0.8.1 lists 128KB as maximum if blocksize < 2 or blocksize > 128 * 1024: # zfs(8) version 0.8.1 lists 128KB as maximum
raise ValidationError('blocksize must be between 2 and 128kb (inclusive)') raise ValidationError('blocksize must be between 2 and 128kb (inclusive)')
if not ((blocksize & (blocksize - 1) == 0) and blocksize != 0): if not ((blocksize & (blocksize - 1) == 0) and blocksize != 0):
@ -706,7 +706,7 @@ class ZFS:
if not self._pe_helper: if not self._pe_helper:
raise ValidationError('PE Helper is not set') raise ValidationError('PE Helper is not set')
if action not in ('create', 'destroy', 'set_mountpoint'): if action not in ('create', 'destroy', 'set_mountpoint'):
raise ValidationError(f'Invalid action') raise ValidationError('Invalid action')
validate_dataset_path(name) validate_dataset_path(name)
if action == 'create': if action == 'create':
@ -759,7 +759,7 @@ def get_zfs(api: str = 'cli', metadata_namespace: Optional[str] = None, **kwargs
if api == 'cli': if api == 'cli':
from .zfs_cli import ZFSCli from .zfs_cli import ZFSCli
return ZFSCli(metadata_namespace=metadata_namespace, **kwargs) return ZFSCli(metadata_namespace=metadata_namespace, **kwargs)
elif api == 'native': if api == 'native':
from .zfs_native import ZFSNative from .zfs_native import ZFSNative
return ZFSNative(metadata_namespace=metadata_namespace, **kwargs) return ZFSNative(metadata_namespace=metadata_namespace, **kwargs)
raise NotImplementedError(f'The api "{api}" has not been implemented.') raise NotImplementedError(f'The api "{api}" has not been implemented.')

@ -138,14 +138,13 @@ class ZFSCli(ZFS):
if dataset: if dataset:
raise DatasetNotFound(f'Dataset "{dataset}" not found') raise DatasetNotFound(f'Dataset "{dataset}" not found')
raise DatasetNotFound('Dataset not found') raise DatasetNotFound('Dataset not found')
elif 'bad property list: invalid property' in proc.stderr: if 'bad property list: invalid property' in proc.stderr:
if dataset: if dataset:
raise PropertyNotFound(f'invalid property on dataset {dataset}') raise PropertyNotFound(f'invalid property on dataset {dataset}')
else: raise PropertyNotFound('invalid property')
raise PropertyNotFound('invalid property') if 'permission denied' in proc.stderr:
elif 'permission denied' in proc.stderr:
raise PermissionError(proc.stderr) raise PermissionError(proc.stderr)
elif 'filesystem successfully created, but it may only be mounted by root' in proc.stderr: if 'filesystem successfully created, but it may only be mounted by root' in proc.stderr:
raise PermissionError(proc.stderr) raise PermissionError(proc.stderr)
raise Exception(f'Command execution "{" ".join(proc.args)}" failed: {proc.stderr}') raise Exception(f'Command execution "{" ".join(proc.args)}" failed: {proc.stderr}')
@ -281,10 +280,10 @@ class ZFSCli(ZFS):
self.pe_helper.zfs_mount(name) self.pe_helper.zfs_mount(name)
log.info(f'Fileset {name} created successfully (using pe_helper)') log.info(f'Fileset {name} created successfully (using pe_helper)')
return self.get_dataset_info(name) return self.get_dataset_info(name)
else:
msg = 'Fileset created partially but no PE helper set' msg = 'Fileset created partially but no PE helper set'
log.error(msg) log.error(msg)
raise PermissionError(msg) raise PermissionError(msg)
else: else:
msg = 'Mountpoint property not set, can\'t run pe_helper' msg = 'Mountpoint property not set, can\'t run pe_helper'
log.error(msg) log.error(msg)

@ -96,7 +96,7 @@ def get_zpool(api: str = 'cli', metadata_namespace: Optional[str] = None, **kwar
if api == 'cli': if api == 'cli':
from .zpool_cli import ZPoolCli from .zpool_cli import ZPoolCli
return ZPoolCli(metadata_namespace=metadata_namespace, **kwargs) return ZPoolCli(metadata_namespace=metadata_namespace, **kwargs)
elif api == 'native': if api == 'native':
from .zpool_native import ZPoolNative from .zpool_native import ZPoolNative
return ZPoolNative(metadata_namespace=metadata_namespace, **kwargs) return ZPoolNative(metadata_namespace=metadata_namespace, **kwargs)
raise NotImplementedError(f'The api "{api}" has not been implemented.') raise NotImplementedError(f'The api "{api}" has not been implemented.')

@ -14,7 +14,13 @@ log = logging.getLogger('simplezfs.zpool_cli')
class ZPoolCli(ZPool): class ZPoolCli(ZPool):
'''
ZPOOL interface implementation using the zpool(8) command line utility. For documentation, please see the interface
:class:`~zfs.zpool.ZPool`. It is recommended to use :func:`~zfs.zfs.get_zpool` to obtain an instance using ``cli``
as api.
If ``zpool_exe`` is supplied, it is assumed that it points to the path to the ``zpool(8)`` executable.
'''
def __init__(self, *, metadata_namespace: Optional[str] = None, pe_helper: Optional[str] = None, def __init__(self, *, metadata_namespace: Optional[str] = None, pe_helper: Optional[str] = None,
use_pe_helper: bool = False, zpool_exe: Optional[str] = None, **kwargs) -> None: use_pe_helper: bool = False, zpool_exe: Optional[str] = None, **kwargs) -> None:
super().__init__(metadata_namespace=metadata_namespace, pe_helper=pe_helper, use_pe_helper=use_pe_helper) super().__init__(metadata_namespace=metadata_namespace, pe_helper=pe_helper, use_pe_helper=use_pe_helper)

@ -8,7 +8,11 @@ from .zpool import ZPool
class ZPoolNative(ZPool): class ZPoolNative(ZPool):
'''
ZPool interface implementation using the libzfs_core python bindings. For documentation, please see the interface
:class:`~zfs.zpool.ZPool`. It is recommended to use :func:`~zfs.zpool.get_zpool` to obtain an instance, using
``native`` as api.
'''
def __init__(self, *, metadata_namespace: Optional[str] = None, pe_helper: Optional[str] = None, def __init__(self, *, metadata_namespace: Optional[str] = None, pe_helper: Optional[str] = None,
use_pe_helper: bool = False, **kwargs) -> None: use_pe_helper: bool = False, **kwargs) -> None:
super().__init__(metadata_namespace=metadata_namespace, pe_helper=pe_helper, use_pe_helper=use_pe_helper) super().__init__(metadata_namespace=metadata_namespace, pe_helper=pe_helper, use_pe_helper=use_pe_helper)

Loading…
Cancel
Save