def check_disks(context, disks, cache_disks=None, log_disks=None): all_disks = [disk["path"] for disk in context.call_sync("disk.query")] available_disks = context.call_sync('volume.get_available_disks') if cache_disks is not None: for disk in cache_disks: disk = correct_disk_path(disk) if disk not in all_disks: raise CommandException(_("Disk {0} does not exist.".format(disk))) if disk in available_disks: available_disks.remove(disk) else: raise CommandException(_("Disk {0} is not available.".format(disk))) if log_disks is not None: for disk in log_disks: disk = correct_disk_path(disk) if disk not in all_disks: raise CommandException(_("Disk {0} does not exist.".format(disk))) if disk in available_disks: available_disks.remove(disk) else: raise CommandException(_("Disk {0} is not available.".format(disk))) if 'auto' in disks: return available_disks, cache_disks, log_disks else: for disk in disks: disk = correct_disk_path(disk) if disk not in all_disks: raise CommandException(_("Disk {0} does not exist.".format(disk))) if disk not in available_disks: raise CommandException(_("Disk {0} is not available.".format(disk))) return disks, cache_disks, log_disks
def run(self, context, args, kwargs, opargs): if 'vdev' not in kwargs: raise CommandException(_("Please specify a vdev to mirror to.")) vdev_ident = correct_disk_path(kwargs.pop('vdev')) if len(args) < 1: raise CommandException(_("Please specify a disk to add to the vdev.")) elif len(args) > 1: raise CommandException(_("Invalid input: {0}".format(args))) disk = correct_disk_path(args[0]) if disk not in context.call_sync('volume.get_available_disks'): raise CommandException(_("Disk {0} is not available".format(disk))) vdev = first_or_default(lambda v: v['path'] == vdev_ident or vdev_ident in [i['path'] for i in v['children']], self.parent.entity['topology']['data'] ) if vdev['type'] == 'disk': vdev['type'] = 'mirror' vdev['children'].append({ 'type': 'disk', 'path': vdev_ident }) vdev['children'].append({ 'type': 'disk', 'path': disk }) self.parent.modified = True self.parent.save()
def check_disks(context, disks, cache_disks=None, log_disks=None): all_disks = [disk["path"] for disk in context.call_sync("disk.query")] available_disks = context.call_sync('volume.get_available_disks') if cache_disks is not None: for disk in cache_disks: disk = correct_disk_path(disk) if disk not in all_disks: raise CommandException(_("Disk {0} does not exist.".format(disk))) if disk in available_disks: available_disks.remove(disk) else: raise CommandException(_("Disk {0} is not available.".format(disk))) if log_disks is not None: for disk in log_disks: disk = correct_disk_path(disk) if disk not in all_disks: raise CommandException(_("Disk {0} does not exist.".format(disk))) if disk in available_disks: available_disks.remove(disk) else: raise CommandException(_("Disk {0} is not available.".format(disk))) if 'auto' in disks: return 'auto', cache_disks, log_disks else: for disk in disks: disk = correct_disk_path(disk) if disk not in all_disks: raise CommandException(_("Disk {0} does not exist.".format(disk))) if disk not in available_disks: raise CommandException(_("Disk {0} is not available.".format(disk))) return disks, cache_disks, log_disks
def run(self, context, args, kwargs, opargs): if not args: raise CommandException("detach_disk requires more arguments.\n{0}".format(inspect.getdoc(self))) disk = args.pop(0) disk = correct_disk_path(disk) context.submit_task('boot.detach_disk', disk) return
def run(self, context, args, kwargs, opargs): if not args: raise CommandException('Not enough arguments provided') disk = args.pop(0) disk = correct_disk_path(disk) tid = context.submit_task('boot.disk.detach', disk) return TaskPromise(context, tid)
def set_disks(self, entity, args): all_disks = [disk["path"] for disk in self.context.call_sync("disk.query")] disks = [] for disk in args: disk = correct_disk_path(disk) if disk not in all_disks: raise CommandException(_("Invalid disk: {0}, see '/ disk show' for a list of disks".format(disk))) disks.append(disk) self.set_args(entity, disks, 'disks')
def run(self, context, args, kwargs, opargs): if not args: raise CommandException('Not enough arguments provided') disk = args.pop(0) disk = correct_disk_path(disk) all_disks = context.entity_subscribers['disk'].query(select='path') if disk not in all_disks: raise CommandException(f"Disk {disk} does not exist.") tid = context.submit_task('boot.disk.attach', disk) return TaskPromise(context, tid)
def set_disks(self, entity, args): all_disks = [ disk["path"] for disk in self.context.call_sync("disk.query") ] disks = [] for disk in args: disk = correct_disk_path(disk) if disk not in all_disks: raise CommandException( _("Invalid disk: {0}, see '/ disk show' for a list of disks" .format(disk))) disks.append(disk) self.set_args(entity, disks, 'disks')
def run(self, context, args, kwargs, opargs): if not args: output_msg("attach_disk requires more arguments.\n{0}".format(inspect.getdoc(self))) return disk = args.pop(0) # The all_disks below is a temporary fix, use this after "select" is working # all_disks = context.call_sync('disk.query', [], {"select":"path"}) all_disks = [d["path"] for d in context.call_sync("disk.query")] available_disks = context.call_sync('volume.get_available_disks') disk = correct_disk_path(disk) if disk not in all_disks: output_msg("Disk " + disk + " does not exist.") return if disk not in available_disks: output_msg("Disk " + disk + " is not usable.") return context.submit_task('boot.disk.attach', disk) return
def run(self, context, args, kwargs, opargs): if not args: output_msg("attach_disk requires more arguments.\n{0}".format(inspect.getdoc(self))) return disk = args.pop(0) # The all_disks below is a temporary fix, use this after "select" is working # all_disks = context.call_sync('disk.query', [], {"select":"path"}) all_disks = [d["path"] for d in context.call_sync("disk.query")] available_disks = context.call_sync('volume.get_available_disks') disk = correct_disk_path(disk) if disk not in all_disks: output_msg("Disk " + disk + " does not exist.") return if disk not in available_disks: output_msg("Disk " + disk + " is not usable.") return volume = context.call_sync('zfs.pool.get_boot_pool') context.submit_task('boot.attach_disk', volume['groups']['data'][0]['guid'], disk) return
def run(self, context, args, kwargs, opargs): if len(args) == 0: raise CommandException(_("Please specify a disk")) disk = args[0] volume = self.parent.entity disk = correct_disk_path(disk) vdevs = list(iterate_vdevs(volume['topology'])) guid = None for vdev in vdevs: if vdev['path'] == disk: guid = vdev['guid'] break if guid is None: raise CommandException(_("Disk {0} is not part of the volume.".format(disk))) context.submit_task( 'volume.vdev.online', self.parent.entity['id'], guid, callback=lambda s, t: post_save(self.parent, s, t) )
def run(self, context, args, kwargs, opargs): if len(args) < 1: raise CommandException('Not enough arguments passed') id = args[0] oldname = args[0] if 'key' in kwargs: if 'disks' not in kwargs: raise CommandException('You have to provide list of disks when importing an encrypted volume') disks = kwargs['disks'] if isinstance(disks, str): disks = [disks] correct_disks = [] for dname in disks: correct_disks.append(correct_disk_path(dname)) encryption = {'key': kwargs['key'], 'disks': correct_disks} password = kwargs.get('password', None) else: encryption = {} password = None if not args[0].isdigit(): vols = context.call_sync('volume.find') vol = first_or_default(lambda v: v['name'] == args[0], vols) if not vol: raise CommandException('Importable volume {0} not found'.format(args[0])) id = vol['id'] oldname = vol['name'] context.submit_task('volume.import', id, kwargs.get('newname', oldname), {}, encryption, password)
def run(self, context, args, kwargs, opargs): entity = self.parent.entity if 'type' not in kwargs: raise CommandException(_( "Please specify a type of vdev, see 'help add_vdev' for more information" )) disks_per_type = DISKS_PER_TYPE.copy() disks_per_type.pop('auto', None) disks_per_type.update({ 'log': 1, 'cache': 1, }) typ = kwargs.pop('type') if disks_per_type.get(typ) is None: raise CommandException(_("Invalid vdev type")) if 'disks' not in kwargs: raise CommandException(_("Please specify one or more disks using the disks property")) else: disks = check_disks(context, to_list(kwargs.pop('disks')))[0] if len(disks) < disks_per_type[typ]: raise CommandException(_( "Vdev of type {0} requires at least {1} disks".format(typ, disks_per_type[typ]) )) if typ == 'mirror': entity['topology']['data'].append({ 'type': 'mirror', 'children': [{'type': 'disk', 'path': correct_disk_path(x)} for x in disks] }) if typ == 'disk': if len(disks) != 1: raise CommandException(_("Disk vdev consist of single disk")) entity['topology']['data'].append({ 'type': 'disk', 'path': correct_disk_path(disks[0]) }) if typ == 'cache': if 'cache' not in entity: entity['topology']['cache'] = [] entity['topology']['cache'].append({ 'type': 'disk', 'path': correct_disk_path(disks[0]) }) if typ == 'log': if len(disks) != 1: raise CommandException(_("Log vdevs cannot be mirrored")) if 'log' not in entity: entity['topology']['log'] = [] entity['topology']['log'].append({ 'type': 'disk', 'path': correct_disk_path(disks[0]) }) if typ.startswith('raidz'): entity['topology']['data'].append({ 'type': typ, 'children': [{'type': 'disk', 'path': correct_disk_path(x)} for x in disks] }) self.parent.modified = True self.parent.save()
def run(self, context, args, kwargs, opargs): if not args and not kwargs: raise CommandException(_("create requires more arguments, see 'help create' for more information")) if len(args) > 1: raise CommandException(_("Wrong syntax for create, see 'help create' for more information")) # This magic below make either `create foo` or `create name=foo` work if len(args) == 1: # However, do not allow user to specify name as both implicit and explicit parameter as this suggests a mistake if 'name' in kwargs: raise CommandException(_("Both implicit and explicit 'name' parameters are specified.")) else: kwargs[self.parent.primary_key.name] = args.pop(0) if 'name' not in kwargs: raise CommandException(_('Please specify a name for your pool')) else: name = kwargs.pop('name') volume_type = kwargs.pop('type', 'auto') if volume_type not in VDEV_TYPES: raise CommandException(_( "Invalid volume type {0}. Should be one of: {1}".format(volume_type, VDEV_TYPES) )) if 'disks' not in kwargs: raise CommandException(_("Please specify one or more disks using the disks property")) else: disks = kwargs.pop('disks') if isinstance(disks, six.string_types): disks = [disks] if read_value(kwargs.pop('encryption', False), ValueType.BOOLEAN) is True: encryption = True password = kwargs.get('password', None) else: encryption = False password = None cache_disks = kwargs.pop('cache', []) log_disks = kwargs.pop('log', []) if cache_disks is None: cache_disks = [] if log_disks is None: log_disks = [] if isinstance(cache_disks, six.string_types): cache_disks = [cache_disks] if isinstance(log_disks, six.string_types): log_disks = [log_disks] ns = SingleItemNamespace(None, self.parent) ns.orig_entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity)) ns.entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity)) disks, cache_disks, log_disks = check_disks(context, disks, cache_disks, log_disks) if len(disks) < DISKS_PER_TYPE[volume_type]: raise CommandException(_("Volume type {0} requires at least {1} disks".format(volume_type, DISKS_PER_TYPE[volume_type]))) if len(disks) > 1 and volume_type == 'disk': raise CommandException(_("Cannot create a volume of type disk with multiple disks")) if volume_type == 'auto': layout = kwargs.pop('layout', 'auto') if layout not in VOLUME_LAYOUTS: raise CommandException(_( "Invalid layout {0}. Should be one of: {1}".format(layout, list(VOLUME_LAYOUTS.keys())) )) else: if len(disks) < DISKS_PER_TYPE[VOLUME_LAYOUTS[layout]]: raise CommandException(_("Volume layout {0} requires at least {1} disks".format(layout, DISKS_PER_TYPE[VOLUME_LAYOUTS[layout]]))) context.submit_task('volume.create_auto', name, 'zfs', layout, disks, cache_disks, log_disks, encryption, password) else: ns.entity['id'] = name ns.entity['topology'] = {} ns.entity['topology']['data'] = [] if volume_type == 'disk': ns.entity['topology']['data'].append( {'type': 'disk', 'path': correct_disk_path(disks[0])}) else: ns.entity['topology']['data'].append({ 'type': volume_type, 'children': [{'type': 'disk', 'path': correct_disk_path(disk)} for disk in disks] }) ns.entity['encrypted'] = encryption if len(cache_disks) > 0: if 'cache' not in ns.entity: ns.entity['topology']['cache'] = [] for disk in cache_disks: ns.entity['topology']['cache'].append({ 'type': 'disk', 'path': correct_disk_path(disk) }) if len(log_disks) > 0: if 'log' not in ns.entity: ns.entity['topology']['log'] = [] if len(log_disks) > 1: ns.entity['topology']['log'].append({ 'type': 'mirror', 'children': [{'type': 'disk', 'path': correct_disk_path(disk)} for disk in log_disks] }) else: ns.entity['topology']['log'].append({ 'type': 'disk', 'path': correct_disk_path(log_disks[0]) }) context.submit_task( self.parent.create_task, ns.entity, password, callback=lambda s, t: post_save(ns, s, t))
def run(self, context, args, kwargs, opargs): entity = self.parent.entity if 'type' not in kwargs: raise CommandException(_( "Please specify a type of vdev, see 'help add_vdev' for more information" )) disks_per_type = DISKS_PER_TYPE.copy() disks_per_type.pop('auto', None) disks_per_type.update({ 'log': 1, 'cache': 1, 'spare': 1 }) typ = kwargs.pop('type') if disks_per_type.get(typ) is None: raise CommandException(_("Invalid vdev type")) if 'disks' not in kwargs: raise CommandException(_("Please specify one or more disks using the disks property")) else: disks = check_disks(context, to_list(kwargs.pop('disks')))[0] if len(disks) < disks_per_type[typ]: raise CommandException(_( "Vdev of type {0} requires at least {1} disks".format(typ, disks_per_type[typ]) )) if typ == 'mirror': entity['topology']['data'].append({ 'type': 'mirror', 'children': [{'type': 'disk', 'path': correct_disk_path(x)} for x in disks] }) if typ == 'disk': if len(disks) != 1: raise CommandException(_("Disk vdev consist of single disk")) entity['topology']['data'].append({ 'type': 'disk', 'path': correct_disk_path(disks[0]) }) if typ == 'cache': if 'cache' not in entity: entity['topology']['cache'] = [] entity['topology']['cache'].append({ 'type': 'disk', 'path': correct_disk_path(disks[0]) }) if typ in ('log', 'spare'): if len(disks) != 1: raise CommandException(_("Log or spare vdevs cannot be mirrored")) if 'log' not in entity: entity['topology'][typ] = [] entity['topology'][typ].append({ 'type': 'disk', 'path': correct_disk_path(disks[0]) }) if typ.startswith('raidz'): entity['topology']['data'].append({ 'type': typ, 'children': [{'type': 'disk', 'path': correct_disk_path(x)} for x in disks] }) self.parent.modified = True self.parent.save()
def run(self, context, args, kwargs, opargs): if not args and not kwargs: raise CommandException(_("create requires more arguments, see 'help create' for more information")) if len(args) > 1: raise CommandException(_("Wrong syntax for create, see 'help create' for more information")) # This magic below make either `create foo` or `create name=foo` work if len(args) == 1: # However, do not allow user to specify name as both implicit and explicit parameter as this suggests a mistake if 'name' in kwargs: raise CommandException(_("Both implicit and explicit 'name' parameters are specified.")) else: kwargs[self.parent.primary_key.name] = args.pop(0) if 'name' not in kwargs: raise CommandException(_('Please specify a name for your pool')) else: name = kwargs.pop('name') volume_type = kwargs.pop('type', 'auto') if volume_type not in VDEV_TYPES: raise CommandException(_( "Invalid volume type {0}. Should be one of: {1}".format(volume_type, VDEV_TYPES) )) if 'disks' not in kwargs: raise CommandException(_("Please specify one or more disks using the disks property")) else: disks = kwargs.pop('disks') if isinstance(disks, six.string_types): disks = [disks] if read_value(kwargs.pop('encryption', False), ValueType.BOOLEAN) is True: encryption = True password = kwargs.get('password', None) else: encryption = False password = None cache_disks = kwargs.pop('cache', []) log_disks = kwargs.pop('log', []) if cache_disks is None: cache_disks = [] if log_disks is None: log_disks = [] if isinstance(cache_disks, six.string_types): cache_disks = [cache_disks] if isinstance(log_disks, six.string_types): log_disks = [log_disks] ns = SingleItemNamespace(None, self.parent) ns.orig_entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity)) ns.entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity)) disks, cache_disks, log_disks = check_disks(context, disks, cache_disks, log_disks) if disks != 'auto': if len(disks) < DISKS_PER_TYPE[volume_type]: raise CommandException(_("Volume type {0} requires at least {1} disks".format( volume_type, DISKS_PER_TYPE[volume_type] ))) if len(disks) > 1 and volume_type == 'disk': raise CommandException(_("Cannot create a volume of type disk with multiple disks")) if volume_type == 'auto': layout = kwargs.pop('layout', 'auto') if layout not in VOLUME_LAYOUTS: raise CommandException(_( "Invalid layout {0}. Should be one of: {1}".format(layout, list(VOLUME_LAYOUTS.keys())) )) else: if disks != 'auto' and len(disks) < DISKS_PER_TYPE[VOLUME_LAYOUTS[layout]]: raise CommandException(_("Volume layout {0} requires at least {1} disks".format(layout, DISKS_PER_TYPE[VOLUME_LAYOUTS[layout]]))) context.submit_task('volume.create_auto', name, 'zfs', layout, disks, cache_disks, log_disks, encryption, password) else: ns.entity['id'] = name ns.entity['topology'] = {} ns.entity['topology']['data'] = [] if volume_type == 'disk': ns.entity['topology']['data'].append( {'type': 'disk', 'path': correct_disk_path(disks[0])}) else: ns.entity['topology']['data'].append({ 'type': volume_type, 'children': [{'type': 'disk', 'path': correct_disk_path(disk)} for disk in disks] }) ns.entity['encrypted'] = encryption if len(cache_disks) > 0: if 'cache' not in ns.entity: ns.entity['topology']['cache'] = [] for disk in cache_disks: ns.entity['topology']['cache'].append({ 'type': 'disk', 'path': correct_disk_path(disk) }) if len(log_disks) > 0: if 'log' not in ns.entity: ns.entity['topology']['log'] = [] if len(log_disks) > 1: ns.entity['topology']['log'].append({ 'type': 'mirror', 'children': [{'type': 'disk', 'path': correct_disk_path(disk)} for disk in log_disks] }) else: ns.entity['topology']['log'].append({ 'type': 'disk', 'path': correct_disk_path(log_disks[0]) }) context.submit_task( self.parent.create_task, ns.entity, password, callback=lambda s, t: post_save(ns, s, t))