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
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)
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)
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)
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