diff --git a/src/simplezfs/zfs.py b/src/simplezfs/zfs.py index 8cbe6e7..37e61b7 100644 --- a/src/simplezfs/zfs.py +++ b/src/simplezfs/zfs.py @@ -138,6 +138,18 @@ class ZFS: return True return False + def get_dataset_info(self, name: str) -> Dataset: + ''' + Returns basic information about a dataset. To retrieve its properties, see :func:`~ZFS.get_property` and + :func:`~ZFS.get_properties`. + + :param name: The name of the dataset in question. + :returns: The dataset info. + :raises DatasetNotFound: If the dataset does not exist. + :raises ValidationError: If the name was invalid. + ''' + raise NotImplementedError(f'{self} has not implemented this function') + def list_datasets(self, *, parent: Union[str, Dataset] = None) -> List[Dataset]: ''' Lists all datasets known to the system. If ``parent`` is set to a pool or dataset name (or a :class:`~zfs.types.Dataset`), diff --git a/src/simplezfs/zfs_cli.py b/src/simplezfs/zfs_cli.py index 068f8f0..b3d9f81 100644 --- a/src/simplezfs/zfs_cli.py +++ b/src/simplezfs/zfs_cli.py @@ -73,6 +73,17 @@ class ZFSCli(ZFS): validate_pool_name(name) return os.path.exists(os.path.join('/dev/zvol', name)) + def get_dataset_info(self, name: str) -> Dataset: + if '/' not in name: + validate_pool_name(name) + else: + validate_dataset_path(name) + args = [self.__exe, 'list', '-H', '-t', 'all', name] + proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8') + if proc.returncode != 0 or len(proc.stderr) > 0: + self.handle_command_error(proc) + return Dataset.from_string(proc.stdout.split('\t')[0].strip()) + def list_datasets(self, *, parent: Union[str, Dataset] = None) -> List[Dataset]: ''' :todo: ability to limit to a pool (path validator discards pool-only arguments) diff --git a/tests/test_zfs.py b/tests/test_zfs.py index 471dc7c..93169f5 100644 --- a/tests/test_zfs.py +++ b/tests/test_zfs.py @@ -423,6 +423,8 @@ class TestZFS: def test_notimplemented(self): zfs = ZFS() + with pytest.raises(NotImplementedError): + zfs.get_dataset_info('name') with pytest.raises(NotImplementedError): zfs.list_datasets() with pytest.raises(NotImplementedError): diff --git a/tests/test_zfs_cli.py b/tests/test_zfs_cli.py index 744f89b..895f0f4 100644 --- a/tests/test_zfs_cli.py +++ b/tests/test_zfs_cli.py @@ -72,6 +72,38 @@ class TestZFSCli: ########################################################################## + @patch('subprocess.run') + def test_get_dataset_info_happy_dataset(self, subproc): + test_stdout = 'rpool/test 105M 142G 192K none' + subproc.return_value = subprocess.CompletedProcess(args=[], returncode=0, stdout=test_stdout, stderr='') + + zfs = ZFSCli(zfs_exe='/bin/true') + data = zfs.get_dataset_info('rpool/test') + subproc.assert_called_once() + assert ['/bin/true', 'list', '-H', '-t', 'all', 'rpool/test'] == subproc.call_args[0][0] + assert data.pool == 'rpool' + assert data.parent == 'rpool' + assert data.name == 'test' + assert data.type == DatasetType.VOLUME + assert data.full_path == 'rpool/test' + + @patch('subprocess.run') + def test_get_dataset_info_happy_pool(self, subproc): + test_stdout = 'rpool 105M 142G 192K none' + subproc.return_value = subprocess.CompletedProcess(args=[], returncode=0, stdout=test_stdout, stderr='') + + zfs = ZFSCli(zfs_exe='/bin/true') + data = zfs.get_dataset_info('rpool') + subproc.assert_called_once() + assert ['/bin/true', 'list', '-H', '-t', 'all', 'rpool'] == subproc.call_args[0][0] + assert data.pool == 'rpool' + assert data.parent == None + assert data.name == 'rpool' + assert data.type == DatasetType.VOLUME + assert data.full_path == 'rpool' + + ########################################################################## + @patch('subprocess.run') def test_list_dataset_noparent_happy(self, subproc): test_stdout = '''tank 213G 13.3G 96K none