コード例 #1
0
ファイル: anaconda.py プロジェクト: sjb8100/anaconda
    def __init__(self):
        from pyanaconda import desktop

        self._bootloader = None
        self.desktop = desktop.Desktop()
        self.dir = None
        self._display_mode = None
        self._interactive_mode = True
        self.gui_startup_failed = False
        self.id = None
        self._instClass = None
        self._intf = None
        self.isHeadless = False
        self.ksdata = None
        self.methodstr = None
        self.additional_repos = None
        self.opts = None
        self._payload = None
        self.proxy = None
        self.decorated = False

        self.stage2 = None
        self._storage = None
        self.updateSrc = None
        self.mehConfig = None

        # *sigh* we still need to be able to write this out
        self.xdriver = None

        # Data for inhibiting the screensaver
        self.dbus_session_connection = None
        self.dbus_inhibit_id = None

        # This is used to synchronize Gtk.main calls between the graphical
        # interface and error dialogs. Whoever gets to their initialization code
        # first will lock gui_initializing
        self.gui_initialized = threading.Lock()

        # Create class for launching our dbus session
        self._dbus_launcher = DBusLauncher()
コード例 #2
0
class Anaconda(object):
    def __init__(self):
        from pyanaconda import desktop

        self._bootloader = None
        self.desktop = desktop.Desktop()
        self.dir = None
        self._display_mode = None
        self._interactive_mode = True
        self.gui_startup_failed = False
        self.id = None
        self._instClass = None
        self._intf = None
        self.isHeadless = False
        self.ksdata = None
        self.methodstr = None
        self.opts = None
        self._payload = None
        self.proxy = None
        self.decorated = False

        self.stage2 = None
        self._storage = None
        self.updateSrc = None
        self.mehConfig = None

        # *sigh* we still need to be able to write this out
        self.xdriver = None

        # Data for inhibiting the screensaver
        self.dbus_session_connection = None
        self.dbus_inhibit_id = None

        # This is used to synchronize Gtk.main calls between the graphical
        # interface and error dialogs. Whoever gets to their initialization code
        # first will lock gui_initializing
        self.gui_initialized = threading.Lock()

        # Create class for launching our dbus session
        self._dbus_launcher = DBusLauncher()

    @property
    def bootloader(self):
        if not self._bootloader:
            self._bootloader = get_bootloader()

        return self._bootloader

    @property
    def instClass(self):
        if not self._instClass:
            from pyanaconda.installclass import factory

            # Get install class by name.
            if self.ksdata.anaconda.installclass.seen:
                name = self.ksdata.anaconda.installclass.name
                self._instClass = factory.get_install_class_by_name(name)
            # Or just find the best one.
            else:
                self._instClass = factory.get_best_install_class()

        return self._instClass

    def _getInterface(self):
        return self._intf

    def _setInterface(self, v):
        # "lambda cannot contain assignment"
        self._intf = v

    def _delInterface(self):
        del self._intf

    intf = property(_getInterface, _setInterface, _delInterface)

    @property
    def payload(self):
        # Try to find the payload class.  First try the install
        # class.  If it doesn't give us one, fall back to the default.
        if not self._payload:
            klass = self.instClass.getBackend()

            if not klass:
                from pyanaconda.flags import flags

                if self.ksdata.ostreesetup.seen:
                    from pyanaconda.payload.rpmostreepayload import RPMOSTreePayload
                    klass = RPMOSTreePayload
                elif flags.livecdInstall:
                    from pyanaconda.payload.livepayload import LiveImagePayload
                    klass = LiveImagePayload
                elif self.ksdata.method.method == "liveimg":
                    from pyanaconda.payload.livepayload import LiveImageKSPayload
                    klass = LiveImageKSPayload
                else:
                    from pyanaconda.payload.dnfpayload import DNFPayload
                    klass = DNFPayload

            self._payload = klass(self.ksdata)

        return self._payload

    @property
    def protected(self):
        specs = []
        if os.path.exists("/run/initramfs/livedev") and \
           stat.S_ISBLK(os.stat("/run/initramfs/livedev")[stat.ST_MODE]):
            specs.append(os.readlink("/run/initramfs/livedev"))

        # methodstr and stage2 become strings in ways that pylint can't figure out
        # pylint: disable=unsubscriptable-object
        if self.methodstr and self.methodstr.startswith("hd:"):
            specs.append(self.methodstr[3:].split(":", 3)[0])

        if self.stage2 and self.stage2.startswith("hd:"):
            specs.append(self.stage2[3:].split(":", 3)[0])

        # zRAM swap devices need to be protected
        for zram_dev in glob("/dev/zram*"):
            specs.append(zram_dev)

        return specs

    @property
    def storage(self):
        if not self._storage:
            from pyanaconda.storage.osinstall import InstallerStorage
            import blivet.arch

            self._storage = InstallerStorage(ksdata=self.ksdata)
            self._set_default_fstype(self._storage)

            if blivet.arch.is_s390():
                self._load_plugin_s390()

        return self._storage

    @property
    def display_mode(self):
        return self._display_mode

    @display_mode.setter
    def display_mode(self, new_mode):
        if isinstance(new_mode, DisplayModes):
            if self._display_mode:
                old_mode = self._display_mode
                log.debug("changing display mode from %s to %s",
                          old_mode.value, new_mode.value)
            else:
                log.debug("setting display mode to %s", new_mode.value)
            self._display_mode = new_mode
        else:  # unknown mode name - ignore & log an error
            log.error("tried to set an unknown display mode name: %s",
                      new_mode.value)

    @property
    def interactive_mode(self):
        return self._interactive_mode

    @interactive_mode.setter
    def interactive_mode(self, value):
        if self._interactive_mode != value:
            self._interactive_mode = value
            if value:
                log.debug("working in interative mode")
            else:
                log.debug("working in noninteractive mode")

    @property
    def gui_mode(self):
        """Report if Anaconda should run with the GUI."""
        return self._display_mode == DisplayModes.GUI

    @property
    def tui_mode(self):
        """Report if Anaconda should run with the TUI."""
        return self._display_mode == DisplayModes.TUI

    def log_display_mode(self):
        if not self.display_mode:
            log.error("Display mode is not set!")
            return

        log.info("Display mode is set to '%s %s'.",
                 constants.INTERACTIVE_MODE_NAME[self.interactive_mode],
                 constants.DISPLAY_MODE_NAME[self.display_mode])

    def _set_default_fstype(self, storage):
        fstype = None
        boot_fstype = None

        # Get the default fstype from a kickstart file.
        if self.ksdata.autopart.autopart and self.ksdata.autopart.fstype:
            fstype = self.ksdata.autopart.fstype
            boot_fstype = self.ksdata.autopart.fstype
        # Or from an install class.
        elif self.instClass.defaultFS:
            fstype = self.instClass.defaultFS
            boot_fstype = None

        # Set the default fstype.
        if fstype:
            storage.set_default_fstype(fstype)

        # Set the default boot fstype.
        if boot_fstype:
            storage.set_default_boot_fstype(boot_fstype)

    def _load_plugin_s390(self):
        # Make sure s390 plugin is loaded.
        import gi
        gi.require_version("BlockDev", "2.0")
        from gi.repository import BlockDev as blockdev

        # Is the plugin loaded? We are done then.
        if "s390" in blockdev.get_available_plugin_names():
            return

        # Otherwise, load the plugin.
        plugin = blockdev.PluginSpec()
        plugin.name = blockdev.Plugin.S390
        plugin.so_name = None
        blockdev.reinit([plugin], reload=False)

    def dumpState(self):
        from meh import ExceptionInfo
        from meh.dump import ReverseExceptionDump
        from inspect import stack as _stack
        from traceback import format_stack

        # Skip the frames for dumpState and the signal handler.
        stack = _stack()[2:]
        stack.reverse()
        exn = ReverseExceptionDump(ExceptionInfo(None, None, stack),
                                   self.mehConfig)

        # gather up info on the running threads
        threads = "\nThreads\n-------\n"

        # Every call to sys._current_frames() returns a new dict, so it is not
        # modified when threads are created or destroyed. Iterating over it is
        # thread safe.
        for thread_id, frame in sys._current_frames().items():
            threads += "\nThread %s\n" % (thread_id, )
            threads += "".join(format_stack(frame))

        # dump to a unique file
        (fd, filename) = mkstemp(prefix="anaconda-tb-", dir="/tmp")
        dump_text = exn.traceback_and_object_dump(self)
        dump_text += threads
        dump_text_bytes = dump_text.encode("utf-8")
        os.write(fd, dump_text_bytes)
        os.close(fd)

        # append to a given file
        with open("/tmp/anaconda-tb-all.log", "a+") as f:
            f.write("--- traceback: %s ---\n" % filename)
            f.write(dump_text + "\n")

    def initInterface(self, addon_paths=None):
        if self._intf:
            raise RuntimeError(
                "Second attempt to initialize the InstallInterface")

        if self.gui_mode:
            from pyanaconda.ui.gui import GraphicalUserInterface
            # Run the GUI in non-fullscreen mode, so live installs can still
            # use the window manager
            self._intf = GraphicalUserInterface(self.storage,
                                                self.payload,
                                                self.instClass,
                                                gui_lock=self.gui_initialized,
                                                fullscreen=False,
                                                decorated=self.decorated)

            # needs to be refreshed now we know if gui or tui will take place
            addon_paths = addons.collect_addon_paths(constants.ADDON_PATHS,
                                                     ui_subdir="gui")
        elif self.tui_mode:
            # TUI and noninteractive TUI are the same in this regard
            from pyanaconda.ui.tui import TextUserInterface
            self._intf = TextUserInterface(self.storage, self.payload,
                                           self.instClass)

            # needs to be refreshed now we know if gui or tui will take place
            addon_paths = addons.collect_addon_paths(constants.ADDON_PATHS,
                                                     ui_subdir="tui")
        elif not self.display_mode:
            raise RuntimeError("Display mode not set.")
        else:
            # this should generally never happen, as display_mode now won't let
            # and invalid value to be set, but let's leave it here just in case
            # something ultra crazy happens
            raise RuntimeError("Unsupported display mode: %s" %
                               self.display_mode)

        if addon_paths:
            self._intf.update_paths(addon_paths)

    def postConfigureInstallClass(self):
        """Do an install class late configuration.

        This will enable to configure payload.
        """
        self.instClass.configurePayload(self.payload)

    def writeXdriver(self, root=None):
        # this should go away at some point, but until it does, we
        # need to keep it around.
        if self.xdriver is None:
            return
        if root is None:
            root = util.getSysroot()
        if not os.path.isdir("%s/etc/X11" % (root, )):
            os.makedirs("%s/etc/X11" % (root, ), mode=0o755)
        f = open("%s/etc/X11/xorg.conf" % (root, ), 'w')
        f.write(
            'Section "Device"\n\tIdentifier "Videocard0"\n\tDriver "%s"\nEndSection\n'
            % self.xdriver)
        f.close()

    def run_boss_with_dbus(self):
        """Ensure suitable DBus is running. If not, start a new session."""
        self._dbus_launcher.start_dbus_session()
        self._dbus_launcher.write_bus_address()
        run_boss()

    def cleanup_dbus_session(self):
        """Stop our DBus services and our DBus session if it is our private DBus session.

        Our DBus is started when no session DBus is available.
        """
        stop_boss()
        self._dbus_launcher.stop()
コード例 #3
0
ファイル: __init__.py プロジェクト: anthrax3/initial-setup
    def __init__(self, gui_mode):
        """Initialize the Initial Setup internals"""
        log.debug("initializing Initial Setup")
        # True if running in graphical mode, False otherwise (text mode)
        self.gui_mode = gui_mode
        # kickstart data
        self.data = None

        # parse any command line arguments
        args = self._parse_arguments()

        # initialize logging
        initial_setup_log.init(stdout_log=not args.no_stdout_log)
        global logging_initialized
        logging_initialized = True

        log.info("Initial Setup %s" % __version__)

        # check if we are running as root
        if os.geteuid() != 0:
            log.critical("Initial Setup needs to be run as root")
            raise InitialSetupError

        if self.gui_mode:
            log.debug("running in GUI mode")
        else:
            log.debug("running in TUI mode")

        self._external_reconfig = False

        # check if the reconfig mode should be enabled
        # by checking if at least one of the reconfig
        # files exist
        for reconfig_file in RECONFIG_FILES:
            if os.path.exists(reconfig_file):
                self.external_reconfig = True
                log.debug("reconfig trigger file found: %s", reconfig_file)

        if self.external_reconfig:
            log.debug("running in externally triggered reconfig mode")

        if self.gui_mode:
            # We need this so we can tell GI to look for overrides objects
            # also in anaconda source directories
            import gi.overrides
            for p in os.environ.get("ANACONDA_WIDGETS_OVERRIDES", "").split(":"):
                gi.overrides.__path__.insert(0, p)
            log.debug("GI overrides imported")

        from pyanaconda.addons import collect_addon_paths

        addon_paths = ["/usr/share/initial-setup/modules", "/usr/share/anaconda/addons"]

        # append ADDON_PATHS dirs at the end
        sys.path.extend(addon_paths)

        self._addon_module_paths = collect_addon_paths(addon_paths, self.gui_mode_id)
        log.info("found %d addon modules:", len(self._addon_module_paths))
        for addon_path in self._addon_module_paths:
            log.debug(addon_path)

        # Too bad anaconda does not have modularized logging
        log.debug("initializing the Anaconda log")
        from pyanaconda import anaconda_logging
        anaconda_logging.init()

        # init threading before Gtk can do anything and before we start using threads
        # initThreading initializes the threadMgr instance, import it afterwards
        log.debug("initializing threading")
        from pyanaconda.threading import initThreading
        initThreading()

        # initialize network logging (needed by the Network spoke that may be shown)
        log.debug("initializing network logging")
        from pyanaconda.network import setup_ifcfg_log
        setup_ifcfg_log()

        # create class for launching our dbus session
        self._dbus_launcher = DBusLauncher()
コード例 #4
0
ファイル: __init__.py プロジェクト: anthrax3/initial-setup
class InitialSetup(object):
    def __init__(self, gui_mode):
        """Initialize the Initial Setup internals"""
        log.debug("initializing Initial Setup")
        # True if running in graphical mode, False otherwise (text mode)
        self.gui_mode = gui_mode
        # kickstart data
        self.data = None

        # parse any command line arguments
        args = self._parse_arguments()

        # initialize logging
        initial_setup_log.init(stdout_log=not args.no_stdout_log)
        global logging_initialized
        logging_initialized = True

        log.info("Initial Setup %s" % __version__)

        # check if we are running as root
        if os.geteuid() != 0:
            log.critical("Initial Setup needs to be run as root")
            raise InitialSetupError

        if self.gui_mode:
            log.debug("running in GUI mode")
        else:
            log.debug("running in TUI mode")

        self._external_reconfig = False

        # check if the reconfig mode should be enabled
        # by checking if at least one of the reconfig
        # files exist
        for reconfig_file in RECONFIG_FILES:
            if os.path.exists(reconfig_file):
                self.external_reconfig = True
                log.debug("reconfig trigger file found: %s", reconfig_file)

        if self.external_reconfig:
            log.debug("running in externally triggered reconfig mode")

        if self.gui_mode:
            # We need this so we can tell GI to look for overrides objects
            # also in anaconda source directories
            import gi.overrides
            for p in os.environ.get("ANACONDA_WIDGETS_OVERRIDES", "").split(":"):
                gi.overrides.__path__.insert(0, p)
            log.debug("GI overrides imported")

        from pyanaconda.addons import collect_addon_paths

        addon_paths = ["/usr/share/initial-setup/modules", "/usr/share/anaconda/addons"]

        # append ADDON_PATHS dirs at the end
        sys.path.extend(addon_paths)

        self._addon_module_paths = collect_addon_paths(addon_paths, self.gui_mode_id)
        log.info("found %d addon modules:", len(self._addon_module_paths))
        for addon_path in self._addon_module_paths:
            log.debug(addon_path)

        # Too bad anaconda does not have modularized logging
        log.debug("initializing the Anaconda log")
        from pyanaconda import anaconda_logging
        anaconda_logging.init()

        # init threading before Gtk can do anything and before we start using threads
        # initThreading initializes the threadMgr instance, import it afterwards
        log.debug("initializing threading")
        from pyanaconda.threading import initThreading
        initThreading()

        # initialize network logging (needed by the Network spoke that may be shown)
        log.debug("initializing network logging")
        from pyanaconda.network import setup_ifcfg_log
        setup_ifcfg_log()

        # create class for launching our dbus session
        self._dbus_launcher = DBusLauncher()

    @property
    def external_reconfig(self):
        """External reconfig status.

        Reports if external (eq. not triggered by kickstart) has been enabled.

        :returns: True if external reconfig mode has been enabled, else False.
        :rtype: bool
        """
        return self._external_reconfig

    @external_reconfig.setter
    def external_reconfig(self, value):
        self._external_reconfig = value

    @property
    def gui_mode_id(self):
        """String id of the current GUI mode

        :returns: "gui" if gui_mode is True, "tui" otherwise
        :rtype: str
        """
        if self.gui_mode:
            return "gui"
        else:
            return "tui"

    def _parse_arguments(self):
        """Parse command line arguments"""
        # create an argparse instance
        parser = argparse.ArgumentParser(prog="Initial Setup",
                                         description="Initial Setup is can run during the first start of a newly installed"
                                         "system to configure it according to the needs of the user.")
        parser.add_argument("--no-stdout-log", action="store_true", default=False, help="don't log to stdout")
        parser.add_argument('--version', action='version', version=__version__)

        # parse arguments and return the result
        return parser.parse_args()

    def _load_kickstart(self):
        """Load the kickstart"""
        from pyanaconda import kickstart

        # Construct a commandMap with only the supported Anaconda's commands
        commandMap = dict((k, kickstart.commandMap[k]) for k in SUPPORTED_KICKSTART_COMMANDS)

        # Prepare new data object
        self.data = kickstart.AnacondaKSHandler(self._addon_module_paths["ks"], commandUpdates=commandMap)

        kickstart_path = INPUT_KICKSTART_PATH
        if os.path.exists(OUTPUT_KICKSTART_PATH):
            log.info("using kickstart from previous run for input")
            kickstart_path = OUTPUT_KICKSTART_PATH

        log.info("parsing input kickstart %s", kickstart_path)
        try:
            # Read the installed kickstart
            parser = kickstart.AnacondaKSParser(self.data)
            parser.readKickstart(kickstart_path)
            log.info("kickstart parsing done")
        except pykickstart.errors.KickstartError as kserr:
            log.critical("kickstart parsing failed: %s", kserr)
            log.critical("Initial Setup startup failed due to invalid kickstart file")
            raise InitialSetupError

        # if we got this far the kickstart should be valid, so send it to Boss as well
        boss = BOSS.get_proxy()

        boss.SplitKickstart(kickstart_path)
        errors = boss.DistributeKickstart()

        if errors:
            message = "\n\n".join("{error_message}".format_map(e) for e in errors)
            raise InitialSetupError(message)

        if self.external_reconfig:
            # set the reconfig flag in kickstart so that
            # relevant spokes show up
            services_proxy = SERVICES.get_proxy()
            services_proxy.SetSetupOnBoot(SETUP_ON_BOOT_RECONFIG)

    def _setup_locale(self):
        log.debug("setting up locale")

        localization_proxy = LOCALIZATION.get_proxy()

        # Normalize the locale environment variables
        if localization_proxy.Kickstarted:
            locale_arg = localization_proxy.Language
        else:
            locale_arg = None
        setup_locale_environment(locale_arg, prefer_environment=True)
        setup_locale(os.environ['LANG'], text_mode=not self.gui_mode)

    def _apply(self):
        # Do not execute sections that were part of the original
        # anaconda kickstart file (== have .seen flag set)

        log.info("applying changes")

        sections = [self.data.keyboard, self.data.lang, self.data.timezone]

        # data.selinux
        # data.firewall

        localization_proxy = LOCALIZATION.get_proxy()
        self.data.keyboard.seen = localization_proxy.KeyboardKickstarted
        self.data.lang.seen = localization_proxy.LanguageKickstarted

        timezone_proxy = TIMEZONE.get_proxy()
        self.data.timezone.seen = timezone_proxy.Kickstarted

        log.info("executing kickstart")
        for section in sections:
            section_msg = "%s on line %d" % (repr(section), section.lineno)
            if section.seen:
                log.debug("skipping %s", section_msg)
                continue
            log.debug("executing %s", section_msg)
            section.execute(None, self.data, None)

        # Prepare the user database tools
        u = Users()

        sections = [self.data.group, self.data.user, self.data.rootpw]

        user_proxy = USER.get_proxy()
        self.data.rootpw.seen = user_proxy.IsRootpwKickstarted

        for section in sections:
            section_msg = "%s on line %d" % (repr(section), section.lineno)
            if section.seen:
                log.debug("skipping %s", section_msg)
                continue
            log.debug("executing %s", section_msg)
            section.execute(None, self.data, None, u)

        # Configure all addons
        log.info("executing addons")
        self.data.addons.execute(None, self.data, None, u, None)

        if self.external_reconfig:
            # prevent the reconfig flag from being written out
            # to kickstart if neither /etc/reconfigSys or /.unconfigured
            # are present
            services_proxy = SERVICES.get_proxy()
            services_proxy.SetSetupOnBoot(SETUP_ON_BOOT_DEFAULT)

        # Write the kickstart data to file
        log.info("writing the Initial Setup kickstart file %s", OUTPUT_KICKSTART_PATH)
        with open(OUTPUT_KICKSTART_PATH, "w") as f:
            f.write(str(self.data))
        log.info("finished writing the Initial Setup kickstart file")

        # Remove the reconfig files, if any - otherwise the reconfig mode
        # would start again next time the Initial Setup service is enabled.
        if self.external_reconfig:
            for reconfig_file in RECONFIG_FILES:
                if os.path.exists(reconfig_file):
                    log.debug("removing reconfig trigger file: %s" % reconfig_file)
                    os.remove(reconfig_file)

        # and we are done with applying changes
        log.info("all changes have been applied")

    def run(self):
        """Run Initial setup

        :param bool gui_mode: if GUI should be used (TUI is the default)

        :returns: True if the IS run was successful, False if it failed
        :rtype: bool
        """
        # start Boss & our DBUS session
        self.run_boss_with_dbus()

        # also register boss shutdown & DBUS session cleanup via exit handler
        atexit.register(self.cleanup_dbus_session)

        # Make sure that all DBus modules are ready.
        if not startup_utils.wait_for_modules(timeout=30):
            log.error("Anaconda DBus modules failed to start on time.")
            return True

        self._load_kickstart()
        self._setup_locale()

        # initialize the screen access manager before launching the UI
        screen_access.initSAM()

        if self.gui_mode:
            try:
                # Try to import IS gui specifics
                log.debug("trying to import GUI")
                import initial_setup.gui
            except ImportError:
                log.exception("GUI import failed, falling back to TUI")
                self.gui_mode = False

        if self.gui_mode:
            # gui already imported (see above)

            # Add addons to search paths
            initial_setup.gui.InitialSetupGraphicalUserInterface.update_paths(self._addon_module_paths)

            # Initialize the UI
            log.debug("initializing GUI")
            ui = initial_setup.gui.InitialSetupGraphicalUserInterface(None, None, PostInstallClass())
        else:
            # Import IS gui specifics
            import initial_setup.tui

            # Add addons to search paths
            initial_setup.tui.InitialSetupTextUserInterface.update_paths(self._addon_module_paths)

            # Initialize the UI
            log.debug("initializing TUI")
            ui = initial_setup.tui.InitialSetupTextUserInterface(None, None, None)

        # Pass the data object to user interface
        log.debug("setting up the UI")
        ui.setup(self.data)

        # Start the application
        log.info("starting the UI")
        ret = ui.run()

        # TUI returns False if the app was ended prematurely
        # all other cases return True or None
        if ret is False:
            log.warning("ended prematurely in TUI")
            return True

        # apply changes
        self._apply()

        # in the TUI mode shutdown the multi TTY handler
        if not self.gui_mode:
            # TODO: wait for this to finish or make it blockng ?
            ui.multi_tty_handler.shutdown()

        # and we are done
        return True

    def run_boss_with_dbus(self):
        """Ensure suitable DBus is running. If not, start a new session."""
        self._dbus_launcher.start_dbus_session()
        self._dbus_launcher.write_bus_address()
        run_boss(kickstart_modules=SUPPORTED_KICKSTART_MODULES)

    def cleanup_dbus_session(self):
        """Stop our DBus services and our DBus session if it is our private DBus session.

        Our DBus is started when no session DBus is available.
        """
        stop_boss()
        self._dbus_launcher.stop()