示例#1
0
    def query(self, filters, options):
        """
        Query all ZFS Snapshots with `query-filters` and `query-options`.
        """
        # Special case for faster listing of snapshot names (#53149)
        if (
            options and options.get('select') == ['name'] and (
                not filters or
                filter_getattrs(filters).issubset({'name', 'pool'})
            )
        ):
            with libzfs.ZFS() as zfs:
                snaps = zfs.snapshots_serialized(['name'])

            if filters or len(options) > 1:
                return filter_list(snaps, filters, options)
            return snaps

        with libzfs.ZFS() as zfs:
            # Handle `id` filter to avoid getting all snapshots first
            kwargs = dict(holds=False, mounted=False)
            if filters and len(filters) == 1 and list(filters[0][:2]) == ['id', '=']:
                kwargs['datasets'] = [filters[0][2]]

            snapshots = zfs.snapshots_serialized(**kwargs)

        # FIXME: awful performance with hundreds/thousands of snapshots
        result = filter_list(snapshots, filters, options)

        if isinstance(result, list):
            result = self.middleware.call_sync('zettarepl.annotate_snapshots', result)
        elif isinstance(result, dict):
            result = self.middleware.call_sync('zettarepl.annotate_snapshots', [result])[0]

        return result
示例#2
0
文件: zfs.py 项目: tejp/freenas
 def query(self, filters=None, options=None):
     # If we are only filtering by name, pool and type we can use
     # zfs(8) which is much faster than py-libzfs
     if (
         options and set(options['select']).issubset({'name', 'pool', 'type'}) and
         filter_getattrs(filters).issubset({'name', 'pool', 'type'})
     ):
         cp = subprocess.run([
             'zfs', 'list', '-H', '-o', 'name,type', '-t', 'filesystem,volume',
         ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf8')
         datasets = []
         for i in cp.stdout.strip().split('\n'):
             name, type_ = i.split('\t')
             pool = name.split('/', 1)[0]
             datasets.append({
                 'name': name,
                 'pool': pool,
                 'type': type_.upper(),
             })
     else:
         with libzfs.ZFS() as zfs:
             # Handle `id` filter specially to avoiding getting all datasets
             if filters and len(filters) == 1 and list(filters[0][:2]) == ['id', '=']:
                 try:
                     datasets = [zfs.get_dataset(filters[0][2]).__getstate__()]
                 except libzfs.ZFSException:
                     datasets = []
             else:
                 datasets = [i.__getstate__() for i in zfs.datasets]
     return filter_list(datasets, filters, options)
示例#3
0
 def query(self, filters=None, options=None):
     """
     Query all ZFS Snapshots with `query-filters` and `query-options`.
     """
     # Special case for faster listing of snapshot names (#53149)
     if (
         options and options.get('select') == ['name'] and (
             not filters or
             filter_getattrs(filters).issubset({'name', 'pool'})
         )
     ):
         # Using zfs list -o name is dozens of times faster than py-libzfs
         cmd = ['zfs', 'list', '-H', '-o', 'name', '-t', 'snapshot']
         order_by = options.get('order_by')
         # -s name makes it even faster
         if not order_by or order_by == ['name']:
             cmd += ['-s', 'name']
         cp = subprocess.run(
             cmd,
             stdout=subprocess.PIPE,
             stderr=subprocess.PIPE,
             universal_newlines=True,
         )
         if cp.returncode != 0:
             raise CallError(f'Failed to retrieve snapshots: {cp.stderr}')
         stdout = cp.stdout.strip()
         if not stdout:
             return []
         snaps = [
             {'name': i, 'pool': i.split('/', 1)[0]}
             for i in stdout.split('\n')
         ]
         if filters:
             return filter_list(snaps, filters, options)
         return snaps
     with libzfs.ZFS() as zfs:
         # Handle `id` filter to avoid getting all snapshots first
         snapshots = []
         if filters and len(filters) == 1 and list(filters[0][:2]) == ['id', '=']:
             try:
                 snapshots.append(zfs.get_snapshot(filters[0][2]).__getstate__())
             except libzfs.ZFSException as e:
                 if e.code != libzfs.Error.NOENT:
                     raise
         else:
             for i in zfs.snapshots:
                 try:
                     snapshots.append(i.__getstate__())
                 except libzfs.ZFSException as e:
                     # snapshot may have been deleted while this is running
                     if e.code != libzfs.Error.NOENT:
                         raise
     # FIXME: awful performance with hundreds/thousands of snapshots
     return filter_list(snapshots, filters, options)
示例#4
0
文件: zfs.py 项目: freenas/freenas
 def query(self, filters=None, options=None):
     """
     Query all ZFS Snapshots with `query-filters` and `query-options`.
     """
     # Special case for faster listing of snapshot names (#53149)
     if (
         options and options.get('select') == ['name'] and (
             not filters or
             filter_getattrs(filters).issubset({'name', 'pool'})
         )
     ):
         # Using zfs list -o name is dozens of times faster than py-libzfs
         cmd = ['zfs', 'list', '-H', '-o', 'name', '-t', 'snapshot']
         order_by = options.get('order_by')
         # -s name makes it even faster
         if not order_by or order_by == ['name']:
             cmd += ['-s', 'name']
         cp = subprocess.run(
             cmd,
             stdout=subprocess.PIPE,
             stderr=subprocess.PIPE,
             universal_newlines=True,
         )
         if cp.returncode != 0:
             raise CallError(f'Failed to retrieve snapshots: {cp.stderr}')
         snaps = [
             {'name': i, 'pool': i.split('/', 1)[0]}
             for i in cp.stdout.strip().split('\n')
         ]
         if filters:
             return filter_list(snaps, filters, options)
         return snaps
     with libzfs.ZFS() as zfs:
         # Handle `id` filter to avoid getting all snapshots first
         snapshots = []
         if filters and len(filters) == 1 and list(filters[0][:2]) == ['id', '=']:
             try:
                 snapshots.append(zfs.get_snapshot(filters[0][2]).__getstate__())
             except libzfs.ZFSException as e:
                 if e.code != libzfs.Error.NOENT:
                     raise
         else:
             for i in zfs.snapshots:
                 try:
                     snapshots.append(i.__getstate__())
                 except libzfs.ZFSException as e:
                     # snapshot may have been deleted while this is running
                     if e.code != libzfs.Error.NOENT:
                         raise
     # FIXME: awful performance with hundreds/thousands of snapshots
     return filter_list(snapshots, filters, options)
示例#5
0
文件: zfs.py 项目: bmhughes/freenas
    def query(self, filters, options):
        """
        Query all ZFS Snapshots with `query-filters` and `query-options`.
        """
        # Special case for faster listing of snapshot names (#53149)
        if (options and options.get('select') == ['name']
                and (not filters
                     or filter_getattrs(filters).issubset({'name', 'pool'}))):
            with libzfs.ZFS() as zfs:
                snaps = zfs.snapshots_serialized(['name'])

            if filters or len(options) > 1:
                return filter_list(snaps, filters, options)
            return snaps

        extra = copy.deepcopy(options['extra'])
        properties = extra.get('properties')
        with libzfs.ZFS() as zfs:
            # Handle `id` filter to avoid getting all snapshots first
            kwargs = dict(holds=False, mounted=False, props=properties)
            if filters and len(filters) == 1 and len(
                    filters[0]) == 3 and filters[0][0] in (
                        'id', 'name') and filters[0][1] == '=':
                kwargs['datasets'] = [filters[0][2]]

            snapshots = zfs.snapshots_serialized(**kwargs)

        # FIXME: awful performance with hundreds/thousands of snapshots
        select = options.pop('select', None)
        result = filter_list(snapshots, filters, options)

        if not select or 'retention' in select:
            if isinstance(result, list):
                result = self.middleware.call_sync(
                    'zettarepl.annotate_snapshots', result)
            elif isinstance(result, dict):
                result = self.middleware.call_sync(
                    'zettarepl.annotate_snapshots', [result])[0]

        if select:
            if isinstance(result, list):
                result = [{k: v
                           for k, v in item.items() if k in select}
                          for item in result]
            elif isinstance(result, dict):
                result = {k: v for k, v in result.items() if k in select}

        return result