class BondForm(Form): def __init__(self, initial, candidate_netdevs, all_netdev_names): self.candidate_netdevs = candidate_netdevs self.all_netdev_names = all_netdev_names super().__init__(initial) connect_signal(self.mode.widget, 'select', self._select_level) self._select_level(None, self.mode.value) name = StringField(_("Name:")) devices = MultiNetdevField(_("Devices: ")) mode = ChoiceField(_("Bond mode:"), choices=BondParameters.modes) xmit_hash_policy = ChoiceField(_("XMIT hash policy:"), choices=BondParameters.xmit_hash_policies) lacp_rate = ChoiceField(_("LACP rate:"), choices=BondParameters.lacp_rates) ok_label = _("Save") def _select_level(self, sender, new_value): self.xmit_hash_policy.enabled = ( new_value in BondParameters.supports_xmit_hash_policy) self.lacp_rate.enabled = (new_value in BondParameters.supports_lacp_rate) def validate_name(self): name = self.name.value if name in self.all_netdev_names: return _('There is already a network device named "{}"').format( name) if len(name) == 0: return _("Name cannot be empty") if len(name) > 16: return _("Name cannot be more than 16 characters long")
class RaidForm(CompoundDiskForm): def __init__(self, model, possible_components, initial, raid_names): self.raid_names = raid_names super().__init__(model, possible_components, initial) name = RaidnameField(_("Name:")) level = ChoiceField(_("RAID Level:"), choices=raidlevel_choices) devices = MultiDeviceField(_("Devices:")) size = ReadOnlyField(_("Size:")) def clean_name(self, val): if not val: raise ValueError("The name cannot be empty") if not re.match('md[0-9]+', val): val = 'md/' + val return val def validate_name(self): if self.name.value in self.raid_names: return _("There is already a RAID named '{}'").format( self.name.value) if self.name.value in ('/dev/md/.', '/dev/md/..'): return _(". and .. are not valid names for RAID devices") def validate_devices(self): log.debug('validate_devices %s %s', len(self.devices.value), self.level.value) active_device_count = len(self.devices.widget.active_devices) if active_device_count < self.level.value.min_devices: return _( 'RAID Level "{}" requires at least {} active devices').format( self.level.value.name, self.level.value.min_devices) return super().validate_devices()
class GuidedChoiceForm(SubForm): disk = ChoiceField(caption=NO_CAPTION, help=NO_HELP, choices=["x"]) use_lvm = BooleanField(_("Set up this disk as an LVM group"), help=NO_HELP) lvm_options = SubFormField(LVMOptionsForm, "", help=NO_HELP) def __init__(self, parent): super().__init__(parent) options = [] tables = [] initial = -1 for disk in parent.model.all_disks(): for obj, cells in summarize_device(disk): table = TablePile([TableRow(cells)]) tables.append(table) enabled = False if obj is disk and disk.size > 6 * (2**30): enabled = True if initial < 0: initial = len(options) options.append(Option((table, enabled, obj))) t0 = tables[0] for t in tables[1:]: t0.bind(t) self.disk.widget.options = options self.disk.widget.index = initial connect_signal(self.use_lvm.widget, 'change', self._toggle) self.lvm_options.enabled = self.use_lvm.value def _toggle(self, sender, val): self.lvm_options.enabled = val
class RaidForm(Form): def __init__(self, mountpoint_to_devpath_mapping, all_devices, initial, raid_names): self.mountpoint_to_devpath_mapping = mountpoint_to_devpath_mapping self.all_devices = all_devices self.raid_names = raid_names super().__init__(initial) connect_signal(self.fstype.widget, 'select', self.select_fstype) self.select_fstype(None, self.fstype.widget.value) name = StringField(_("Name:")) level = ChoiceField(_("RAID Level:"), choices=raidlevel_choices) devices = MultiDeviceField(_("Devices:")) size = ReadOnlyField(_("Size:")) def select_fstype(self, sender, fs): self.mount.enabled = fs.is_mounted fstype = FSTypeField(_("Format:")) mount = MountField(_("Mount:")) def clean_mount(self, val): if self.fstype.value.is_mounted: return val else: return None def clean_name(self, val): if not re.match('md[0-9]+', val): val = 'md/' + val return val def validate_name(self): if self.name.value in self.raid_names: return _("There is already a RAID named '{}'").format( self.name.value) def validate_devices(self): log.debug( 'validate_devices %s %s', len(self.devices.value), self.level.value) active_device_count = len(self.devices.widget.active_devices) if active_device_count < self.level.value.min_devices: return _( 'RAID Level "{}" requires at least {} active devices').format( self.level.value.name, self.level.value.min_devices) def validate_mount(self): mount = self.mount.value if mount is None: return # /usr/include/linux/limits.h:PATH_MAX if len(mount) > 4095: return _('Path exceeds PATH_MAX') dev = self.mountpoint_to_devpath_mapping.get(mount) if dev is not None: return _("{} is already mounted at {}").format(dev, mount)
class KeyboardForm(Form): cancel_label = _("Back") layout = ChoiceField(_("Layout:"), choices=["dummy"]) variant = ChoiceField(_("Variant:"), choices=["dummy"])
class IdentityForm(Form): realname = RealnameField(_("Your name:")) hostname = UsernameField( _("Your server's name:"), help=_("The name it uses when it talks to other computers.")) username = UsernameField(_("Pick a username:"******"Choose a password:"******"Confirm your password:"******"Import SSH identity:"), choices=[ (_("No"), True, None), (_("from Github"), True, "gh"), (_("from Launchpad"), True, "lp"), ], help=_("You can import your SSH keys from Github or Launchpad.")) import_username = UsernameField(_ssh_import_data[None]['caption']) def validate_realname(self): if len(self.realname.value) < 1: return _("Real name must not be empty.") if len(self.realname.value) > REALNAME_MAXLEN: return _("Realname too long, must be < ") + str(REALNAME_MAXLEN) def validate_hostname(self): if len(self.hostname.value) < 1: return _("Server name must not be empty") if len(self.hostname.value) > HOSTNAME_MAXLEN: return (_("Server name too long, must be < ") + str(HOSTNAME_MAXLEN)) if not re.match(r'[a-z_][a-z0-9_-]*', self.hostname.value): return _("Hostname must match NAME_REGEX, i.e. [a-z_][a-z0-9_-]*") def validate_username(self): if len(self.username.value) < 1: return _("Username missing") if len(self.username.value) > USERNAME_MAXLEN: return _("Username too long, must be < ") + str(USERNAME_MAXLEN) if not re.match(r'[a-z_][a-z0-9_-]*', self.username.value): return _("Username must match NAME_REGEX, i.e. [a-z_][a-z0-9_-]*") def validate_password(self): if len(self.password.value) < 1: return _("Password must be set") def validate_confirm_password(self): if self.password.value != self.confirm_password.value: return _("Passwords do not match") # validation of the import username does not read from # ssh_import_id.value because it is sometimes done from the # 'select' signal of the import id selector, which is called # before the import id selector's value has actually changed. so # the signal handler stuffs the value here before doing # validation (yes, this is a hack). ssh_import_id_value = None def validate_import_username(self): if self.ssh_import_id_value is None: return username = self.import_username.value if len(username) == 0: return _("This field must not be blank.") if len(username) > SSH_IMPORT_MAXLEN: return _("SSH id too long, must be < ") + str(SSH_IMPORT_MAXLEN) if self.ssh_import_id_value == 'lp': lp_regex = r"^[a-z0-9][a-z0-9\+\.\-]+$" if not re.match(lp_regex, self.import_username.value): return _("A Launchpad username must be at least two " "characters long and start with a letter or " "number. All letters must be lower-case. The " "characters +, - and . are also allowed after " "the first character." "") elif self.ssh_import_id_value == 'gh': if username.startswith('-') or ( username.endswith('-') or '--' in username or not re.match(r'^[a-zA-Z0-9\-]+$', username)): return _("A Github username may only contain alphanumeric " "characters or single hyphens, and cannot begin or " "end with a hyphen.")
class NetworkMethodForm(Form): ok_label = _("Save") method = ChoiceField("IPv{ip_version} Method: ", choices=network_choices)
class SSHForm(Form): install_server = BooleanField(_("Install OpenSSH server")) ssh_import_id = ChoiceField( _("Import SSH identity:"), choices=[ (_("No"), True, None), (_("from GitHub"), True, "gh"), (_("from Launchpad"), True, "lp"), ], help=_("You can import your SSH keys from GitHub or Launchpad.")) import_username = UsernameField(_ssh_import_data[None]['caption']) pwauth = BooleanField(_("Allow password authentication over SSH")) cancel_label = _("Back") def __init__(self, initial): super().__init__(initial=initial) connect_signal( self.install_server.widget, 'change', self._toggle_server) self._toggle_server(None, self.install_server.value) def _toggle_server(self, sender, new_value): if new_value: self.ssh_import_id.enabled = True self.import_username.enabled = self.ssh_import_id.value is not None self.pwauth.enabled = self.ssh_import_id.value is not None else: self.ssh_import_id.enabled = False self.import_username.enabled = False self.pwauth.enabled = False # validation of the import username does not read from # ssh_import_id.value because it is sometimes done from the # 'select' signal of the import id selector, which is called # before the import id selector's value has actually changed. so # the signal handler stuffs the value here before doing # validation (yes, this is a hack). ssh_import_id_value = None def validate_import_username(self): if self.ssh_import_id_value is None: return username = self.import_username.value if len(username) == 0: return _("This field must not be blank.") if len(username) > SSH_IMPORT_MAXLEN: return _("SSH id too long, must be < ") + str(SSH_IMPORT_MAXLEN) if self.ssh_import_id_value == 'lp': lp_regex = r"^[a-z0-9][a-z0-9\+\.\-]*$" if not re.match(lp_regex, self.import_username.value): return _("A Launchpad username must start with a letter or " "number. All letters must be lower-case. The " "characters +, - and . are also allowed after " "the first character.""") elif self.ssh_import_id_value == 'gh': if not re.match(r'^[a-zA-Z0-9\-]+$', username): return _("A GitHub username may only contain alphanumeric " "characters or single hyphens, and cannot begin or " "end with a hyphen.")