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)
Beispiel #2
0
 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)
Beispiel #3
0
 def test_charwidth(self):
     ''' test charwidth() '''
     # example of 1-column character (ASCII)
     self.assertEqual(charwidth(u'A'), 1)
     self.assertEqual(charwidth(u'A'.encode(get_encoding())), 1)
     # example of 1-column character (non-ASCII)
     self.assertEqual(charwidth(u'\u00c0'), 1)
     self.assertEqual(charwidth(u'\u00c0'.encode(get_encoding())), 1)
     # example of 2-column character
     self.assertEqual(charwidth(u'\u3042'), 2)
     self.assertEqual(charwidth(u'\u3042'.encode(get_encoding())), 2)
 def test_charwidth(self):
     ''' test charwidth() '''
     # example of 1-column character (ASCII)
     self.assertEqual(charwidth(u'A'), 1)
     self.assertEqual(charwidth(u'A'.encode(get_encoding())), 1)
     # example of 1-column character (non-ASCII)
     self.assertEqual(charwidth(u'\u00c0'), 1)
     self.assertEqual(charwidth(u'\u00c0'.encode(get_encoding())), 1)
     # example of 2-column character
     self.assertEqual(charwidth(u'\u3042'), 2)
     self.assertEqual(charwidth(u'\u3042'.encode(get_encoding())), 2)
Beispiel #5
0
def on_exit_edit(edit_field, disk_win=None):
    '''On exit, if the user has left the field blank, set the size to 0'''

    text = edit_field.get_text()
    if not text.strip():
        text = "0"
        enctext = text.encode(get_encoding())
        # encode per locale for floating point conversion
        edit_field.set_text("%.1f" % locale.atof(enctext))

    part_order = disk_win.ui_obj.get_parts_in_use().index(edit_field.data_obj)
    LOGGER.debug("Part being resized is at index: %s", part_order)

    new_size_text = text.strip()

    LOGGER.debug("Resizing text=%s", new_size_text)
    # encode user input per locale for floating point conversion
    enctext = new_size_text.encode(get_encoding())
    new_size = Size(str(locale.atof(enctext)) + Size.gb_units)
    old_size = edit_field.data_obj.size

    new_size_byte = new_size.get(Size.byte_units)
    old_size_byte = old_size.get(Size.byte_units)

    precision = Size(UI_PRECISION).get(Size.byte_units)

    if abs(new_size_byte - old_size_byte) > precision:
        parent_doc_obj = edit_field.data_obj.doc_obj.parent
        if isinstance(parent_doc_obj, Disk):
            if isinstance(edit_field.data_obj.doc_obj, Partition):
                resized_obj = parent_doc_obj.resize_partition(
                    edit_field.data_obj.doc_obj, new_size.get(Size.gb_units),
                    size_units=Size.gb_units)
            else:
                resized_obj = parent_doc_obj.resize_slice(
                    edit_field.data_obj.doc_obj, new_size.get(Size.gb_units),
                    size_units=Size.gb_units)
        else:
            resized_obj = parent_doc_obj.resize_slice(
                edit_field.data_obj.doc_obj, new_size.get(Size.gb_units),
                size_units=Size.gb_units)

        if isinstance(resized_obj, Partition):
            resized_obj.in_zpool = ROOT_POOL
        else:
            if resized_obj.in_zpool == ROOT_POOL:
                resized_obj.tag = V_ROOT

        if disk_win is not None:
            disk_win.set_disk_info(ui_obj=disk_win.ui_obj)
            disk_win.activate_index(part_order)

    dump_doc("After resize")
Beispiel #6
0
    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()
Beispiel #7
0
    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()
Beispiel #8
0
def exit_text_installer(logname=None, errcode=0):
    '''Teardown any existing iSCSI objects, Close out the logger and exit with
    errcode'''

    # get the Iscsi object from the DOC, if present.
    doc = InstallEngine.get_instance().doc
    iscsi = doc.volatile.get_first_child(name=ISCSI_LABEL, class_type=Iscsi)
    if iscsi:
        # The user exited prematurely, so try to tear down the Iscsi object
        try:
            LOGGER.debug("User has exited installer.  Tearing down "
                         "Iscsi object")
            iscsi.teardown()
        except CalledProcessError as err:
            # only print something to the screen if the errcode is nonzero
            if errcode != 0:
                print _("Unable to tear down iSCSI initiator:\n%s" % err)
            else:
                LOGGER.debug("Tearing down Iscsi object failed:  %s" % err)

    LOGGER.info("**** END ****")
    LOGGER.close()
    if logname is not None:
        print _("Exiting Text Installer. Log is available at:\n%s") % logname
    if isinstance(errcode, unicode):
        errcode = errcode.encode(get_encoding())
    sys.exit(errcode)
def exit_text_installer(logname=None, errcode=0):
    '''Close out the logger and exit with errcode'''
    LOGGER.info("**** END ****")
    LOGGER.close()
    if logname is not None:
        print _("Exiting Text Installer. Log is available at:\n%s") % logname
    if isinstance(errcode, unicode):
        errcode = errcode.encode(get_encoding())
    sys.exit(errcode)
def exit_text_installer(logname=None, errcode=0):
    '''Close out the logger and exit with errcode'''
    LOGGER.info("**** END ****")
    LOGGER.close()
    if logname is not None:
        print _("Exiting Text Installer. Log is available at:\n%s") % logname
    if isinstance(errcode, unicode):
        errcode = errcode.encode(get_encoding())
    sys.exit(errcode)
Beispiel #11
0
def _exit(logname, errcode=0):
    '''Close out the logger and exit with errcode'''
    LOGGER.info("**** END ****")
    # LOGGER.close() # LOGGER.close() is broken - CR 7012566
    print _("Exiting System Configuration Tool. Log is available at:\n"
            "%s") % logname
    if isinstance(errcode, unicode):
        # pylint: disable-msg=E1103
        errcode = errcode.encode(get_encoding())
    sys.exit(errcode)
def _exit(logname, errcode=0):
    '''Close out the logger and exit with errcode'''
    LOGGER.info("**** END ****")
    # LOGGER.close() # LOGGER.close() is broken - CR 7012566
    print _("Exiting System Configuration Tool. Log is available at:\n"
            "%s") % logname
    if isinstance(errcode, unicode):
        # pylint: disable-msg=E1103
        errcode = errcode.encode(get_encoding())
    sys.exit(errcode)
Beispiel #13
0
def decimal_valid(edit_field, disk_win=None):
    '''Check text to see if it is a decimal number of precision no
    greater than the tenths place.

    '''
    text = edit_field.get_text().lstrip()
    radixchar = locale.localeconv()['decimal_point']
    if text.endswith(" "):
        raise UIMessage(_('Only the digits 0-9 and %s are valid.') % radixchar)
    vals = text.split(radixchar)
    if len(vals) > 2:
        raise UIMessage(_('A number can only have one %s') % radixchar)
    try:
        if len(vals[0]) > 0:
            int(vals[0])
        if len(vals) > 1 and len(vals[1]) > 0:
            int(vals[1])
    except ValueError:
        raise UIMessage(_('Only the digits 0-9 and %s are valid.') % radixchar)
    if len(vals) > 1 and len(vals[1]) > 1:
        raise UIMessage(_("Size can be specified to only one decimal place."))
    if disk_win is not None:
        text = text.rstrip(radixchar)
        if not text:
            text = "0"

        # encode user input per locale for floating point conversion
        text = text.encode(get_encoding())
        new_size = Size(str(locale.atof(text)) + Size.gb_units)
        max_size = edit_field.data_obj.get_max_size()

        # When comparing sizes, check only to the first decimal place,
        # as that is all the user sees. (Rounding errors that could
        # cause the partition/slice layout to be invalid get cleaned up
        # prior to target instantiation)
        new_size_rounded = round(new_size.get(Size.gb_units), 1)
        max_size_rounded = round(max_size.get(Size.gb_units), 1)
        if new_size_rounded > max_size_rounded:
            locale_new_size = locale.format("%.1f", new_size_rounded)
            locale_max_size = locale.format("%.1f", max_size_rounded)
            msg = _("The new size ") + locale_new_size + \
                _(" is greater than the available space ") + locale_max_size
            raise UIMessage(msg)
    return True
Beispiel #14
0
def parse_unconfig_args(parser, args):
    # Now parse options specific to the subcommand
    (options, sub_cmd) = parser.parse_args(args)

    options.alt_root = os.getenv(ALT_ROOT_ENV_VAR)

    # If operating on alternate root, verify given path.
    if options.alt_root:
        if not os.access(options.alt_root, os.W_OK):
            print _("Root filesystem provided for the non-global zone"
                    " does not exist")
            sys.exit(SU_FATAL_ERR)

    #
    # unconfiguration/reconfiguration is not permitted in ROZR non-global
    # zone unless such zone is booted in writable mode.
    # When operating in alternate root mode, skip that check, since in that
    # case ROZR zone would be manipulated from global zone. That along with
    # previous check guarantees writable access.
    #
    if not options.alt_root and _in_rozr_zone():
        print _("Root filesystem mounted read-only, '%s' operation"
                 " not permitted." % sub_cmd[0])
        print _("The likely cause is that sysconfig(1m) was invoked"
                 " in ROZR non-global zone.")
        print _("In that case, see mwac(5) and zonecfg(1m) man pages"
                 " for additional information.")

        sys.exit(SU_FATAL_ERR)

    # At this time, it is believed that there is no point in allowing
    # the prompt to be displayed in the alternate root case. Since there is no
    # use case, let's not explode our test matrix.
    if options.alt_root and options.shutdown:
        parser.error("Invalid to specify -s option with an alternate root")

    # If no grouping is specified, that implies a system level unconfiguration.
    # Confirm with the user that this is what they want for security reasons.
    if not options.grouping:
        if sub_cmd[0] == CONFIGURE:
            print _("This program will re-configure your system.")
        else:
            print _("This program will unconfigure your system.")
            print _("The system will be reverted to a \"pristine\" state.")
            print _("It will not have a name or know about other systems"
                    " or networks.")

        msg = _("Do you want to continue (y/[n])? ")
        confirm = raw_input(msg.encode(get_encoding()))
        if confirm.lower() != "y":
            sys.exit(SU_OK)

        # They have confirmed, set grouping to system.
        options.grouping = [SYSTEM]

    # Formulate the comma separated string into a list
    for grp in options.grouping:
        if COMMA in grp:
            options.grouping.extend(map(str.strip, grp.split(",")))
            options.grouping.remove(grp)
            break

    # If the user specifies a list of groups and one of them is system set
    # to just system since it is a superset of all other groupings.
    if len(options.grouping) > 1 and SYSTEM in options.grouping:
        options.grouping = [SYSTEM]

    if options.alt_root:
        svccfg_repository = os.path.join(options.alt_root, SMF_REPOSITORY)
        os.environ["SVCCFG_REPOSITORY"] = svccfg_repository

    # Check that the functional groups requested are valid
    valid_group_check(options.grouping, sub_cmd, parser)

    # If not operating on the alternate root, we can and must check to make
    # sure that the grouping specified has services of that grouping on the
    # image.
    if not options.alt_root and SYSTEM not in options.grouping:
        # Check that there exist unconfigurable services with the specified
        # grouping on the machine.
        cmd = [SVCPROP, "-p", "unconfigure/exec", "*"]
        p_ret = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.DEVNULL,
                                 check_result=Popen.ANY)
        unconfigurable_svcs = p_ret.stdout.split("\n")
        for opt_grp in options.grouping:
            found = False
            for svcs in unconfigurable_svcs:
                if svcs:
                    svc = svcs.split("/:properties")[0]
                    cmd = [SVCPROP, "-p", "sysconfig/group", svc]
                    p_ret = Popen.check_call(cmd, stdout=Popen.STORE,
                        stderr=Popen.DEVNULL, check_result=Popen.ANY)
                    grping = p_ret.stdout.strip()
                    if grping == opt_grp:
                        found = True

            if not found:
                print _("There are no services on the system with grouping "
                        "of %s" % opt_grp)
                sys.exit(1)

    #
    # The user specified a profile file or a directory with profiles to use
    # on the configure. Verify that supplied profiles contain .xml suffix
    # (otherwise smf(5) will not apply them) and syntactically
    # validate them. Then copy them to the temporary location,
    # /etc/svc/profile/sc/ directory. The unconfig milestone will move
    # them to the site area when it runs. We can't put profiles
    # to site directory right now because they may end up applied before
    # unconfiguration runs and then removed during unconfiguration.
    #
    if sub_cmd[0] == CONFIGURE and options.profile:
        # Verify that supplied path (file or directory) exists.
        if not os.path.exists(options.profile):
            parser.error("%s does not exist." % options.profile)

        # Remove all of /etc/svc/profile/sc
        custom_profile_dir = CUSTOM_PROFILE_DIR
        if options.alt_root:
            custom_profile_dir = os.path.join(options.alt_root,
                                              custom_profile_dir)
        else:
            custom_profile_dir = os.path.join("/", custom_profile_dir)

        if os.path.exists(custom_profile_dir):
            for root, dirs, files in os.walk(custom_profile_dir):
                for profile_file in files:
                    os.unlink(os.path.join(root, profile_file))
        else:
            os.mkdir(custom_profile_dir)

        if os.path.isdir(options.profile):
            #
            # Profile directory is specified.
            # Directory has to contain at least one profile. Start with
            # assumption that given directory does not contain any
            # profile.
            #
            profile_dir_is_empty = True

            # Validate profiles - all supplied profiles have to validate.
            for root, dirs, files in os.walk(options.profile):
                for pfile in files:
                    profile_file = os.path.join(root, pfile)
                    # Abort if profile is invalid.
                    if not profile_is_valid(profile_file):
                        sys.exit(SU_FATAL_ERR)

                    # Place profile in the temporary site profile area.
                    orig_umask = os.umask(0377) 
                    shutil.copyfile(profile_file,
                                    os.path.join(custom_profile_dir, pfile))
                    os.umask(orig_umask) 
                    profile_dir_is_empty = False

            # If no profile was found in given directory, abort.
            if profile_dir_is_empty:
                print _("Directory %s does not contain any profile."
                         % options.profile)
                sys.exit(SU_FATAL_ERR)

        else:
            # Profile is a file - validate it.
            if not profile_is_valid(options.profile):
                sys.exit(SU_FATAL_ERR)

            # Place profile in the temporary site profile area.
            orig_umask = os.umask(0377)
            shutil.copyfile(options.profile, os.path.join(custom_profile_dir,
                            os.path.basename(options.profile)))
            os.umask(orig_umask) 

    #
    # if there is a request to re-configure system in interactive way
    # (using SCI tool), check if we are on console, since this is where SCI
    # tool will be lauched. If we are not on console, let user confirm this
    # is really what one wants to do.
    #
    if sub_cmd[0] == CONFIGURE and not options.profile \
        and not options.alt_root:

        # For now, sysconfig should halt when the user runs sysconfig configure
        # after running sysconfig unconfigure. When the functionality that
        # enables the unconfiguration of individual groupings is implemented,
        # this may need to be revisited. Currently, system is the only group
        # that can be configured/unconfigured.
        cmd = [SVCPROP, "-c", "-p", "sysconfig/unconfigure",
               "milestone/unconfig"]
        p_ret = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.DEVNULL,
                             check_result=Popen.ANY)

        unconfigure_has_occurred = p_ret.stdout.strip()

        cmd = [SVCPROP, "-c", "-p", "sysconfig/configure", "milestone/config"]
        p_ret = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.DEVNULL,
                             check_result=Popen.ANY)

        config_has_occurred = p_ret.stdout.strip()

        if unconfigure_has_occurred == 'true' \
            and config_has_occurred == 'false':
            print _("Error: system has been unconfigured. Reboot to invoke "
               "the SCI Tool and configure the system.")
            sys.exit(SU_FATAL_ERR)

        print _("Interactive configuration requested.")
        print _("System Configuration Interactive (SCI) tool will be" +
            " launched on console.")

        cmd = [TTY]
        try:
            p = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.PIPE,
                                 check_result=(Popen.STDERR_EMPTY, 0))
        except CalledProcessError as err:
            print err.popen.stderr
            # if tty fails, we may not be able to interact with user.
            # In this case, skip the confirmation prompt.
        else:
            terminal_device = p.stdout.strip()

            if terminal_device != CONSOLE:
                print _("Since you are currently not logged on console,\n"
                         "you may not be able to navigate SCI tool.")
                msg = _("Would you like to proceed with re-configuration "
                        "(y/[n])? ")
                confirm = raw_input(msg.encode(get_encoding()))
                if confirm.lower() != "y":
                    sys.exit(SU_OK)

    return (options, sub_cmd)
def parse_unconfig_args(parser, args):
    # Now parse options specific to the subcommand
    (options, sub_cmd) = parser.parse_args(args)

    options.alt_root = os.getenv(ALT_ROOT_ENV_VAR)

    # If operating on alternate root, verify given path.
    if options.alt_root:
        if not os.access(options.alt_root, os.W_OK):
            print _("Root filesystem provided for the non-global zone"
                    " does not exist")
            sys.exit(SU_FATAL_ERR)

    #
    # unconfiguration/reconfiguration is not permitted in ROZR non-global
    # zone unless such zone is booted in writable mode.
    # When operating in alternate root mode, skip that check, since in that
    # case ROZR zone would be manipulated from global zone. That along with
    # previous check guarantees writable access.
    #
    if not options.alt_root and _in_rozr_zone():
        print _("Root filesystem mounted read-only, '%s' operation"
                 " not permitted." % sub_cmd[0])
        print _("The likely cause is that sysconfig(1m) was invoked"
                 " in ROZR non-global zone.")
        print _("In that case, see mwac(5) and zonecfg(1m) man pages"
                 " for additional information.")

        sys.exit(SU_FATAL_ERR)

    # At this time, it is believed that there is no point in allowing
    # the prompt to be displayed in the alternate root case. Since there is no
    # use case, let's not explode our test matrix.
    if options.alt_root and options.shutdown:
        parser.error("Invalid to specify -s option with an alternate root")

    # If no grouping is specified, that implies a system level unconfiguration.
    # Confirm with the user that this is what they want for security reasons.
    if not options.grouping:
        if sub_cmd[0] == CONFIGURE:
            print _("This program will re-configure your system.")
        else:
            print _("This program will unconfigure your system.")
            print _("The system will be reverted to a \"pristine\" state.")
            print _("It will not have a name or know about other systems"
                    " or networks.")

        msg = _("Do you want to continue (y/[n])? ")
        confirm = raw_input(msg.encode(get_encoding()))
        if confirm.lower() != "y":
            sys.exit(SU_OK)

        # They have confirmed, set grouping to system.
        options.grouping = [SYSTEM]

    # Formulate the comma separated string into a list
    for grp in options.grouping:
        if COMMA in grp:
            options.grouping.extend(map(str.strip, grp.split(",")))
            options.grouping.remove(grp)
            break

    # If the user specifies a list of groups and one of them is system set
    # to just system since it is a superset of all other groupings.
    if len(options.grouping) > 1 and SYSTEM in options.grouping:
        options.grouping = [SYSTEM]

    if options.alt_root:
        svccfg_repository = os.path.join(options.alt_root, SMF_REPOSITORY)
        os.environ["SVCCFG_REPOSITORY"] = svccfg_repository

    # Check that the functional groups requested are valid
    valid_group_check(options.grouping, sub_cmd, parser)

    # If not operating on the alternate root, we can and must check to make
    # sure that the grouping specified has services of that grouping on the
    # image.
    if not options.alt_root and SYSTEM not in options.grouping:
        # Check that there exist unconfigurable services with the specified
        # grouping on the machine.
        cmd = [SVCPROP, "-p", "unconfigure/exec", "*"]
        p_ret = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.DEVNULL,
                                 check_result=Popen.ANY)
        unconfigurable_svcs = p_ret.stdout.split("\n")
        for opt_grp in options.grouping:
            found = False
            for svcs in unconfigurable_svcs:
                if svcs:
                    svc = svcs.split("/:properties")[0]
                    cmd = [SVCPROP, "-p", "sysconfig/group", svc]
                    p_ret = Popen.check_call(cmd, stdout=Popen.STORE,
                        stderr=Popen.DEVNULL, check_result=Popen.ANY)
                    grping = p_ret.stdout.strip()
                    if grping == opt_grp:
                        found = True

            if not found:
                print _("There are no services on the system with grouping "
                        "of %s" % opt_grp)
                sys.exit(1)

    #
    # The user specified a profile file or a directory with profiles to use
    # on the configure. Verify that supplied profiles contain .xml suffix
    # (otherwise smf(5) will not apply them) and syntactically
    # validate them. Then copy them to the temporary location,
    # /etc/svc/profile/sc/ directory. The unconfig milestone will move
    # them to the site area when it runs. We can't put profiles
    # to site directory right now because they may end up applied before
    # unconfiguration runs and then removed during unconfiguration.
    #
    if sub_cmd[0] == CONFIGURE and options.profile:
        # Verify that supplied path (file or directory) exists.
        if not os.path.exists(options.profile):
            parser.error("%s does not exist." % options.profile)

        # Remove all of /etc/svc/profile/sc
        custom_profile_dir = CUSTOM_PROFILE_DIR
        if options.alt_root:
            custom_profile_dir = os.path.join(options.alt_root,
                                              custom_profile_dir)
        else:
            custom_profile_dir = os.path.join("/", custom_profile_dir)

        if os.path.exists(custom_profile_dir):
            for root, dirs, files in os.walk(custom_profile_dir):
                for profile_file in files:
                    os.unlink(os.path.join(root, profile_file))
        else:
            os.mkdir(custom_profile_dir)

        if os.path.isdir(options.profile):
            #
            # Profile directory is specified.
            # Directory has to contain at least one profile. Start with
            # assumption that given directory does not contain any
            # profile.
            #
            profile_dir_is_empty = True

            # Validate profiles - all supplied profiles have to validate.
            for root, dirs, files in os.walk(options.profile):
                for pfile in files:
                    profile_file = os.path.join(root, pfile)
                    # Abort if profile is invalid.
                    if not profile_is_valid(profile_file):
                        sys.exit(SU_FATAL_ERR)

                    # Place profile in the temporary site profile area.
                    orig_umask = os.umask(0377) 
                    shutil.copyfile(profile_file,
                                    os.path.join(custom_profile_dir, pfile))
                    os.umask(orig_umask) 
                    profile_dir_is_empty = False

            # If no profile was found in given directory, abort.
            if profile_dir_is_empty:
                print _("Directory %s does not contain any profile."
                         % options.profile)
                sys.exit(SU_FATAL_ERR)

        else:
            # Profile is a file - validate it.
            if not profile_is_valid(options.profile):
                sys.exit(SU_FATAL_ERR)

            # Place profile in the temporary site profile area.
            orig_umask = os.umask(0377)
            shutil.copyfile(options.profile, os.path.join(custom_profile_dir,
                            os.path.basename(options.profile)))
            os.umask(orig_umask) 

    #
    # if there is a request to re-configure system in interactive way
    # (using SCI tool), check if we are on console, since this is where SCI
    # tool will be lauched. If we are not on console, let user confirm this
    # is really what one wants to do.
    #
    if sub_cmd[0] == CONFIGURE and not options.profile \
        and not options.alt_root:

        # For now, sysconfig should halt when the user runs sysconfig configure
        # after running sysconfig unconfigure. When the functionality that
        # enables the unconfiguration of individual groupings is implemented,
        # this may need to be revisited. Currently, system is the only group
        # that can be configured/unconfigured.
        cmd = [SVCPROP, "-c", "-p", "sysconfig/unconfigure",
               "milestone/unconfig"]
        p_ret = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.DEVNULL,
                             check_result=Popen.ANY)

        unconfigure_has_occurred = p_ret.stdout.strip()

        cmd = [SVCPROP, "-c", "-p", "sysconfig/configure", "milestone/config"]
        p_ret = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.DEVNULL,
                             check_result=Popen.ANY)

        config_has_occurred = p_ret.stdout.strip()

        if unconfigure_has_occurred == 'true' \
            and config_has_occurred == 'false':
            print _("Error: system has been unconfigured. Reboot to invoke "
               "the SCI Tool and configure the system.")
            sys.exit(SU_FATAL_ERR)

        print _("Interactive configuration requested.")
        print _("System Configuration Interactive (SCI) tool will be" +
            " launched on console.")

        cmd = [TTY]
        try:
            p = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.PIPE,
                                 check_result=(Popen.STDERR_EMPTY, 0))
        except CalledProcessError as err:
            print err.popen.stderr
            # if tty fails, we may not be able to interact with user.
            # In this case, skip the confirmation prompt.
        else:
            terminal_device = p.stdout.strip()

            if terminal_device != CONSOLE:
                print _("Since you are currently not logged on console,\n"
                         "you may not be able to navigate SCI tool.")
                msg = _("Would you like to proceed with re-configuration "
                        "(y/[n])? ")
                confirm = raw_input(msg.encode(get_encoding()))
                if confirm.lower() != "y":
                    sys.exit(SU_OK)

    return (options, sub_cmd)
Beispiel #16
0
def resize_validate(edit_field, disk_win=None):
    '''Check text to see if it is a decimal number of precision no greater
       than the tenths place. Resize the partition if everything checks
       out.
    '''

    LOGGER.debug("in resize_validate()")
    text = edit_field.get_text().lstrip()
    radixchar = locale.localeconv()['decimal_point']
    if text.endswith(" "):
        raise UIMessage(
            _('Only the digits 0-9 and "%s" are valid.') % radixchar)
    vals = text.split(radixchar)
    if len(vals) > 2:
        raise UIMessage(_('A number can only have one "%s"') % radixchar)
    try:
        if len(vals[0]) > 0:
            int(vals[0])
        if len(vals) > 1 and len(vals[1]) > 0:
            int(vals[1])
    except ValueError:
        raise UIMessage(
            _('Only the digits 0-9 and "%s" are valid.') % radixchar)
    if len(vals) > 1 and len(vals[1]) > 1:
        raise UIMessage(_("Size can be specified to only one decimal place."))

    if disk_win is None:
        return True

    text = text.rstrip(radixchar)
    # If the user deleted all digits, leave partition size alone until user
    # inputs new digits
    if not text:
        LOGGER.debug("No size value digits, skipping resize")
        return True

    part_order = disk_win.ui_obj.get_parts_in_use().index(edit_field.data_obj)
    LOGGER.debug("Part being resized is at index: %s", part_order)

    # encode user input per locale for floating point conversion
    text = text.encode(get_encoding())
    new_size = Size(str(locale.atof(text)) + Size.gb_units)
    max_size = edit_field.data_obj.get_max_size()

    # When comparing user input and display sizes, check only to the first
    # decimal place as that is all the user sees.
    new_size_rounded = round(new_size.get(Size.gb_units), 1)
    max_size_rounded = round(max_size.get(Size.gb_units), 1)
    if new_size_rounded > max_size_rounded:
        locale_new_size = locale.format("%.1f", new_size_rounded)
        locale_max_size = locale.format("%.1f", max_size_rounded)
        msg = _("The new size %(size)s is greater than "
                "the available space %(avail)s") % \
                {"size": locale_new_size,
                 "avail": locale_max_size}
        raise UIMessage(msg)

    new_size_text = text.strip()
    LOGGER.debug("New size text=%s", new_size_text)

    old_size = edit_field.data_obj.size
    new_size_byte = new_size.get(Size.byte_units)

    # Filter out edits that would result in resizing a partition to zero
    if new_size_byte == 0:
        return True

    old_size_byte = old_size.get(Size.byte_units)
    precision_bytes = Size(UI_PRECISION).get(Size.byte_units)

    # Ignore potential rounding artifacts.
    if abs(new_size_byte - old_size_byte) <= precision_bytes:
        return True

    max_size_byte = max_size.get(Size.byte_units)

    if new_size_byte > max_size_byte:
        # Allow for loss of precision from rounding errors, but no greater
        if (new_size_byte - max_size_byte) > precision_bytes:
            raise RuntimeError("Requested partition resize to %d bytes "
                               "exceeds maximum size available: %d" %
                               (new_size_byte, max_size_byte))

        # Clamp the new size at max size otherwise the resize will throw
        # an InsufficientSpaceError.
        LOGGER.debug(
            "Requested partition resize exceeds maximum size: "
            "Clamping %d bytes to %d bytes", new_size_byte, max_size_byte)
        new_size = max_size
    parent_doc_obj = edit_field.data_obj.doc_obj.parent
    if isinstance(parent_doc_obj, Disk):
        if isinstance(edit_field.data_obj.doc_obj, GPTPartition):
            resized_obj = parent_doc_obj.resize_gptpartition(
                edit_field.data_obj.doc_obj,
                new_size.get(Size.gb_units),
                size_units=Size.gb_units)
        elif isinstance(edit_field.data_obj.doc_obj, Partition):
            resized_obj = parent_doc_obj.resize_partition(
                edit_field.data_obj.doc_obj,
                new_size.get(Size.gb_units),
                size_units=Size.gb_units)
        else:
            resized_obj = parent_doc_obj.resize_slice(
                edit_field.data_obj.doc_obj,
                new_size.get(Size.gb_units),
                size_units=Size.gb_units)
    else:
        resized_obj = parent_doc_obj.resize_slice(edit_field.data_obj.doc_obj,
                                                  new_size.get(Size.gb_units),
                                                  size_units=Size.gb_units)

    if isinstance(resized_obj, Partition):
        # Don't do this for GPTPartition because there is no guarantee this
        # will be the installation target partition if there is more than
        # 1 Solaris partition
        resized_obj.in_zpool = ROOT_POOL
    elif isinstance(resized_obj, Slice):
        if resized_obj.in_zpool == ROOT_POOL:
            resized_obj.tag = V_ROOT

    disk_win.set_disk_info(ui_obj=disk_win.ui_obj)
    disk_win.activate_index(part_order)

    dump_doc("After resize")

    return True