def print_headers(self): '''Print the headers for the displayed data. header[0] - The width of this column. header[1] and header[2] are trimmed to this size header[1] - The internationalized text for the left window header[2] - The internationalized text for the right window ''' self.left_header_string = [] self.right_header_string = [] for header in self.headers: left_header_str = header[1] right_header_str = header[2] # Trim the header to fit in the column width, # splitting columns with at least 1 space # Pad with extra space(s) to align the columns left_header_str = fit_text_truncate(left_header_str, header[0] - 1, just="left") self.left_header_string.append(left_header_str) right_header_str = fit_text_truncate(right_header_str, header[0] - 1, just="left") self.right_header_string.append(right_header_str) self.left_header_string = " ".join(self.left_header_string) self.right_header_string = " ".join(self.right_header_string) LOGGER.debug(self.left_header_string) self.add_text(self.left_header_string, 0, DiskWindow.SCROLL_PAD) right_win_offset = (self.win_width + DiskWindow.DEAD_ZONE + DiskWindow.SCROLL_PAD) self.add_text(self.right_header_string, 0, right_win_offset) self.window.hline(1, DiskWindow.SCROLL_PAD, curses.ACS_HLINE, textwidth(self.left_header_string)) self.window.hline(1, right_win_offset, curses.ACS_HLINE, textwidth(self.right_header_string)) self.no_ut_refresh()
def test_textwidth(self): ''' test textwidth() ''' # without tab self.assertEqual(textwidth(u'A\u00c0\u3042'), 1 + 1 + 2) self.assertEqual(textwidth(u'A\u00c0\u3042'.encode(get_encoding())), 1 + 1 + 2) # with tab self.assertEqual(textwidth(u'\tA\u00c0\u3042'), 4 + 1 + 1 + 2) self.assertEqual(textwidth(u'\tA\u00c0\u3042'.encode(get_encoding())), 4 + 1 + 1 + 2)
def _show(self): super(NSLDAPProfile, self)._show() if self.nameservice.nameservice != 'LDAP': raise SkipException if self.nameservice.dns: self.intro = \ _("Specify the name of the LDAP profile to be used to " "configure this system and the host name or IP address of " "the server that contains the profile.") self.title2 = _("Profile server host name or IP address:") else: self.intro = \ _("Specify the name of the LDAP profile to be used to " "configure this system and the IP address of the " "server that contains the profile.") self.title2 = _("Profile server IP address:") self.intro += _(" Enter the LDAP search base.") y_loc = self._paint_opening() maxtitlelen = max(textwidth(self.title), textwidth(self.title2), textwidth(self.title3)) aligned_x_loc = maxtitlelen + INDENT + 1 cols = self.win_size_x - aligned_x_loc self.center_win.add_text(self.title.rjust(maxtitlelen), y_loc, INDENT) area = WindowArea(1, cols, y_loc, aligned_x_loc) self.ldap_profile = EditField(area, window=self.center_win, text=self.nameservice.ldap_profile, error_win=self.main_win.error_line, validate=inc_validate_nowhite_nospecial) # in case of error, tell user what is being validated self.ldap_profile.validate_kwargs['etext'] = _('profile name') y_loc += 1 area = WindowArea(1, cols, y_loc, aligned_x_loc, scrollable_columns=NameService.HOSTNAME_SCREEN_LEN + 1) self.center_win.add_text(self.title2.rjust(maxtitlelen), y_loc, INDENT) # create edit field, validating for host name or IP address depending # on whether DNS was selected self.ldap_ip = EditField(area, window=self.center_win, text=self.nameservice.ldap_ip, error_win=self.main_win.error_line, validate=(incremental_validate_host if self.nameservice.dns else incremental_validate_ip)) # search base y_loc += 1 self.center_win.add_text(self.title3.rjust(maxtitlelen), y_loc, INDENT) area = WindowArea(1, cols, y_loc, aligned_x_loc, scrollable_columns=MAXDNLEN + 1) self.ldap_search_base = EditField(area, window=self.center_win, text=self.nameservice.ldap_search_base, error_win=self.main_win.error_line) self.main_win.do_update() self.center_win.activate_object(self.ldap_ip)
def _show(self): ''' called upon display of a screen ''' super(NSAltChooser, self)._show() y_loc = self._paint_opening() LOGGER.debug(self.nameservice) # allow the user to select an alternate name service area = WindowArea(x_loc=0, y_loc=y_loc, scrollable_lines=len(NameService.USER_CHOICE_LIST) + 1) area.lines = self.win_size_y - (y_loc + 1) area.columns = self.win_size_x self.scroll_region = ScrollWindow(area, window=self.center_win) # add the entries to the screen menu_item_max_width = self.win_size_x - NameService.SCROLL_SIZE for idx, nsn in enumerate(NameService.USER_CHOICE_LIST): y_loc += 1 hilite = min(menu_item_max_width, textwidth(nsn) + 1) win_area = WindowArea(1, hilite, idx, INDENT) ListItem(win_area, window=self.scroll_region, text=nsn, data_obj=nsn) # finalize positioning self.main_win.do_update() self.center_win.activate_object(self.scroll_region) self.scroll_region.activate_object_force(self.cur_nschoice_idx, force_to_top=True)
def _show(self): ''' called upon display of a screen ''' super(NSDNSChooser, self)._show() y_loc = self._paint_opening() LOGGER.debug(self.nameservice) # allow the user to choose DNS or not ynlist = [_('Configure DNS'), _('Do not configure DNS')] area = WindowArea(x_loc=0, y_loc=y_loc, scrollable_lines=len(ynlist) + 1) area.lines = self.win_size_y - (y_loc + 1) area.columns = self.win_size_x self.scroll_region_dns = ScrollWindow(area, window=self.center_win) # add the entries to the screen for idx, yon in enumerate(ynlist): win_area = WindowArea(1, textwidth(yon) + 1, idx, INDENT) ListItem(win_area, window=self.scroll_region_dns, text=yon, data_obj=yon) # finalize positioning self.main_win.do_update() self.center_win.activate_object(self.scroll_region_dns) self.scroll_region_dns.activate_object_force(self.cur_dnschoice_idx, force_to_top=True)
def get_cursor_loc(self): '''Cursor should be positioned at the end of the entered text''' win_loc = self.window.getbegyx() x_loc = win_loc[1] if not self.clear_on_enter: x_loc += min(textwidth(self.get_text()), self.area.columns) return (win_loc[0], x_loc)
def _show(self): super(NSNISAuto, self)._show() if self.nameservice.nameservice != 'NIS': raise SkipException y_loc = self._paint_opening() y_loc += self.center_win.add_paragraph(self.intro2, y_loc) y_loc += 1 ynlist = [_('Find one'), _('Specify one')] area = WindowArea(x_loc=0, y_loc=y_loc, scrollable_lines=len(ynlist) + 1) area.lines = self.win_size_y - (y_loc + 1) area.columns = self.win_size_x self.scroll_region = ScrollWindow(area, window=self.center_win) y_loc += 1 # blank line # add the entries to the screen for idx, yon in enumerate(ynlist): y_loc += 1 win_area = WindowArea(lines=1, columns=textwidth(yon) + 1, y_loc=idx, x_loc=INDENT) ListItem(win_area, window=self.scroll_region, text=yon, data_obj=yon) self.main_win.do_update() self.center_win.activate_object(self.scroll_region) self.scroll_region.activate_object_force(self.cur_nisnschoice_idx, force_to_top=True) y_loc += 1 # blank line self.center_win.add_paragraph(self.intro3, y_loc)
def add_text(self, text, start_y=0, start_x=0, max_chars=None, centered=False): '''Add a single line of text to the window 'text' must fit within the specified space, or it will be truncated ''' win_y, win_x = self.window.getmaxyx() terminalui.LOGGER.log(LOG_LEVEL_INPUT, "start_y=%d, start_x=%d, " "max_chars=%s, centered=%s, win_max_x=%s, " "win_max_y=%s", start_y, start_x, max_chars, centered, win_x, win_y) max_x = self.window.getmaxyx()[1] - self.border_size[1] start_x += self.border_size[1] abs_max_chars = max_x - start_x if max_chars is None: max_chars = abs_max_chars else: max_chars = min(max_chars, abs_max_chars) text = fit_text_truncate(text, max_chars) if centered: start_x = (max_x - textwidth(text)) / 2 + start_x if isinstance(text, unicode): text = text.encode(get_encoding()) terminalui.LOGGER.log(LOG_LEVEL_INPUT, "calling addstr with params start_y=%s," "start_x=%s, text=%s", start_y, start_x, text) self.window.addstr(start_y, start_x, text) self.no_ut_refresh()
def show_actions(self): '''Read through the actions dictionary, displaying all the actions descriptive text along the footer (along with a prefix linked to its associated keystroke) ''' self.footer.window.clear() if InnerWindow.USE_ESC: prefix = " Esc-" else: prefix = " F" strings = [] length = 0 action_format = "%s%i_%s" for key in sorted(self.actions.keys()): key_num = key - curses.KEY_F0 action_text = self.actions[key].text action_str = action_format % (prefix, key_num, action_text) strings.append(action_str) display_str = "".join(strings) max_len = self.footer.window.getmaxyx()[1] length = textwidth(display_str) if not InnerWindow.USE_ESC: length += (len(" Esc-") - len(" F")) * len(self.actions) if length > max_len: raise ValueError("Can't display footer actions - string too long") self.footer.window.addstr(display_str.encode(get_encoding())) self.footer.window.noutrefresh()
def _show(self): super(NSDNSServer, self)._show() # check dictionary of screens associated with name service selections if not self.nameservice.dns: raise SkipException y_loc = self._paint_opening() self.dns_server_list = [] find_1st_nonblank = None find_last_nonblank = -1 for i in range(NameServiceInfo.MAXDNSSERV): self.center_win.add_text(self.title, y_loc, INDENT) area = WindowArea(1, MAXIP, y_loc, textwidth(self.title) + INDENT + 1) y_loc += 1 if i < len(self.nameservice.dns_server) and \ self.nameservice.dns_server[i] is not None: text = self.nameservice.dns_server[i] else: text = '' # find first blank field or last non-blank field if text: find_last_nonblank = i elif find_1st_nonblank is None: find_1st_nonblank = i self.dns_server_list += [EditField(area, window=self.center_win, text=text, validate=incremental_validate_ip, error_win=self.main_win.error_line)] self.main_win.do_update() # position cursor on first blank or after last field if find_1st_nonblank is None: idx = min(find_last_nonblank + 1, NameServiceInfo.MAXDNSSERV - 1) else: idx = find_1st_nonblank self.center_win.activate_object(self.dns_server_list[idx])
def _show(self): super(NSLDAPProxyBindInfo, self)._show() if self.nameservice.nameservice != 'LDAP': raise SkipException if self.nameservice.ldap_proxy_bind == \ NameServiceInfo.LDAP_CHOICE_NO_PROXY_BIND: raise SkipException y_loc = self._paint_opening() y_loc += 1 # blank line self.center_win.add_text(self.title, y_loc, INDENT) y_loc += 1 # edit field on following line since it should be big cols = self.win_size_x - INDENT - 2 area = WindowArea(1, cols, y_loc, INDENT + 2, scrollable_columns=MAXDNLEN + 1) self.ldap_pb_dn = EditField(area, window=self.center_win, text=self.nameservice.ldap_pb_dn, error_win=self.main_win.error_line) # in case of error, tell user what is being validated self.ldap_pb_dn.validate_kwargs['etext'] = _('distinguished name') y_loc += 2 # blank line titlelen = textwidth(self.title2) self.center_win.add_text(self.title2, y_loc, NameService.SCROLL_SIZE) cols = self.win_size_x - titlelen - INDENT - 1 area = WindowArea(1, cols, y_loc, titlelen + INDENT + 1) self.ldap_pb_psw = EditField(area, window=self.center_win, text=self.nameservice.ldap_pb_psw, error_win=self.main_win.error_line, masked=True) self.main_win.do_update() self.center_win.activate_object(self.ldap_pb_dn)
def _show(self): ''' show DNS search list ''' super(NSDNSSearch, self)._show() # check dictionary of screens associated with name service selections if not self.nameservice.dns: raise SkipException y_loc = self._paint_opening() cols = min(MAXDOMAINLEN + 1, self.win_size_x - textwidth(self.title) - INDENT - 1) self.dns_search_list = [] find_1st_nonblank = None find_last_nonblank = -1 LOGGER.info(self.nameservice.dns_search) for i in range(MAXDNSSEARCH): self.center_win.add_text(text=self.title, start_y=y_loc, start_x=INDENT) area = WindowArea(1, cols, y_loc, textwidth(self.title) + INDENT + 1) y_loc += 1 if i < len(self.nameservice.dns_search) and \ self.nameservice.dns_search[i] is not None: text = self.nameservice.dns_search[i] else: text = '' # find first blank field or last non-blank field if text: find_last_nonblank = i elif find_1st_nonblank is None: find_1st_nonblank = i edf = EditField(area, window=self.center_win, text=text, validate=incremental_validate_domain, error_win=self.main_win.error_line) self.dns_search_list += [edf] self.main_win.do_update() # position cursor on first blank or after last field if find_1st_nonblank is None: idx = min(find_last_nonblank + 1, MAXDNSSEARCH - 1) else: idx = find_1st_nonblank self.center_win.activate_object(self.dns_search_list[idx])
def _show(self): ''' show domain ''' super(NSDomain, self)._show() if not _has_name_service(): raise SkipException if not self.nameservice.nameservice: raise SkipException y_loc = self._paint_opening() cols = min(MAXDOMAINLEN + 1, self.win_size_x - textwidth(self.title) - INDENT - 1) self.center_win.add_text(self.title, y_loc, INDENT) area = WindowArea(1, cols, y_loc, textwidth(self.title) + INDENT + 1, scrollable_columns=MAXDOMAINLEN + 1) self.domain = EditField(area, window=self.center_win, text=self.nameservice.domain, validate=incremental_validate_domain, error_win=self.main_win.error_line) self.main_win.do_update() self.center_win.activate_object(self.domain)
def _set_text(self, text, do_pad=True): '''Used internally to bypass the the public interface's numeric_pad functionality''' if do_pad: text = self._do_pad(text) if text is None: text = u"" self._reset_text() terminalui.LOGGER.log(LOG_LEVEL_INPUT, "_set_text textwidth=%s, columns=%s, text=%s", textwidth(text), self.area.columns, text) length_diff = textwidth(text) - self.area.columns if (length_diff >= 0): self.scroll(scroll_to_column=length_diff) for idx, char in enumerate(text): if length_diff > 0 and idx == length_diff: self.textbox.do_command(EditField.LARROW_CHAR) elif self.masked: self.textbox.do_command(self.masked_char) else: self.textbox.do_command(ord(char)) self.text.append(char) self.no_ut_refresh()
def handle_input(self, input_key): ''' For each keystroke, determine if it's a special character (and needs to end editing), printable character, or backspace. For special characters, send the return the done-editing code (CTRL-G), and store the special character for processing by parent window objects. If printable, append it to self.text, and try to validate. If validation fails, reject the character. ''' input_key = self.translate_input(input_key) if self.is_special_char(input_key): self.input_key = input_key return EditField.CMD_DONE_EDIT else: self.input_key = None if isprint(input_key) or (ismeta(input_key) and input_key < curses.KEY_MIN): # isprint: ASCII characters # ismeta and < curses.KEY_MIN: Remaining UTF-8 characters # > curses.KEY_MIN: Special key such as down arrow, backspace, etc. self.text.append(unichr(input_key)) if not self.is_valid(): if len(self.text) > 0: self.text.pop() return None self._modified = True if self.masked: input_key = self.masked_char elif input_key == curses.KEY_BACKSPACE: if len(self.text) > 0: del_char = self.text.pop() self._modified = True del_width = charwidth(del_char) if textwidth(self.get_text()) >= self.area.columns: self.scroll(columns=-del_width) self.is_valid() # Run self.is_valid here so that any functional side effects can # occur, but don't check the return value (removing a character # from a valid string should never be invalid, and even if it were, # it would not make sense to add the deleted character back in) return input_key
def _show(self): super(NSNISIP, self)._show() LOGGER.info("self.nameservice: %s" % self.nameservice) if self.nameservice.nameservice != 'NIS': raise SkipException if self.nameservice.nis_auto == NameServiceInfo.NIS_CHOICE_AUTO: raise SkipException if self.nameservice.dns: self.intro = \ _("Enter the host name or IP address of the name server. " "A host name must have at least 2 characters and can be " "alphanumeric and can contain hyphens. IP " "addresses must contain four sets of numbers separated " "by periods (for example, 129.200.9.1).") self.title = _("Server's host name or IP address:") else: self.intro = \ _("Enter the IP address of the name server. IP " "addresses must contain four sets of numbers separated " "by periods (for example, 129.200.9.1).") self.title = _("Server's IP address:") y_loc = self._paint_opening() self.center_win.add_text(self.title, y_loc, INDENT) aligned_x_loc = textwidth(self.title) + INDENT + 1 cols = self.win_size_x - aligned_x_loc area = WindowArea(1, cols, y_loc, aligned_x_loc) self.center_win.add_text(self.title, y_loc, INDENT) area = WindowArea(1, cols, y_loc, aligned_x_loc, scrollable_columns=NameService.HOSTNAME_SCREEN_LEN + 1) # create edit field, validating for host name or IP address depending # on whether DNS was selected self.nis_ip = EditField( area, window=self.center_win, text=self.nameservice.nis_ip, error_win=self.main_win.error_line, validate=(incremental_validate_host if self.nameservice.dns else incremental_validate_ip)) self.main_win.do_update() self.center_win.activate_object(self.nis_ip)
def display_help_topics(self): '''Display the help topics screen.''' self.main_win.set_header_text(self.help_header) y_loc = 1 y_loc += self.center_win.add_paragraph(self.intro, y_loc, 1, max_x=(self.win_size_x - 1)) y_loc += 1 area = WindowArea(scrollable_lines=(len(self.help_info) + 1), y_loc=y_loc, x_loc=0) terminalui.LOGGER.debug("lines=%s", len(self.help_dict)) area.lines = self.win_size_y - (y_loc + 1) area.columns = self.win_size_x self.scroll_region = ScrollWindow(area, window=self.center_win) # add the entries to the screen terminalui.LOGGER.debug("range=%s", len(self.help_info)) for idx, info in enumerate(self.help_info): # create ListItem for each help topic topic_format = info[1] topic_title = self.help_dict[info[0]][1] help_topic = topic_format % topic_title hilite = min(self.win_size_x, textwidth(help_topic) + 1) list_item = ListItem(WindowArea(1, hilite, idx, 0), window=self.scroll_region, text=help_topic) terminalui.LOGGER.debug("self.screen_last=%s", self.screen_last) if self.screen_last == info[0]: terminalui.LOGGER.debug("Set cur_help_idx = %s", idx) self.cur_help_idx = idx terminalui.LOGGER.debug("beg_y=%d, beg_x=%d", *list_item.window.getbegyx()) self.center_win.activate_object(self.scroll_region) self.scroll_region.activate_object(self.cur_help_idx)
def __init__(self, main_win, configure_network=False): global LOGGER if LOGGER is None: LOGGER = logging.getLogger(INSTALL_LOGGER_NAME + ".sysconfig") super(NetworkTypeScreen, self).__init__(main_win) self.hostfield_offset = textwidth(NetworkTypeScreen.HOSTNAME_TEXT) self.menu_item_desc_max = (self.win_size_x - NetworkTypeScreen.ITEM_DESC_OFFSET) self.net_type_dict = {} self.sys_info = None self.automatic = None self.manual = None self.none_option = None self.hostname = None self.nic_info = NetworkInfo() # find_links() returns tuple containing # * dictionary of configurable NICs # * number of NICs mandated from global zone. # # Taking that information into account, initialize type # of network configuration: # * FROMGZ - One or more link found, but all found links are # controlled from global zone. # * None - otherwise # # Set 'have_nic' flag to True if there is at least one configurable # link, otherwise set the flag to False. # self.ether_nics, self.fromgz_num = NetworkInfo.find_links() self.nic_info.type = NetworkInfo.NONE self.have_nic = True if len(self.ether_nics) == 0: self.have_nic = False if self.fromgz_num > 0: self.nic_info.type = NetworkInfo.FROMGZ self.configure_network = configure_network
def wait_for_disks(self): '''Block while waiting for libtd to finish. Catch F9 and quit if needed ''' self.main_win.actions.pop(curses.KEY_F2, None) self.main_win.actions.pop(curses.KEY_F6, None) self.main_win.actions.pop(curses.KEY_F3, None) self.main_win.show_actions() self.center_win.add_text(DiskScreen.DISK_SEEK_TEXT, 5, 1, self.win_size_x - 3) self.main_win.do_update() offset = textwidth(DiskScreen.DISK_SEEK_TEXT) + 2 spin_index = 0 self.center_win.window.timeout(250) while not self._target_discovery_completed: input_key = self.main_win.getch() if input_key == curses.KEY_F9: if self.confirm_quit(): raise QuitException self.center_win.add_text(DiskScreen.SPINNER[spin_index], 5, offset) self.center_win.no_ut_refresh() self.main_win.do_update() spin_index = (spin_index + 1) % len(DiskScreen.SPINNER) self.center_win.window.timeout(-1) self.center_win.clear() # check the result of target discovery if self._target_discovery_status is not InstallEngine.EXEC_SUCCESS: err_data = (errsvc.get_errors_by_mod_id(TARGET_DISCOVERY))[0] LOGGER.error("Target discovery failed") err = err_data.error_data[liberrsvc.ES_DATA_EXCEPTION] LOGGER.error(err) raise TargetDiscoveryError( ("Unexpected error (%s) during target " "discovery. See log for details.") % err)
def _show(self): super(NSLDAPProxyBindChooser, self)._show() # check dictionary of screens associated with name service selections if self.nameservice.nameservice != 'LDAP': raise SkipException y_loc = self._paint_opening() ynlist = [_('No'), _('Yes')] area = WindowArea(x_loc=0, y_loc=y_loc, scrollable_lines=len(ynlist) + 1) area.lines = self.win_size_y - (y_loc + 1) area.columns = self.win_size_x self.scroll_region = ScrollWindow(area, window=self.center_win) # add the entries to the screen for idx, yon in enumerate(ynlist): win_area = WindowArea(1, textwidth(yon) + 1, idx, INDENT) ListItem(win_area, window=self.scroll_region, text=yon, data_obj=yon) self.main_win.do_update() self.center_win.activate_object(self.scroll_region) self.scroll_region.activate_object_force(self.cur_pbchoice_idx, force_to_top=True)
def wait_for_disks(self): '''Block while waiting for libtd to finish. Catch F9 and quit if needed ''' self.main_win.actions.pop(curses.KEY_F2, None) self.main_win.actions.pop(curses.KEY_F6, None) self.main_win.actions.pop(curses.KEY_F3, None) self.main_win.show_actions() self.center_win.add_text(DiskScreen.DISK_SEEK_TEXT, 5, 1, self.win_size_x - 3) self.main_win.do_update() offset = textwidth(DiskScreen.DISK_SEEK_TEXT) + 2 spin_index = 0 self.center_win.window.timeout(250) while not self._target_discovery_completed: input_key = self.main_win.getch() if input_key == curses.KEY_F9: if self.confirm_quit(): raise QuitException self.center_win.add_text(DiskScreen.SPINNER[spin_index], 5, offset) self.center_win.no_ut_refresh() self.main_win.do_update() spin_index = (spin_index + 1) % len(DiskScreen.SPINNER) self.center_win.window.timeout(-1) self.center_win.clear() # check the result of target discovery if self._target_discovery_status is not InstallEngine.EXEC_SUCCESS: err_data = (errsvc.get_errors_by_mod_id(TARGET_DISCOVERY))[0] LOGGER.error("Target discovery failed") err = err_data.error_data[liberrsvc.ES_DATA_EXCEPTION] LOGGER.error(err) raise TargetDiscoveryError(("Unexpected error (%s) during target " "discovery. See log for details.") % err)
def __init__(self, main_win, show_user_account=None): global LOGGER if LOGGER is None: LOGGER = logging.getLogger(INSTALL_LOGGER_NAME + ".sysconfig") super(UserScreen, self).__init__(main_win) self.max_text_len = (self.win_size_x - UserScreen.PASS_SCREEN_LEN - UserScreen.ITEM_OFFSET) / 2 max_field = max(textwidth(UserScreen.ROOT_LABEL), textwidth(UserScreen.CONFIRM_LABEL), textwidth(UserScreen.NAME_LABEL), textwidth(UserScreen.USERNAME_LABEL), textwidth(UserScreen.USER_PASS_LABEL)) self.text_len = min(max_field + 1, self.max_text_len) self.list_area = WindowArea(1, self.text_len, 0, UserScreen.ITEM_OFFSET) scrollable_columns = UserInfo.MAX_PASS_LEN + 1 self.edit_area = WindowArea(1, UserScreen.PASS_SCREEN_LEN + 1, 0, self.text_len, scrollable_columns=scrollable_columns) self.username_edit_area = WindowArea( 1, UserScreen.PASS_SCREEN_LEN + 1, 0, self.text_len, scrollable_columns=UserInfo.MAX_USERNAME_LEN + 1) err_x_loc = 2 * self.max_text_len - self.text_len err_width = (self.text_len + UserScreen.PASS_SCREEN_LEN) self.error_area = WindowArea(1, err_width, 0, err_x_loc) self.root = None self.user = None self.root_pass_list = None self.root_pass_edit = None self.root_pass_err = None self.root_confirm_err = None self.root_confirm_list = None self.root_confirm_edit = None self.real_name_err = None self.real_name_list = None self.real_name_edit = None self.username_err = None self.username_list = None self.username_edit = None self.user_pass_err = None self.user_pass_list = None self.user_pass_edit = None self.user_confirm_err = None self.user_confirm_list = None self.user_confirm_edit = None # # If show_user_account is True, complete Users screen will be # displayed (root password edit fields as well as widgets related # to creating initial user account). Otherwise, widgets for initial # user account are hidden. # # If not initialized explicitly by caller (e.g. text installer), # show_user_account is set to True only if all conditions needed # for successful creation of user account are met. # # In particular, existence of parent of home ZFS dataset is checked, # since if parent of home ZFS dataset was missing, then # svc:/system/config-user smf service (responsible for configuring # root and user accounts) would fail to create user account. As # a result of that, the whole system would end up in maintenance mode. # self.show_user_account = show_user_account if self.show_user_account is None: self.show_user_account = self.home_zfs_parent_exists()
def _show(self): '''Display partition data for selected disk, and present the two choices ''' doc = InstallEngine.get_instance().doc disk = get_desired_target_disk(doc) if disk.label == "GPT": # this disk has GPT partitions, so skip this screen raise SkipException if self.x86_slice_mode: if disk.whole_disk: raise SkipException sol_partition = get_solaris_partition(doc) if sol_partition is None: # Must have a Solaris partition err_msg = "Critical error - no Solaris partition found" LOGGER.error(err_msg) raise ValueError(err_msg) LOGGER.debug("Working with the following partition:") LOGGER.debug(str(sol_partition)) # See if there are any slices in the partition all_slices = sol_partition.get_children(class_type=Slice) if not all_slices: LOGGER.info("No previous slices found") # Setting the in_zpool flag to indicate the whole # partition should be used. The needed underlying # slices will be created in the next step when # the in_zpool flag is detected. sol_partition.in_zpool = DEFAULT_ZPOOL_NAME raise SkipException LOGGER.debug("Preserved partition with existing slices, " "presenting option to install into a slice") self.disk = sol_partition else: self.disk = get_desired_target_disk(doc) LOGGER.debug("Working with the following disk:") LOGGER.debug(str(self.disk)) if self.disk.whole_disk: LOGGER.debug("disk.whole_disk=True, skip editing") raise SkipException if self.disk.is_boot_disk(): bootable = FDiskPart.BOOT_TEXT else: bootable = u"" disk_size_gb_str = locale.format("%.1f", self.disk.disk_prop.dev_size.get(Size.gb_units)) + LOCALIZED_GB type_bootable_str = FDiskPart.HEADER_TYPE_BOOTABLE % \ {"type": self.disk.disk_prop.dev_type, "bootable": bootable} header_text = self.header_text + disk_size_gb_str + \ type_bootable_str self.main_win.set_header_text(header_text) y_loc = 1 y_loc += self.center_win.add_paragraph(self.paragraph, start_y=y_loc) y_loc += 1 if self.is_x86 and not self.x86_slice_mode: all_parts = self.disk.get_children(class_type=Partition) else: all_parts = self.disk.get_children(class_type=Slice) found_parts = bool(all_parts) if found_parts: next_line = self.found else: next_line = self.proposed y_loc += self.center_win.add_paragraph(next_line, start_y=y_loc) y_loc += 1 disk_win_area = WindowArea(6, 70, y_loc, 0) self.disk_win = DiskWindow(disk_win_area, self.disk, target_controller=self.tc, window=self.center_win) y_loc += disk_win_area.lines y_loc += 3 whole_disk_width = textwidth(self.use_whole) + 3 cols = (self.win_size_x - whole_disk_width) / 2 whole_disk_item_area = WindowArea(1, whole_disk_width, y_loc, cols) self.whole_disk_item = ListItem(whole_disk_item_area, window=self.center_win, text=self.use_whole, centered=True) y_loc += 1 partial_width = textwidth(self.use_part) + 3 cols = (self.win_size_x - partial_width) / 2 partial_item_area = WindowArea(1, partial_width, y_loc, cols) self.partial_disk_item = ListItem(partial_item_area, window=self.center_win, text=self.use_part, centered=True) self.main_win.do_update() if self.use_whole_segment: self.center_win.activate_object(self.whole_disk_item) else: self.center_win.activate_object(self.partial_disk_item)
def wait_for_iscsi_disk(self): ''' Block while waiting for iSCSI discovery to finish ''' # check for the existence of an Iscsi object in the DOC. That object # is only added when the user selects 'iSCSI' as the discovery criteria self.iscsi = self.doc.volatile.get_first_child(name=ISCSI_LABEL, class_type=Iscsi) if not self.iscsi: return self.main_win.actions.pop(curses.KEY_F2, None) self.main_win.actions.pop(curses.KEY_F6, None) self.main_win.actions.pop(curses.KEY_F3, None) self.main_win.show_actions() self.center_win.add_text(DiskScreen.DISK_SEEK_TEXT, 5, 1, self.win_size_x - 3) self.main_win.do_update() offset = textwidth(DiskScreen.DISK_SEEK_TEXT) + 2 spin_index = 0 self.center_win.window.timeout(250) # there's an iscsi object in the DOC. Check for an existing iSCSI # target discovery checkpoint. If found, update the kwargs for # discovery to find all the information about the newest mapped LUN. # If not, register a new checkpoint. kwargs = {"search_type": "disk", "search_name": self.iscsi.ctd_list} for checkpoint in self.engine._checkpoints: if checkpoint.name == ISCSI_TARGET_DISCOVERY: checkpoint.kwargs = kwargs break else: # register a new iSCSI target discovery checkpoint self.engine.register_checkpoint(ISCSI_TARGET_DISCOVERY, "solaris_install/target/discovery", "TargetDiscovery", kwargs=kwargs, insert_before=TRANSFER_PREP) # run target discovery again against the iSCSI LUN self._iscsi_target_discovery_completed = False errsvc.clear_error_list() self.engine.execute_checkpoints(start_from=ISCSI_TARGET_DISCOVERY, pause_before=TRANSFER_PREP, callback=self._iscsi_td_callback) while not self._iscsi_target_discovery_completed: input_key = self.main_win.getch() if input_key == curses.KEY_F9: if self.confirm_quit(): raise QuitException self.center_win.add_text(DiskScreen.SPINNER[spin_index], 5, offset) self.center_win.no_ut_refresh() self.main_win.do_update() spin_index = (spin_index + 1) % len(DiskScreen.SPINNER) self.center_win.window.timeout(-1) self.center_win.clear() # check the result of target discovery if self._iscsi_target_discovery_status is not \ InstallEngine.EXEC_SUCCESS: err_data = errsvc.get_errors_by_mod_id(ISCSI_TARGET_DISCOVERY)[0] LOGGER.error("iSCSI target discovery failed") err = err_data.error_data[liberrsvc.ES_DATA_EXCEPTION] LOGGER.error(err) raise TargetDiscoveryError( "Unexpected error (%s) during iSCSI " "target discovery. See log for details." % err)
def _show(self): """ create the screen to collect user input """ # look in the DOC for an Iscsi object eng = InstallEngine.get_instance() iscsi_obj = eng.doc.volatile.get_children(name=ISCSI_LABEL, class_type=Iscsi) # If there's no iscsi object in the DOC, skip this screen if not iscsi_obj: raise SkipException else: self.iscsi_obj = iscsi_obj[0] LOGGER.debug("show Iscsi object: %s" % str(self.iscsi_obj)) y_loc = 1 self.center_win.add_paragraph(IscsiScreen.INTRO, start_y=y_loc) # look to see if DHCP is providing information if self.check_dhcp(): y_loc += 2 self.center_win.add_paragraph(IscsiScreen.FOUND_DHCP_LABEL, start_y=y_loc) # Target IP y_loc += 2 # Mark this field required self.center_win.window.addch(y_loc, 2, IscsiScreen.REQUIRED_MARK, self.center_win.color_theme.inactive) edit_start = textwidth(IscsiScreen.TARGET_IP_LABEL) + \ IscsiScreen.ITEM_OFFSET ip_area = WindowArea(y_loc=y_loc, x_loc=1, lines=1, columns=edit_start + IscsiScreen.MAX_IP_LEN + 1) self.target_ip_list = ListItem(ip_area, window=self.center_win, text=IscsiScreen.TARGET_IP_LABEL) self.target_ip_list.key_dict.update(self.add_keys) self.default_edit.x_loc = edit_start self.default_edit.columns = IscsiScreen.MAX_IP_LEN + 1 self.target_ip_edit = EditField(self.default_edit, window=self.target_ip_list, validate=incremental_validate_ip, error_win=self.main_win.error_line) self.target_ip_edit.key_dict.update(self.add_keys) if self.target_ip is not None: self.target_ip_edit.set_text(self.target_ip) # Target Port edit_start = ip_area.x_loc + \ textwidth(IscsiScreen.TARGET_PORT_LABEL) + \ IscsiScreen.ITEM_OFFSET port_area = WindowArea(y_loc=y_loc, x_loc=self.half_win_width + IscsiScreen.DEAD_ZONE, lines=1, columns=edit_start + IscsiScreen.MAX_PORT_LEN + 1) self.target_port_list = ListItem(port_area, window=self.center_win, text=IscsiScreen.TARGET_PORT_LABEL) self.target_port_list.key_dict.update(self.add_keys) self.right_edit.x_loc = edit_start self.right_edit.columns = IscsiScreen.MAX_PORT_LEN + 1 self.target_port_edit = EditField(self.right_edit, window=self.target_port_list, validate=incremental_validate_digits, error_win=self.main_win.error_line, text=Iscsi.ISCSI_DEFAULT_PORT) self.target_port_edit.key_dict.update(self.add_keys) if self.target_port is not None: self.target_port_edit.set_text(self.target_port) # Target LUN y_loc += 1 edit_start = textwidth(IscsiScreen.TARGET_LUN_LABEL) + \ IscsiScreen.ITEM_OFFSET lun_area = WindowArea(y_loc=y_loc, x_loc=1, lines=1, columns=edit_start + IscsiScreen.MAX_LUN_LEN + 1) self.target_lun_list = ListItem(lun_area, window=self.center_win, text=IscsiScreen.TARGET_LUN_LABEL) self.target_lun_list.key_dict.update(self.add_keys) self.default_edit.x_loc = edit_start self.default_edit.columns = IscsiScreen.MAX_LUN_LEN + 1 self.target_lun_edit = EditField(self.default_edit, window=self.target_lun_list, validate=incremental_validate_hex, error_win=self.main_win.error_line) self.target_lun_edit.key_dict.update(self.add_keys) if self.target_lun is not None: self.target_lun_edit.set_text(self.target_lun) # Target Name y_loc += 2 name_area = WindowArea(y_loc=y_loc, x_loc=1, lines=1, columns=self.full_win_width) name_area.y_loc = y_loc target_name_list = ListItem(name_area, window=self.center_win, text=IscsiScreen.TARGET_NAME_LABEL) self.name_edit.x_loc = textwidth(IscsiScreen.TARGET_NAME_LABEL) + \ IscsiScreen.ITEM_OFFSET self.name_edit.columns = self.full_win_width - \ textwidth(IscsiScreen.TARGET_NAME_LABEL) - \ IscsiScreen.ITEM_OFFSET self.target_name_edit = EditField(self.name_edit, window=target_name_list) if self.target_name is not None: self.target_name_edit.set_text(self.target_name) # Horizontal line y_loc += 1 self.center_win.window.hline(y_loc, 3, curses.ACS_HLINE, self.full_win_width) # Initiator Name y_loc += 1 if self.is_iscsiboot: # the system BIOS is configured for iSCSI boot. This means the # user will be unable to change the initiator-name. Display the # name, but don't allow it to be changed. text = "%s %s" % \ (IscsiScreen.INITIATOR_NAME_LABEL, self.initiator_name) self.center_win.add_text(text, start_y=y_loc, start_x=1) y_loc += 1 self.center_win.add_text(IscsiScreen.ISCSI_BOOT_LABEL, start_y=y_loc, start_x=1) else: # display the edit field as normal name_area.y_loc = y_loc initiator_name_list = ListItem(name_area, window=self.center_win, text=IscsiScreen.INITIATOR_NAME_LABEL) self.name_edit.x_loc = \ textwidth(IscsiScreen.INITIATOR_NAME_LABEL) + \ IscsiScreen.ITEM_OFFSET self.name_edit.columns = self.full_win_width - \ textwidth(IscsiScreen.INITIATOR_NAME_LABEL) - \ IscsiScreen.ITEM_OFFSET self.initiator_name_edit = EditField(self.name_edit, window=initiator_name_list, text=self.initiator_name) y_loc += 2 self.center_win.add_text(IscsiScreen.USE_CHAP_LABEL, y_loc, 1) # CHAP username y_loc += 1 edit_start = textwidth(IscsiScreen.CHAP_NAME_LABEL) + \ IscsiScreen.ITEM_OFFSET chapname_area = WindowArea(y_loc=y_loc, x_loc=15, lines=1, columns=edit_start + IscsiScreen.CHAP_LEN) chap_name_list = ListItem(chapname_area, window=self.center_win, text=IscsiScreen.CHAP_NAME_LABEL) self.chap_edit.x_loc = edit_start self.chap_edit.columns = IscsiScreen.CHAP_LEN + 1 self.chap_edit.scrollable_columns = IscsiScreen.MAX_NAME_LEN + 1 self.chap_name_edit = EditField(self.chap_edit, window=chap_name_list) if self.chap_name is not None: self.chap_name_edit.set_text(self.chap_name) # CHAP password y_loc += 1 edit_start = textwidth(IscsiScreen.CHAP_PASSWORD_LABEL) + \ IscsiScreen.ITEM_OFFSET chapname_area.y_loc = y_loc chap_password_list = ListItem(chapname_area, window=self.center_win, text=IscsiScreen.CHAP_PASSWORD_LABEL) self.chap_edit.x_loc = textwidth(IscsiScreen.CHAP_PASSWORD_LABEL) + \ IscsiScreen.ITEM_OFFSET self.chap_edit.scrollable_columns = None self.chap_password_edit = PasswordField(self.chap_edit, window=chap_password_list) if self.chap_password is not None: self.chap_password_edit.set_text(self.chap_password) # Legend y_loc += 2 self.center_win.window.addch(y_loc, 1, IscsiScreen.REQUIRED_MARK, self.center_win.color_theme.inactive) self.center_win.add_text(IscsiScreen.REQUIRED_FIELD_LABEL, y_loc, 1) self.main_win.do_update() self.center_win.activate_object()
def pop_up(self, header, question, left_btn_txt, right_btn_txt, color=None): '''Suspend the current screen, setting the header to 'header', presenting the 'question,' and providing two 'buttons'. Returns True if the RIGHT button is selected, False if the LEFT is selected. The LEFT button is initially selected. ''' # Hide the cursor, storing its previous state (visibility) so # it can be restored when finished. Then, move the cursor # to the default position (in case this terminal type does not support # hiding the cursor entirely) try: old_cursor_state = curses.curs_set(0) except curses.error: old_cursor_state = 2 cursor_loc = curses.getsyx() curses.setsyx(self.cursor_pos[0], self.cursor_pos[1]) # Add the header, a border, and the question to the window self.popup_win.window.border() header_x = (self.popup_win.area.columns - textwidth(header)) / 2 self.popup_win.add_text(header, 0, header_x) y_loc = 2 y_loc += self.popup_win.add_paragraph(question, y_loc, 2) y_loc += 2 # Set the background color based on the parameter given, or choose # a default based on the theme. Set the highlight_color by flipping # the A_REVERSE bit of the color if color is None: color = self.popup_win.color self.popup_win.set_color(color) highlight_color = color ^ curses.A_REVERSE # Create two "buttons" of equal size by finding the larger of the # two, and centering them max_len = max(textwidth(left_btn_txt), textwidth(right_btn_txt)) left_btn_txt = " [ %s ]" % left_btn_txt.center(max_len) right_btn_txt = " [ %s ]" % right_btn_txt.center(max_len) button_len = textwidth(left_btn_txt) + 1 win_size = self.popup_win.window.getmaxyx() left_area = WindowArea(1, button_len, y_loc, (win_size[1] / 2) - (button_len + 2)) left_button = ListItem(left_area, window=self.popup_win, text=left_btn_txt, color=color, highlight_color=highlight_color) right_area = WindowArea(1, button_len, y_loc, win_size[1] / 2 + 2) right_button = ListItem(right_area, window=self.popup_win, text=right_btn_txt, color=color, highlight_color=highlight_color) # Highlight the left button, clear any errors on the screen, # and display the pop up self.popup_win.activate_object(left_button) self.popup_win.no_ut_refresh() self.error_line.clear_err() self.do_update() self._active_win = self.popup_win # Loop until the user selects an option. input_key = None while input_key != curses.KEY_ENTER: input_key = self.getch() input_key = self.popup_win.process(input_key) if input_key == curses.KEY_LEFT: self.popup_win.activate_object(left_button) elif input_key == curses.KEY_RIGHT: self.popup_win.activate_object(right_button) self.do_update() self._active_win = self.central_area user_selected = (self.popup_win.get_active_object() is right_button) # Clear the pop up and restore the previous screen, including the # cursor position and visibility self.popup_win.clear() self.central_area.redrawwin() curses.setsyx(cursor_loc[0], cursor_loc[1]) try: curses.curs_set(old_cursor_state) except curses.error: pass self.do_update() return user_selected
def _show(self): '''Create a list of disks to choose from and create the window for displaying the partition/slice information from the selected disk ''' self.wait_for_disks() self.wait_for_iscsi_disk() discovered_target = self.doc.persistent.get_first_child( \ name=Target.DISCOVERED) LOGGER.debug(discovered_target) if discovered_target is None: self.center_win.add_paragraph(DiskScreen.NO_DISKS, 1, 1, max_x=(self.win_size_x - 1)) return self.disks = discovered_target.get_children(class_type=Disk) if not self.disks: self.center_win.add_paragraph(DiskScreen.NO_TARGETS, 1, 1, max_x=(self.win_size_x - 1)) return if self._image_size is None: try: self._image_size = Size(str(get_image_size(LOGGER)) + \ Size.mb_units) LOGGER.debug("Image_size: %s", self._image_size) except: # Unable to get the image size for some reason, allow # the target controller to use it's default size. LOGGER.debug("Unable to get image size") self._image_size = FALLBACK_IMAGE_SIZE # initialize the target controller so the min/max size for the # installation can be calculated. Explicitly do not want to select an # initial disk at this time in case none of the disks discovered is # usable. The target controller initialization needs to be done # everytime we show the disk selection screen so the desired target # node in the DOC can be re-populated with information from target # discovery. self.tc.initialize(image_size=self._image_size, no_initial_disk=True) # Go through all the disks found and find ones that have enough space # for installation. At the same time, see if any existing disk is the # boot disk. If a boot disk is found, move it to the front of the list num_usable_disks = 0 boot_disk = None for disk in self.disks: LOGGER.debug("size: %s, min: %s" % \ (disk.disk_prop.dev_size, self.minimum_size)) if disk.disk_prop.dev_size >= self.minimum_size: if disk.is_boot_disk(): boot_disk = disk num_usable_disks += 1 if boot_disk is not None: self.disks.remove(boot_disk) self.disks.insert(0, boot_disk) if num_usable_disks == 0: self.center_win.add_paragraph(DiskScreen.NO_DISKS, 1, 1, max_x=(self.win_size_x - 1)) return self.main_win.reset_actions() self.main_win.show_actions() y_loc = 1 self.center_win.add_text(DiskScreen.PARAGRAPH, y_loc, 1) y_loc += 1 self.center_win.add_text(self.size_line, y_loc, 1) y_loc += 2 self.center_win.add_text(self.disk_header_text, y_loc, 1) y_loc += 1 self.center_win.window.hline(y_loc, self.center_win.border_size[1] + 1, curses.ACS_HLINE, textwidth(self.disk_header_text)) y_loc += 1 disk_win_area = WindowArea(4, textwidth(self.disk_header_text) + 2, y_loc, 0) disk_win_area.scrollable_lines = len(self.disks) + 1 self.disk_win = ScrollWindow(disk_win_area, window=self.center_win) disk_item_area = WindowArea(1, disk_win_area.columns - 2, 0, 1) disk_index = 0 len_type = DiskScreen.DISK_HEADERS[0][0] - 1 len_size = DiskScreen.DISK_HEADERS[1][0] - 1 len_boot = DiskScreen.DISK_HEADERS[2][0] - 1 len_dev = DiskScreen.DISK_HEADERS[3][0] - 1 len_notes = DiskScreen.DISK_HEADERS[4][0] - 1 for disk in self.disks: disk_text_fields = [] dev_type = disk.disk_prop.dev_type if dev_type is not None: type_field = dev_type[:len_type] type_field = ljust_columns(type_field, len_type) else: type_field = " " * len_type disk_text_fields.append(type_field) disk_size = disk.disk_prop.dev_size.get(Size.gb_units) size_field = locale.format("%*.1f", (len_size, disk_size)) disk_text_fields.append(size_field) if disk.is_boot_disk(): bootable_field = "+".center(len_boot) else: bootable_field = " " * (len_boot) disk_text_fields.append(bootable_field) # # Information will be displayed in the device column with # the following priority: # # First priority is to display receptacle information, # if available. If receptacle information is displayed, # ctd name will not be displayed. # # If receptacle information is not available, the ctd name # will be displayed. # # Both items above can take as much as the 44 character wide # column as needed. # # If the receptacle/ctd name is less than 30 characters, # manufacturer information will be displayed in the left # over space. There won't be a column heading for the # manufacturer information. # device = disk.receptacle or disk.ctd added_device_field = False # is there enough room to display the manufacturer? if (len_dev - len(device)) >= DiskScreen.VENDOR_LEN: vendor = disk.disk_prop.dev_vendor if vendor is not None: dev_display_len = len_dev - DiskScreen.VENDOR_LEN device_field = ljust_columns(device, dev_display_len) disk_text_fields.append(device_field) vendor_field = vendor[:DiskScreen.VENDOR_LEN - 1] vendor_field = ljust_columns(vendor_field, DiskScreen.VENDOR_LEN - 1) disk_text_fields.append(vendor_field) added_device_field = True if not added_device_field: device_field = device[:len_dev] device_field = ljust_columns(device_field, len_dev) disk_text_fields.append(device_field) # display "<" or ">" if the disk is too big or too small selectable = True if disk.disk_prop.dev_size < self.minimum_size: selectable = False notes_field = DiskScreen.TOO_SMALL.center(len_notes) disk_text_fields.append(notes_field) elif disk.disk_prop.dev_size > Size(MAX_VTOC): notes_field = DiskScreen.TOO_BIG.center(len_notes) disk_text_fields.append(notes_field) # check the blocksize of the disk. If it's not 512 bytes and we # have an EFI firmware on x86, make the disk unselectable by the # user. See PSARC 2008/769 elif platform.processor() == "i386" and \ disk.geometry.blocksize != 512: firmware = SystemFirmware.get() if firmware.fw_name == "uefi64": selectable = False notes_field = DiskScreen.INVALID_DISK.center(len_notes) disk_text_fields.append(notes_field) LOGGER.debug( "marking disk %s unselectable as its " "blocksize is not 512 bytes on an UEFI " "firmware x86 system.", disk.ctd) disk_text = " ".join(disk_text_fields) disk_item_area.y_loc = disk_index disk_list_item = ListItem(disk_item_area, window=self.disk_win, text=disk_text, add_obj=selectable) disk_list_item.on_make_active = on_activate disk_list_item.on_make_active_kwargs["disk"] = disk disk_list_item.on_make_active_kwargs["disk_select"] = self disk_index += 1 self.disk_win.no_ut_refresh() y_loc += 7 disk_detail_area = WindowArea(6, 70, y_loc, 1) self.disk_detail = DiskWindow(disk_detail_area, self.disks[0], target_controller=self.tc, window=self.center_win) self.main_win.do_update() self.center_win.activate_object(self.disk_win) self.disk_win.activate_object(self.selected_disk_index, jump=True)
def _show(self): '''Create a list of disks to choose from and create the window for displaying the partition/slice information from the selected disk ''' self.wait_for_disks() discovered_target = self.doc.persistent.get_first_child( \ name=Target.DISCOVERED) LOGGER.debug(discovered_target) if discovered_target is None: self.center_win.add_paragraph(DiskScreen.NO_DISKS, 1, 1, max_x=(self.win_size_x - 1)) return self.disks = discovered_target.get_children(class_type=Disk) if not self.disks: self.center_win.add_paragraph(DiskScreen.NO_TARGETS, 1, 1, max_x=(self.win_size_x - 1)) return if self._image_size is None: try: self._image_size = Size(str(get_image_size(LOGGER)) + \ Size.mb_units) LOGGER.debug("Image_size: %s", self._image_size) except: # Unable to get the image size for some reason, allow # the target controller to use it's default size. LOGGER.debug("Unable to get image size") self._image_size = FALLBACK_IMAGE_SIZE # initialize the target controller so the min/max size for # the installation can be calculated. Explicitly do not # want to select an initial disk at this time in case # none of the disks discovered is usable. The target controller # initialization needs to be done everytime we show the disk selection # screen so the desired target node in the DOC can be re-populated # with information from target discovery. self.tc.initialize(image_size=self._image_size, no_initial_disk=True) # Go through all the disks found and find ones that have # enough space for installation. At the same time, see if any # existing disk is the boot disk. If a boot disk is found, move # it to the front of the list num_usable_disks = 0 boot_disk = None for disk in self.disks: LOGGER.debug("size: %s, min: %s" % \ (disk.disk_prop.dev_size, self.minimum_size)) if disk.disk_prop.dev_size >= self.minimum_size: if disk.is_boot_disk(): boot_disk = disk num_usable_disks += 1 if boot_disk is not None: self.disks.remove(boot_disk) self.disks.insert(0, boot_disk) if num_usable_disks == 0: self.center_win.add_paragraph(DiskScreen.NO_DISKS, 1, 1, max_x=(self.win_size_x - 1)) return self.main_win.reset_actions() self.main_win.show_actions() y_loc = 1 self.center_win.add_text(DiskScreen.PARAGRAPH, y_loc, 1) y_loc += 1 self.center_win.add_text(self.size_line, y_loc, 1) y_loc += 2 self.center_win.add_text(self.disk_header_text, y_loc, 1) y_loc += 1 self.center_win.window.hline(y_loc, self.center_win.border_size[1] + 1, curses.ACS_HLINE, textwidth(self.disk_header_text)) y_loc += 1 disk_win_area = WindowArea(4, textwidth(self.disk_header_text) + 2, y_loc, 0) disk_win_area.scrollable_lines = len(self.disks) + 1 self.disk_win = ScrollWindow(disk_win_area, window=self.center_win) disk_item_area = WindowArea(1, disk_win_area.columns - 2, 0, 1) disk_index = 0 len_type = DiskScreen.DISK_HEADERS[0][0] - 1 len_size = DiskScreen.DISK_HEADERS[1][0] - 1 len_boot = DiskScreen.DISK_HEADERS[2][0] - 1 len_dev = DiskScreen.DISK_HEADERS[3][0] - 1 len_mftr = DiskScreen.DISK_HEADERS[4][0] - 1 for disk in self.disks: disk_text_fields = [] if disk.disk_prop is None or disk.disk_prop.dev_type is None: continue type_field = disk.disk_prop.dev_type[:len_type] type_field = ljust_columns(type_field, len_type) disk_text_fields.append(type_field) disk_size = disk.disk_prop.dev_size.get(Size.gb_units) size_field = locale.format("%*.1f", (len_size, disk_size)) disk_text_fields.append(size_field) if disk.is_boot_disk(): bootable_field = "+".center(len_boot) else: bootable_field = " " * (len_boot) disk_text_fields.append(bootable_field) device_field = disk.ctd[:len_dev] device_field = ljust_columns(device_field, len_dev) disk_text_fields.append(device_field) vendor = disk.disk_prop.dev_vendor if vendor is not None: mftr_field = vendor[:len_mftr] mftr_field = ljust_columns(mftr_field, len_mftr) else: mftr_field = " " * len_mftr disk_text_fields.append(mftr_field) selectable = True if disk.disk_prop.dev_size < self.minimum_size: note_field = self.too_small_text selectable = False elif disk_size > Size(MAX_VTOC).get(Size.gb_units): note_field = self.too_big_warn else: note_field = "" disk_text_fields.append(note_field) disk_text = " ".join(disk_text_fields) disk_item_area.y_loc = disk_index disk_list_item = ListItem(disk_item_area, window=self.disk_win, text=disk_text, add_obj=selectable) disk_list_item.on_make_active = on_activate disk_list_item.on_make_active_kwargs["disk"] = disk disk_list_item.on_make_active_kwargs["disk_select"] = self disk_index += 1 self.disk_win.no_ut_refresh() y_loc += 7 disk_detail_area = WindowArea(6, 70, y_loc, 1) self.disk_detail = DiskWindow(disk_detail_area, self.disks[0], target_controller=self.tc, window=self.center_win) self.main_win.do_update() self.center_win.activate_object(self.disk_win) self.disk_win.activate_object(self.selected_disk_index)
def _show(self): '''Display partition data for selected disk, and present the two choices ''' doc = InstallEngine.get_instance().doc disk = get_desired_target_disk(doc) # verify the desired disk has a GPT partition table if disk.label == "VTOC": raise SkipException self.disk = disk LOGGER.debug("Working with the following disk:") LOGGER.debug(str(self.disk)) # set the header of the screen if self.disk.is_boot_disk(): bootable = GPTPart.BOOT_TEXT else: bootable = u"" disk_size_gb_str = locale.format("%.1f", self.disk.disk_prop.dev_size.get(Size.gb_units)) + LOCALIZED_GB type_bootable_str = GPTPart.HEADER_TYPE_BOOTABLE % \ {"type": self.disk.disk_prop.dev_type, "bootable": bootable} header_text = self.header_text + disk_size_gb_str + type_bootable_str self.main_win.set_header_text(header_text) if self.disk.whole_disk: LOGGER.debug("disk.whole_disk=True, skip editing") raise SkipException y_loc = 1 y_loc += self.center_win.add_paragraph(self.paragraph, start_y=y_loc) y_loc += 1 gpt_partitions = self.disk.get_children(class_type=GPTPartition) if gpt_partitions: next_line = self.found else: next_line = self.proposed y_loc += self.center_win.add_paragraph(next_line, start_y=y_loc) y_loc += 1 disk_win_area = WindowArea(6, 70, y_loc, 0) self.disk_win = DiskWindow(disk_win_area, self.disk, target_controller=self.tc, window=self.center_win) y_loc += disk_win_area.lines y_loc += 3 whole_disk_width = textwidth(self.use_whole) + 3 cols = (self.win_size_x - whole_disk_width) / 2 whole_disk_item_area = WindowArea(1, whole_disk_width, y_loc, cols) self.whole_disk_item = ListItem(whole_disk_item_area, window=self.center_win, text=self.use_whole, centered=True) y_loc += 1 partial_width = textwidth(self.use_part) + 3 cols = (self.win_size_x - partial_width) / 2 partial_item_area = WindowArea(1, partial_width, y_loc, cols) self.partial_disk_item = ListItem(partial_item_area, window=self.center_win, text=self.use_part, centered=True) self.main_win.do_update() if self.use_whole_segment: self.center_win.activate_object(self.whole_disk_item) else: self.center_win.activate_object(self.partial_disk_item)
def __init__(self, main_win, show_user_account=None): global LOGGER if LOGGER is None: LOGGER = logging.getLogger(INSTALL_LOGGER_NAME + ".sysconfig") super(UserScreen, self).__init__(main_win) self.max_text_len = (self.win_size_x - UserScreen.PASS_SCREEN_LEN - UserScreen.ITEM_OFFSET) / 2 max_field = max(textwidth(UserScreen.ROOT_LABEL), textwidth(UserScreen.CONFIRM_LABEL), textwidth(UserScreen.NAME_LABEL), textwidth(UserScreen.USERNAME_LABEL), textwidth(UserScreen.USER_PASS_LABEL)) self.text_len = min(max_field + 1, self.max_text_len) self.list_area = WindowArea(1, self.text_len, 0, UserScreen.ITEM_OFFSET) scrollable_columns = UserInfo.MAX_PASS_LEN + 1 self.edit_area = WindowArea(1, UserScreen.PASS_SCREEN_LEN + 1, 0, self.text_len, scrollable_columns=scrollable_columns) self.username_edit_area = WindowArea(1, UserScreen.PASS_SCREEN_LEN + 1, 0, self.text_len, scrollable_columns=UserInfo.MAX_USERNAME_LEN + 1) err_x_loc = 2 * self.max_text_len - self.text_len err_width = (self.text_len + UserScreen.PASS_SCREEN_LEN) self.error_area = WindowArea(1, err_width, 0, err_x_loc) self.root = None self.user = None self.root_pass_list = None self.root_pass_edit = None self.root_pass_err = None self.root_confirm_err = None self.root_confirm_list = None self.root_confirm_edit = None self.real_name_err = None self.real_name_list = None self.real_name_edit = None self.username_err = None self.username_list = None self.username_edit = None self.user_pass_err = None self.user_pass_list = None self.user_pass_edit = None self.user_confirm_err = None self.user_confirm_list = None self.user_confirm_edit = None # # If show_user_account is True, complete Users screen will be # displayed (root password edit fields as well as widgets related # to creating initial user account). Otherwise, widgets for initial # user account are hidden. # # If not initialized explicitly by caller (e.g. text installer), # show_user_account is set to True only if all conditions needed # for successful creation of user account are met. # # In particular, existence of parent of home ZFS dataset is checked, # since if parent of home ZFS dataset was missing, then # svc:/system/config-user smf service (responsible for configuring # root and user accounts) would fail to create user account. As # a result of that, the whole system would end up in maintenance mode. # self.show_user_account = show_user_account if self.show_user_account is None: self.show_user_account = self.home_zfs_parent_exists()
def _show(self): '''Display partition data for selected disk, and present the two choices ''' doc = InstallEngine.get_instance().doc if self.x86_slice_mode: disk = get_desired_target_disk(doc) if disk.whole_disk: raise SkipException sol_partition = get_solaris_partition(doc) LOGGER.debug("Working with the following partition:") LOGGER.debug(str(sol_partition)) if sol_partition is None: # Must have a Solaris partition err_msg = "Critical error - no Solaris partition found" LOGGER.error(err_msg) raise ValueError(err_msg) # See if there are any slices in the partition all_slices = sol_partition.get_children(class_type=Slice) if not all_slices: LOGGER.info("No previous slices found") # Setting the in_zpool flag to indicate the whole # partition should be used. The needed underlying # slices will be created in the next step when # the in_zpool flag is detected. sol_partition.in_zpool = ROOT_POOL raise SkipException LOGGER.debug("Preserved partition with existing slices, " "presenting option to install into a slice") self.disk = sol_partition else: self.disk = get_desired_target_disk(doc) LOGGER.debug("Working with the following disk:") LOGGER.debug(str(self.disk)) if self.disk.whole_disk: LOGGER.debug("disk.whole_disk=True, skip editting") raise SkipException if self.disk.is_boot_disk(): bootable = FDiskPart.BOOT_TEXT else: bootable = u"" disk_size_gb_str = locale.format("%.1f", self.disk.disk_prop.dev_size.get(Size.gb_units)) + LOCALIZED_GB type_bootable_str = FDiskPart.HEADER_TYPE_BOOTABLE % \ {"type": self.disk.disk_prop.dev_type, "bootable": bootable} header_text = self.header_text + disk_size_gb_str + \ type_bootable_str self.main_win.set_header_text(header_text) y_loc = 1 y_loc += self.center_win.add_paragraph(self.paragraph, start_y=y_loc) y_loc += 1 if self.is_x86 and not self.x86_slice_mode: all_parts = self.disk.get_children(class_type=Partition) else: all_parts = self.disk.get_children(class_type=Slice) found_parts = bool(all_parts) if found_parts: next_line = self.found else: next_line = self.proposed y_loc += self.center_win.add_paragraph(next_line, start_y=y_loc) y_loc += 1 disk_win_area = WindowArea(6, 70, y_loc, 0) self.disk_win = DiskWindow(disk_win_area, self.disk, target_controller=self.tc, window=self.center_win) y_loc += disk_win_area.lines y_loc += 3 whole_disk_width = textwidth(self.use_whole) + 3 cols = (self.win_size_x - whole_disk_width) / 2 whole_disk_item_area = WindowArea(1, whole_disk_width, y_loc, cols) self.whole_disk_item = ListItem(whole_disk_item_area, window=self.center_win, text=self.use_whole, centered=True) y_loc += 1 partial_width = textwidth(self.use_part) + 3 cols = (self.win_size_x - partial_width) / 2 partial_item_area = WindowArea(1, partial_width, y_loc, cols) self.partial_disk_item = ListItem(partial_item_area, window=self.center_win, text=self.use_part, centered=True) self.main_win.do_update() if self.use_whole_segment: self.center_win.activate_object(self.whole_disk_item) else: self.center_win.activate_object(self.partial_disk_item)