def __init__(self, controller, netdev_infos): self.controller = controller self.dev_name_to_table = {} self.cur_netdev_names = [] self.error = Text("", align='center') self.device_colspecs = { 0: ColSpec(rpad=1), 3: ColSpec(min_width=15), 4: ColSpec(can_shrink=True, rpad=1), } self.heading_table = TablePile([ TableRow([ Color.info_minor(Text(header)) for header in [ "", "NAME", "TYPE", "NOTES", "", ] ]) ], spacing=2, colspecs=self.device_colspecs) self.device_pile = Pile([self.heading_table]) for dev_info in netdev_infos: self.new_link(dev_info) self._create_bond_btn = menu_btn(_("Create bond"), on_press=self._create_bond) bp = button_pile([self._create_bond_btn]) bp.align = 'left' rows = [ self.device_pile, bp, ] self.buttons = button_pile([ done_btn("TBD", on_press=self.done), # See _route_watcher back_btn(_("Back"), on_press=self.cancel), ]) self.bottom = Pile([ ('pack', self.buttons), ]) self.error_showing = False super().__init__( screen(rows=rows, buttons=self.bottom, focus_buttons=True, excerpt=_(self.excerpt)))
def __init__(self, parent, device, ip_version): self.parent = parent self.device = device self.ip_version = ip_version self.method_form = NetworkMethodForm() self.method_form.method.caption = _( "IPv{v} Method: ").format(v=ip_version) manual_initial = {} cur_addresses = [] for addr in device.config.get('addresses', []): if addr_version(addr) == ip_version: cur_addresses.append(addr) if cur_addresses: method = 'manual' addr = ipaddress.ip_interface(cur_addresses[0]) ns = device.config.get('nameservers', {}) manual_initial = { 'subnet': str(addr.network), 'address': str(addr.ip), 'nameservers': ', '.join(ns.get('addresses', [])), 'searchdomains': ', '.join(ns.get('search', [])), } gw = device.config.get('gateway{v}'.format(v=ip_version)) if gw: manual_initial['gateway'] = str(gw) elif self.device.config.get('dhcp{v}'.format(v=ip_version)): method = 'dhcp' else: method = 'disable' self.method_form.method.value = method connect_signal( self.method_form.method.widget, 'select', self._select_method) log.debug("manual_initial %s", manual_initial) self.manual_form = NetworkConfigForm(ip_version, manual_initial) connect_signal(self.method_form, 'submit', self.done) connect_signal(self.manual_form, 'submit', self.done) connect_signal(self.method_form, 'cancel', self.cancel) connect_signal(self.manual_form, 'cancel', self.cancel) self.form_pile = Pile(self.method_form.as_rows()) self.bp = WidgetPlaceholder(self.method_form.buttons) self._select_method(None, method) widgets = [self.form_pile, Text(""), self.bp] super().__init__( "Edit {device} IPv{v} configuration".format( device=device.name, v=ip_version), widgets, 0, 0)
def make_body(self): self.error_text = Text("", align="center") self.pile = Pile([ ('pack', Text(_("Please press one of the following keys:"))), ('pack', Text("")), ('pack', Columns([Text(s, align="center") for s in self.step.symbols], dividechars=1)), ]) return self.pile
def __init__(self, parent, snap, cur_channel): self.parent = parent self.snap = snap self.channels = [] self.needs_focus = True self.description = Text(snap.description.replace('\r', '').strip()) self.lb_description = ListBox([self.description]) radio_group = [] for csi in snap.channels: notes = '-' if csi.confinement != "strict": notes = csi.confinement btn = StarRadioButton(radio_group, "{}:".format(csi.channel_name), state=csi.channel_name == cur_channel, on_state_change=self.state_change, user_data=SnapSelection( channel=csi.channel_name, is_classic=csi.confinement == "classic")) self.channels.append( Color.menu_button( TableRow([ btn, Text(csi.version), Text("({})".format(csi.revision)), Text(humanize_size(csi.size)), Text(notes), ]))) self.lb_channels = Table(self.channels, container_maker=NoTabCyclingListBox) title = Columns([ Text(snap.name), ('pack', Text(_("Publisher: {}").format(snap.publisher), align='right')), ], dividechars=1) contents = [ ('pack', title), ('pack', Text("")), ('pack', Text(snap.summary)), ('pack', Text("")), self.lb_description, # overwritten in render() ('pack', Text("")), ('weight', 1, self.lb_channels), ] self.description_index = contents.index(self.lb_description) self.pile = Pile(contents) super().__init__(self.pile)
def __init__(self, controller): self.controller = controller self.listwalker = SimpleFocusListWalker([]) self.listbox = ListBox(self.listwalker) self.linebox = MyLineBox(self.listbox) body = [ ('pack', Text("")), ('weight', 1, Padding.center_79(self.linebox)), ('pack', Text("")), ] self.pile = Pile(body) super().__init__(self.pile)
def __init__(self, parent, dev_info, ip_version): self.parent = parent self.dev_info = dev_info self.ip_version = ip_version self.method_form = NetworkMethodForm() self.method_form.method.caption = _( "IPv{v} Method: ").format(v=ip_version) manual_initial = {} dhcp_status = getattr(dev_info, 'dhcp' + str(ip_version)) static_config = getattr(dev_info, 'static' + str(ip_version)) if static_config.addresses: method = 'manual' addr = ipaddress.ip_interface(static_config.addresses[0]) manual_initial = { 'subnet': str(addr.network), 'address': str(addr.ip), 'nameservers': ', '.join(static_config.nameservers), 'searchdomains': ', '.join(static_config.searchdomains), } if static_config.gateway: manual_initial['gateway'] = static_config.gateway elif dhcp_status.enabled: method = 'dhcp' else: method = 'disable' self.method_form.method.value = method connect_signal( self.method_form.method.widget, 'select', self._select_method) log.debug("manual_initial %s", manual_initial) self.manual_form = NetworkConfigForm(ip_version, manual_initial) connect_signal(self.method_form, 'submit', self.done) connect_signal(self.manual_form, 'submit', self.done) connect_signal(self.method_form, 'cancel', self.cancel) connect_signal(self.manual_form, 'cancel', self.cancel) self.form_pile = Pile(self.method_form.as_rows()) self.bp = WidgetPlaceholder(self.method_form.buttons) self._select_method(None, method) widgets = [self.form_pile, Text(""), self.bp] super().__init__( "Edit {device} IPv{v} configuration".format( device=dev_info.name, v=ip_version), widgets, 0, 0)
def _build_model_inputs(self): netdevs = self.model.get_all_netdevs() ifname_width = 8 # default padding if netdevs: ifname_width += max(map(lambda dev: len(dev.name), netdevs)) if ifname_width > 20: ifname_width = 20 iface_menus = [] # Display each interface -- name in first column, then configured IPs # in the second. log.debug('interfaces: {}'.format(netdevs)) for dev in netdevs: col_1 = [] col_2 = [] col_1.append( menu_btn(label=dev.name, on_press=self.on_net_dev_press)) if dev.type == 'wlan': col_2.extend(_build_wifi_info(dev)) if len(dev.actual_ip_addresses) == 0 and (dev.type == 'eth' and not dev.is_connected): col_2.append(Color.info_primary(Text(_("Not connected")))) col_2.extend(_build_gateway_ip_info_for_version(dev, 4)) col_2.extend(_build_gateway_ip_info_for_version(dev, 6)) # Other device info (MAC, vendor/model, speed) template = '' if dev.hwaddr: template += '{} '.format(dev.hwaddr) # TODO is this to translate? if dev.is_bond_slave: template += '(Bonded) ' # TODO to check if this is affected by translations if not dev.vendor.lower().startswith('unknown'): vendor = textwrap.wrap(dev.vendor, 15)[0] template += '{} '.format(vendor) if not dev.model.lower().startswith('unknown'): model = textwrap.wrap(dev.model, 20)[0] template += '{} '.format(model) if dev.speed: template += '({})'.format(dev.speed) col_2.append(Color.info_minor(Text(template))) iface_menus.append( Columns([(ifname_width, Pile(col_1)), Pile(col_2)], 2)) return iface_menus
def __init__(self, parent, device, ip_version): self.parent = parent self.device = device self.ip_version = ip_version self.method_form = NetworkMethodForm() self.method_form.method.caption = _("IPv{ip_version} Method: ").format( ip_version=ip_version) manual_initial = {} if len(device.configured_ip_addresses_for_version(ip_version)) > 0: method = 'manual' addr = ipaddress.ip_interface( device.configured_ip_addresses_for_version(ip_version)[0]) manual_initial = { 'subnet': str(addr.network), 'address': str(addr.ip), 'nameservers': ', '.join(device.configured_nameservers), 'searchdomains': ', '.join(device.configured_searchdomains), } gw = device.configured_gateway_for_version(ip_version) if gw: manual_initial['gateway'] = str(gw) elif self.device.dhcp_for_version(ip_version): method = 'dhcp' else: method = 'disable' self.method_form.method.value = method connect_signal(self.method_form.method.widget, 'select', self._select_method) log.debug("manual_initial %s", manual_initial) self.manual_form = NetworkConfigForm(ip_version, manual_initial) connect_signal(self.method_form, 'submit', self.done) connect_signal(self.manual_form, 'submit', self.done) connect_signal(self.method_form, 'cancel', self.cancel) connect_signal(self.manual_form, 'cancel', self.cancel) self.form_pile = Pile(self.method_form.as_rows()) self.bp = WidgetPlaceholder(self.method_form.buttons) self._select_method(None, method) widgets = [self.form_pile, Text(""), self.bp] super().__init__( "Edit {device} IPv{ip_version} configuration".format( device=device.name, ip_version=ip_version), widgets, 0, 0)
def __init__(self, model, family, controller): self.model = model self.family = family self.controller = controller self.default_gateway_w = None self.gateway_options = Pile(self._build_default_routes()) body = [ Padding.center_79(Text("Please set the default gateway:")), Padding.line_break(""), Padding.center_79(self.gateway_options), Padding.line_break(""), Padding.fixed_10(self._build_buttons()) ] super().__init__(ListBox(body))
def __init__(self, parent, cur_index): self.parent = parent group = [] for i, option in enumerate(self.parent._options): if option[1]: btn = _PopUpButton(option[0], state=i==cur_index) connect_signal(btn, 'click', self.click, i) group.append(AttrWrap(btn, 'menu_button', 'menu_button focus')) else: btn = Text(" " + option[0]) group.append(AttrWrap(btn, 'info_minor')) pile = Pile(group) pile.set_focus(group[cur_index]) fill = Filler(pile, valign=TOP) super().__init__(LineBox(fill))
def __init__(self, mountpoint_to_devpath_mapping): opts = [] first_opt = None max_len = max(map(len, common_mountpoints)) for i, mnt in enumerate(common_mountpoints): devpath = mountpoint_to_devpath_mapping.get(mnt) if devpath is None: if first_opt is None: first_opt = i opts.append((mnt, True, mnt)) else: opts.append(("%-*s (%s)" % (max_len, mnt, devpath), False)) if first_opt is None: first_opt = len(opts) opts.append((_('other'), True, OTHER)) opts.append(('---', False)), opts.append((_('leave unmounted'), True, LEAVE_UNMOUNTED)) self._selector = Selector(opts, first_opt) connect_signal(self._selector, 'select', self._select_mount) self._other = _MountEditor() super().__init__(Pile([self._selector])) self._other_showing = False if self._selector.value is OTHER: # This can happen if all the common_mountpoints are in use. self._showhide_other(True)
def _build_buttons(self): done = done_btn(on_press=self.done) buttons = [ Color.button(done), ] return Pile(buttons)
def _build_model_inputs(self): items = [ Columns( [ ("weight", 0.2, Text("Ceph MON", align="right")), ("weight", 0.3, Color.string_input(self.ceph_mon)) ], dividechars=4 ), Columns( [ ("weight", 0.2, Text("Username", align="right")), ("weight", 0.3, Color.string_input(self.username)) ], dividechars=4 ), Columns( [ ("weight", 0.2, Text("Key", align="right")), ("weight", 0.3, Color.string_input(self.ceph_key)) ], dividechars=4 ) ] return Pile(items)
def __init__(self, mountpoints, ok_for_slash_boot): opts = [] first_opt = None for i, mnt in enumerate(common_mountpoints): if not ok_for_slash_boot and mnt == "/boot": opts.append((mnt, False)) elif mnt not in mountpoints: if first_opt is None: first_opt = i opts.append((mnt, True, mnt)) else: opts.append((mnt, False)) if first_opt is None: first_opt = len(opts) opts.append((_('other'), True, OTHER)) opts.append(('---', False)), opts.append((_('leave unmounted'), True, LEAVE_UNMOUNTED)) self._selector = Selector(opts, first_opt) connect_signal(self._selector, 'select', self._select_mount) self._other = _MountEditor() super().__init__(Pile([self._selector])) self._other_showing = False if self._selector.value is OTHER: # This can happen if all the common_mountpoints are in use. self._showhide_other(True)
def __init__(self, controller): self.controller = controller super().__init__(Pile([ ListBox([Text('')]), # need to have a listbox or something else "stretchy" here or urwid complains. ('pack', button_pile([ok_btn("OK", on_press=self.confirm)])), ('pack', Text("")), ], focus_item=1))
def _build_buttons(self): cancel = Color.button(cancel_btn(on_press=self.cancel)) done = Color.button(done_btn(on_press=self.done)) self.default_focus = done buttons = [done, cancel] return Pile(buttons, focus_item=done)
def __init__(self, parent, ssh_data, key_material, fingerprints): self.parent = parent self.ssh_data = ssh_data self.key_material = key_material ok = ok_btn(label=_("Yes"), on_press=self.ok) cancel = cancel_btn(label=_("No"), on_press=self.cancel) if len(fingerprints) > 1: title = _("Confirm SSH keys") header = _("Keys with the following fingerprints were fetched. " "Do you want to use them?") else: title = _("Confirm SSH key") header = _("A key with the following fingerprint was fetched. " "Do you want to use it?") fingerprints = Pile([Text(fingerprint) for fingerprint in fingerprints]) super().__init__( title, [ Text(header), Text(""), fingerprints, Text(""), button_pile([ok, cancel]), ], 2, 4)
def __init__(self, parent, device): self.parent = parent self.device = device title = _("Network interface {nic} WIFI configuration").format( nic=device.name) self.form = WLANForm() connect_signal(self.form, 'submit', self.done) connect_signal(self.form, 'cancel', self.cancel) ssid, psk = self.device.configured_ssid if ssid: self.form.ssid.value = ssid if psk: self.form.psk.value = psk self.ssid_row = self.form.ssid._table self.psk_row = self.form.psk._table self.ssid_row.bind(self.psk_row) self.inputs = Pile(self._build_iface_inputs()) self.error = Text("") widgets = [ self.inputs, Padding.center_79(Color.info_error(self.error)), self.form.buttons, ] super().__init__(title, widgets, 0, 0)
def _build_model_inputs(self): local_tpl = ("This device is registered to {realname}.") remote_tpl = ( "\n\nRemote access was enabled via authentication with SSO user" " <{username}>.\nPublic SSH keys were added to the device " "for remote access.\n\n{realname} can connect remotely to this " "device via SSH:") sl = [] user = self.model.user login_info = { 'realname': user.realname, 'username': user.username, } login_text = local_tpl.format(**login_info) login_text += remote_tpl.format(**login_info) ips = [] for dev in self.netdevs: for addr in dev.actual_global_ip_addresses: ips.append(addr) sl += [Text(login_text), Padding.line_break("")] for ip in ips: ssh_iface = " ssh %s@%s" % (user.username, ip) sl.append(Text(ssh_iface)) return Pile(sl)
def __init__(self, bottom_w, stretchy): self.bottom_w = bottom_w self.stretchy = stretchy self.listbox = ListBox([stretchy.stretchy_w]) def entry(i, w): if i == stretchy.stretchy_index: return ('weight', 1, self.listbox) else: return ('pack', w) # this Filler/Padding/LineBox/Filler/Padding construction # seems ridiculous but it works. self.top_w = urwid.Filler(urwid.Padding(urwid.LineBox( urwid.Filler(urwid.Padding(Pile( [entry(i, w) for (i, w) in enumerate(stretchy.widgets)], focus_item=stretchy.widgets[stretchy.focus_index]), left=2, right=2), top=1, bottom=1, height=('relative', 100)), title=stretchy.title), left=3, right=3), top=1, bottom=1, height=('relative', 100))
def _build_buttons(self): log.debug('lvm: _build_buttons') cancel = cancel_btn(on_press=self.cancel) done = done_btn(on_press=self.done) buttons = [Color.button(done), Color.button(cancel)] return Pile(buttons)
def _build_disk_selection(self): log.debug('lvm: _build_disk_selection') items = [Text("DISK SELECTION")] # lvm can use empty whole disks, or empty partitions avail_disks = self.model.get_empty_disk_names() avail_parts = self.model.get_empty_partition_names() avail_devs = sorted(avail_disks + avail_parts) if len(avail_devs) == 0: return items.append( [Color.info_minor(Text("No available disks."))]) for dname in avail_devs: device = self.model.get_disk(dname) if device.path != dname: # we've got a partition lvmdev = device.get_partition(dname) else: lvmdev = device disk_sz = humanize_size(lvmdev.size) disk_string = "{} {}, {}".format(dname, disk_sz, device.model) log.debug('lvm: disk_string={}'.format(disk_string)) self.selected_disks.append(CheckBox(disk_string)) items += self.selected_disks return Pile(items)
def _build_buttons(self): log.debug('bcache: _build_buttons') buttons = [ done_btn(on_press=self.done), cancel_btn(on_press=self.cancel), ] return Pile(buttons)
def as_row(self, view, longest_caption): if self.pile is not None: raise RuntimeError("do not call as_row more than once!") self.parent_view = view self._longest_caption = longest_caption self.pile = Pile([self._cols()]) return self.pile
def __init__(self, app): rows = [] keys = GLOBAL_KEYS if app.opts.run_on_serial: keys += SERIAL_GLOBAL_HELP_KEYS for key, text in keys: rows.append(TableRow([Text(_(key)), Text(_(text))])) if app.opts.dry_run: dro = _('(dry-run only)') for key, text in DRY_RUN_KEYS: rows.append(TableRow([Text(_(key)), Text(_(text) + ' ' + dro)])) table = TablePile(rows, spacing=2, colspecs={1: ColSpec(can_shrink=True)}) widgets = [ Pile([ ('pack', Text(rewrap(GLOBAL_KEY_HELP))), ('pack', Text("")), ('pack', table), ]), Text(""), button_pile([close_btn(app, self)]), ] super().__init__(_("Shortcut Keys"), widgets, 0, 2)
def __init__(self, model, controller): self.model = model self.controller = controller cancel = cancel_btn(_("Cancel"), on_press=self.cancel) disks = [] for disk in self.model.all_disks(): label = "%-42s %s" % (disk.label, humanize_size( disk.size).rjust(9)) if disk.size >= model.lower_size_limit: disk_btn = forward_btn(label, on_press=self.choose_disk, user_arg=disk) else: disk_btn = Color.info_minor(Text(" " + label)) disks.append(disk_btn) body = Pile([ ('pack', Text("")), ('pack', Padding.center_70(Text(_("Choose the disk to install to:")))), ('pack', Text("")), Padding.center_70(ListBox(disks)), ('pack', Text("")), ('pack', button_pile([cancel])), ('pack', Text("")), ]) super().__init__(body)
def __init__(self, model, controller, name): self.model = model self.controller = controller self.dev = self.model.get_netdev_by_name(name) self._build_widgets() super().__init__( Pile([ ('pack', Text("")), Padding.center_79(ListBox(self._build_body())), ('pack', Pile([ ('pack', Text("")), self._build_buttons(), ('pack', Text("")), ])), ]))
def __init__(self, parent, existing=None): self.parent = parent self.existing = existing raid_names = {raid.name for raid in parent.model.all_raids()} if existing is None: title = _('Create software RAID ("MD") disk') label = _('Create') x = 0 while True: name = 'md{}'.format(x) if name not in raid_names: break x += 1 initial = { 'devices': {}, 'name': name, 'level': raidlevels_by_value["raid1"], 'size': '-', } else: raid_names.remove(existing.name) title = _('Edit software RAID disk "{name}"').format( name=existing.name) label = _('Save') name = existing.name if name.startswith('md/'): name = name[3:] devices = {} for d in existing.devices: devices[d] = 'active' for d in existing.spare_devices: devices[d] = 'spare' initial = { 'devices': devices, 'name': name, 'level': raidlevels_by_value[existing.raidlevel] } possible_components = get_possible_components( self.parent.model, existing, initial['devices'], lambda dev: dev.ok_for_raid) form = self.form = RaidForm( self.parent.model, possible_components, initial, raid_names) form.devices.widget.set_supports_spares( initial['level'].supports_spares) form.buttons.base_widget[0].set_label(label) connect_signal(form.level.widget, 'select', self._select_level) connect_signal(form.devices.widget, 'change', self._change_devices) connect_signal(form, 'submit', self.done) connect_signal(form, 'cancel', self.cancel) rows = form.as_rows() super().__init__( title, [Pile(rows), Text(""), self.form.buttons], 0, 0)
class MultiNetdevChooser(WidgetWrap, WantsToKnowFormField): def __init__(self): self.pile = Pile([]) self.selected = set() self.box_to_device = {} super().__init__(self.pile) @property def value(self): return list(sorted(self.selected, key=lambda x: x.name)) @value.setter def value(self, value): self.selected = set(value) for checkbox, opt in self.pile.contents: checkbox.state = self.box_to_device[checkbox] in self.selected def set_bound_form_field(self, bff): contents = [] for d in bff.form.candidate_netdevs: box = CheckBox(d.name, on_state_change=self._state_change) self.box_to_device[box] = d contents.append((box, self.pile.options('pack'))) self.pile.contents[:] = contents def _state_change(self, sender, state): device = self.box_to_device[sender] if state: self.selected.add(device) else: self.selected.remove(device)
def show_overlay(self, overlay_widget, **kw): args = dict( align='center', width=('relative', 60), min_width=80, valign='middle', height='pack' ) PADDING = 3 # Don't expect callers to account for the padding if # they pass a fixed width. if 'width' in kw: if isinstance(kw['width'], int): kw['width'] += 2*PADDING args.update(kw) top = Pile([ ('pack', Text("")), Columns([ (PADDING, Text("")), overlay_widget, (PADDING, Text("")) ]), ('pack', Text("")), ]) self._w = Overlay(top_w=top, bottom_w=disabled(self._w), **args)