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

        if self.displayMode == 'g':
            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)

            # 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.displayMode in ['t', 'c']: # text and command line are the same
            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")
        else:
            raise RuntimeError("Unsupported displayMode: %s" % self.displayMode)

        if addon_paths:
            self._intf.update_paths(addon_paths)
Beispiel #2
0
    def __init__(self, cli_args):
        """Initialize the Initial Setup text UI.

        :param cli_args: command line arguments parsed by Argparse
        """
        TextUserInterface.__init__(self, None, None, get_product_title, is_final(),
                                   quitMessage=QUIT_MESSAGE)

        self.multi_tty_handler = None
        self._use_multi_tty_handler = not cli_args.no_multi_tty

        # In some case, such as when running Initial Setup directly
        # in console or from an SSH session script, we should not
        # start the multi TTY handler and just run in the single
        # local console.
        if self._use_multi_tty_handler:
            # redirect stdin and stdout to custom pipes

            # stdin
            stdin_fd, tui_stdin_fd = os.pipe()
            sys.stdin = os.fdopen(stdin_fd, "r")

            # stdout
            tui_stdout_fd, stdout_fd = os.pipe()
            sys.stdout = os.fdopen(stdout_fd, "w")
            sys.stdout.reconfigure(line_buffering=True)

            # instantiate and start the multi TTY handler
            self.multi_tty_handler = MultipleTTYHandler(tui_stdin_fd=tui_stdin_fd,
                                                        tui_stdout_fd=tui_stdout_fd)
            # start the multi-tty handler
            threading.threadMgr.add(
                threading.AnacondaThread(name="initial_setup_multi_tty_thread",
                                         target=self.multi_tty_handler.run)
            )
Beispiel #3
0
    def initInterface(self):
        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,
                                                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)

            # 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)
Beispiel #4
0
 def setup(self, data):
     TextUserInterface.setup(self, data)
     # Make sure custom getpass() from multi-tty handler is used instead of regular getpass.
     # This needs to be done as the default getpass() implementation cant work with arbitrary
     # consoles and always defaults to /dev/tty for input.
     configuration = App.get_configuration()
     configuration.password_function = self.multi_tty_handler.custom_getpass
Beispiel #5
0
    def initInterface(self):
        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(None, self.payload,
                                                gui_lock=self.gui_initialized,
                                                fullscreen=False)

            # 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(None, self.payload)

            # 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)
Beispiel #6
0
    def initInterface(self, addon_paths=None):
        if self._intf:
            raise RuntimeError(
                "Second attempt to initialize the InstallInterface")

        if self.displayMode == 'g':
            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)

            # 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.displayMode in ['t',
                                  'c']:  # text and command line are the same
            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")
        else:
            raise RuntimeError("Unsupported displayMode: %s" %
                               self.displayMode)

        if addon_paths:
            self._intf.update_paths(addon_paths)
Beispiel #7
0
    def __init__(self, storage, payload, instclass):
        TextUserInterface.__init__(self,
                                   storage,
                                   payload,
                                   instclass,
                                   product_title,
                                   is_final,
                                   quitMessage=QUIT_MESSAGE)

        # redirect stdin and stdout to custom pipes

        # stdin
        stdin_fd, tui_stdin_fd = os.pipe()
        sys.stdin = os.fdopen(stdin_fd, "r")

        # stdout
        tui_stdout_fd, stdout_fd = os.pipe()
        sys.stdout = os.fdopen(stdout_fd, "w")

        # instantiate and start the multi TTY handler
        self.multi_tty_handler = MultipleTTYHandler(
            tui_stdin_fd=tui_stdin_fd, tui_stdout_fd=tui_stdout_fd)
        # start the multi-tty handler
        threading.threadMgr.add(
            threading.AnacondaThread(name="initial_setup_multi_tty_thread",
                                     target=self.multi_tty_handler.run))
Beispiel #8
0
 def setup(self, data):
     TextUserInterface.setup(self, data)
     # Make sure custom getpass() from multi-tty handler is used instead of regular getpass.
     # This needs to be done as the default getpass() implementation cant work with arbitrary
     # consoles and always defaults to /dev/tty for input.
     screen_scheduler = App.get_scheduler()
     io_manager = screen_scheduler.io_manager
     io_manager.set_pass_func(self.multi_tty_handler.custom_getpass)
Beispiel #9
0
 def __init__(self, storage, payload, instclass):
     TextUserInterface.__init__(self,
                                storage,
                                payload,
                                instclass,
                                product_title,
                                is_final,
                                quitMessage=QUIT_MESSAGE)
Beispiel #10
0
    def tui_test(self, proxy_getter):
        # Create the interface.
        from pyanaconda.ui.tui import TextUserInterface
        self.interface = TextUserInterface(self.storage, self.payload)

        # Check the hubs
        from pyanaconda.ui.tui.hubs.summary import SummaryHub
        self.assertEqual(self.hubs, [SummaryHub])

        # Check the actions classes.
        self.assertEqual(self._get_action_class_names(), [
            "UnsupportedHardwareSpoke", "KernelWarningSpoke", "SummaryHub",
            "ProgressSpoke"
        ])

        # Check the Summary hub.
        self.assertEqual(
            self._get_category_names(SummaryHub), {
                'CustomizationCategory': [],
                'LocalizationCategory': ['LangSpoke', 'TimeSpoke'],
                'SoftwareCategory': ['SoftwareSpoke', 'SourceSpoke'],
                'SystemCategory':
                ['NetworkSpoke', 'ShellSpoke', 'StorageSpoke'],
                'UserSettingsCategory': ['PasswordSpoke', 'UserSpoke']
            })

        # Force us to always decide order of standalone spokes based on priority not by name.
        # This will ordering errors easier to spot.
        self._check_spokes_priority_uniqueness()
Beispiel #11
0
    def initInterface(self):
        if self._intf:
            raise RuntimeError(
                "Second attempt to initialize the InstallInterface")

        # this boot option is meant to be temporary, so just check it directly
        # from kernel boot command line like this
        if "webui" in kernel_arguments:
            from pyanaconda.ui.webui import CockpitUserInterface
            self._intf = CockpitUserInterface(
                None, self.payload, "webui.remote" in kernel_arguments)

            # needs to be refreshed now we know if gui or tui will take place
            # FIXME - what about Cockpit based addons ?
            addon_paths = []
        elif 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(None,
                                                self.payload,
                                                gui_lock=self.gui_initialized,
                                                fullscreen=False)

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

            # needs to be refreshed now we know if gui or tui will take place
            addon_paths = collect_addon_ui_paths(ADDON_PATHS, "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)
Beispiel #12
0
    def tui_test(self):
        # Create the interface.
        from pyanaconda.ui.tui import TextUserInterface
        self.interface = TextUserInterface(self.storage, self.payload)

        # Check the hubs
        from pyanaconda.ui.tui.hubs.summary import SummaryHub
        self.assertEqual(self.hubs, [SummaryHub])

        # Check the actions classes.
        self.assertEqual(self._get_action_class_names(), [
            "UnsupportedHardwareSpoke",
            "SummaryHub",
            "ProgressSpoke"
        ])

        # Check the Summary hub.
        self.assertEqual(self._get_category_names(SummaryHub), {
            'CustomizationCategory': [],
            'LocalizationCategory': [
                'LangSpoke',
                'TimeSpoke'
            ],
            'SoftwareCategory': [
                'SoftwareSpoke',
                'SourceSpoke'
            ],
            'SystemCategory': [
                'NetworkSpoke',
                'PartTypeSpoke',
                'ShellSpoke',
                'StorageSpoke'
            ],
            'UserSettingsCategory': [
                'PasswordSpoke',
                'UserSpoke'
            ]
        })
Beispiel #13
0
 def __init__(self, storage, payload, instclass):
     TextUserInterface.__init__(self, storage, payload, instclass,
                                      product_title, is_final, quitMessage = QUIT_MESSAGE)
Beispiel #14
0
class Anaconda(object):
    def __init__(self):
        self._display_mode = None
        self._interactive_mode = True
        self.gui_startup_failed = False
        self._intf = None
        self.ksdata = None
        self.methodstr = None
        self.additional_repos = None
        self.opts = None
        self._payload = None
        self.proxy = None
        self.mehConfig = 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 = None

    def set_from_opts(self, opts):
        """Load argument to variables from self.opts."""
        self.opts = opts
        self.proxy = opts.proxy
        self.methodstr = opts.method
        self.additional_repos = opts.addRepo

    @property
    def dbus_launcher(self):
        if not self._dbus_launcher:
            self._dbus_launcher = AnacondaDBusLauncher()

        return self._dbus_launcher

    @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:
            if self.ksdata.ostreesetup.seen:
                if FlatpakPayload.is_available():
                    from pyanaconda.payload.rpmostreepayload import RPMOSTreePayloadWithFlatpaks
                    klass = RPMOSTreePayloadWithFlatpaks
                else:
                    from pyanaconda.payload.rpmostreepayload import RPMOSTreePayload
                    klass = RPMOSTreePayload
            elif self.opts.liveinst:
                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

    @staticmethod
    def get_protected_devices(opts):
        specs = []

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

        if opts.stage2 and SourceFactory.is_harddrive(opts.stage2):
            specs.append(opts.stage2[3:].split(":", 3)[0])

        for additional_repo in opts.addRepo:
            _name, repo_url = Anaconda._get_additional_repo_name(
                additional_repo)
            if SourceFactory.is_harddrive(repo_url):
                specs.append(repo_url[3:].split(":", 3)[0])

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

        return specs

    @staticmethod
    def _get_additional_repo_name(repo):
        try:
            name, rest = repo.split(',', maxsplit=1)
        except ValueError:
            raise RuntimeError(
                "addrepo boot option has incorrect format. Correct format is: "
                "inst.addrepo=<name>,<url>") from None
        return name, rest

    @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 add_additional_repositories_to_ksdata(self):
        from pyanaconda.kickstart import RepoData

        for add_repo in self.additional_repos:
            name, repo_url = self._get_additional_repo_name(add_repo)
            try:
                source = SourceFactory.parse_repo_cmdline_string(repo_url)
            except PayloadSourceTypeUnrecognized:
                log.error(
                    "Type for additional repository %s is not recognized!",
                    add_repo)
                return

            repo = RepoData(name=name, baseurl=repo_url, install=False)

            if source.is_nfs or source.is_http or source.is_https or source.is_ftp \
                    or source.is_file:
                repo.enabled = True
            elif source.is_harddrive:
                repo.enabled = True
                repo.partition = source.partition
                repo.iso_path = source.path
                repo.baseurl = "file://"
            else:
                log.error(
                    "Source type %s for additional repository %s is not supported!",
                    source.source_type.value, add_repo)
                continue

            self._check_repo_name_uniqueness(repo)
            self.ksdata.repo.dataList().append(repo)

    def _check_repo_name_uniqueness(self, repo):
        """Log if we are adding repository with already used name

        In automatic kickstart installation this will result in using the first defined repo.
        """
        if repo in self.ksdata.repo.dataList():
            log.warning(
                "Repository name %s is not unique. Only the first repo will be used!",
                repo.name)

    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")

    @property
    def intf(self):
        """The user interface."""
        return self._intf

    def initInterface(self):
        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(None,
                                                self.payload,
                                                gui_lock=self.gui_initialized,
                                                fullscreen=False)

            # 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(None, self.payload)

            # 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)
Beispiel #15
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.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 = None

    def set_from_opts(self, opts):
        """Load argument to variables from self.opts."""
        self.opts = opts
        self.decorated = opts.decorated
        self.proxy = opts.proxy
        self.updateSrc = opts.updateSrc
        self.methodstr = opts.method
        self.stage2 = opts.stage2
        self.additional_repos = opts.addRepo

    @property
    def dbus_launcher(self):
        if not self._dbus_launcher:
            self._dbus_launcher = AnacondaDBusLauncher()

        return self._dbus_launcher

    @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:
            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 SourceFactory.is_harddrive(self.methodstr):
            specs.append(self.methodstr[3:].split(":", 3)[0])

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

        for additional_repo in self.additional_repos:
            _name, repo_url = self._get_additional_repo_name(additional_repo)
            if SourceFactory.is_harddrive(repo_url):
                specs.append(repo_url[3:].split(":", 3)[0])

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

        return specs

    @staticmethod
    def _get_additional_repo_name(repo):
        name, rest = repo.split(',', maxsplit=1)
        return name, rest

    @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_storage_defaults(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 add_additional_repositories_to_ksdata(self):
        from pyanaconda.kickstart import RepoData

        for add_repo in self.additional_repos:
            name, repo_url = self._get_additional_repo_name(add_repo)
            try:
                source = SourceFactory.parse_repo_cmdline_string(repo_url)
            except PayloadSourceTypeUnrecognized:
                log.error(
                    "Type for additional repository %s is not recognized!",
                    add_repo)
                return

            repo = RepoData(name=name, baseurl=repo_url, install=False)

            if source.is_nfs or source.is_http or source.is_https or source.is_ftp \
                    or source.is_file:
                repo.enabled = True
            elif source.is_harddrive:
                repo.enabled = True
                repo.partition = source.partition
                repo.iso_path = source.path
                repo.baseurl = "file://"
            else:
                log.error(
                    "Source type %s for additional repository %s is not supported!",
                    source.source_type.value, add_repo)
                continue

            self._check_repo_name_uniqueness(repo)
            self.ksdata.repo.dataList().append(repo)

    def _check_repo_name_uniqueness(self, repo):
        """Log if we are adding repository with already used name

        In automatic kickstart installation this will result in using the first defined repo.
        """
        if repo in self.ksdata.repo.dataList():
            log.warning(
                "Repository name %s is not unique. Only the first repo will be used!",
                repo.name)

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

        # Get the default fstype from a kickstart file.
        auto_part_proxy = STORAGE.get_proxy(AUTO_PARTITIONING)

        if auto_part_proxy.Enabled and auto_part_proxy.FilesystemType:
            fstype = auto_part_proxy.FilesystemType
            boot_fstype = 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)

        # Set the default LUKS version.
        luks_version = self.instClass.default_luks_version

        if luks_version:
            storage.set_default_luks_version(luks_version)

        # Set the default partitioning.
        storage.set_default_partitioning(self.instClass.default_partitioning)

    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 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()
Beispiel #16
0
class Anaconda(object):
    def __init__(self):
        from pyanaconda import desktop

        self._bootloader = None
        self.canReIPL = False
        self.desktop = desktop.Desktop()
        self.dir = None
        self.displayMode = None
        self.gui_startup_failed = False
        self.id = None
        self._instClass = None
        self._intf = None
        self.isHeadless = False
        self.ksdata = None
        self.mediaDevice = None
        self.methodstr = None
        self.opts = None
        self._payload = None
        self.proxy = None
        self.proxyUsername = None
        self.proxyPassword = None
        self.reIPLMessage = None
        self.rescue_mount = True
        self.rootParts = None

        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()

    @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 DefaultInstall
            self._instClass = DefaultInstall()

        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 packaging 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.packaging.rpmostreepayload import RPMOSTreePayload
                    klass = RPMOSTreePayload
                elif flags.livecdInstall:
                    from pyanaconda.packaging.livepayload import LiveImagePayload
                    klass = LiveImagePayload
                elif self.ksdata.method.method == "liveimg":
                    from pyanaconda.packaging.livepayload import LiveImageKSPayload
                    klass = LiveImageKSPayload
                else:
                    from pyanaconda.packaging.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:
            import blivet
            import blivet.arch

            import gi
            gi.require_version("BlockDev", "1.0")

            from gi.repository import BlockDev as blockdev
            self._storage = blivet.Blivet(ksdata=self.ksdata)

            if self.instClass.defaultFS:
                self._storage.setDefaultFSType(self.instClass.defaultFS)

            if blivet.arch.isS390():
                # want to make sure s390 plugin is loaded
                if "s390" not in blockdev.get_available_plugin_names():
                    plugin = blockdev.PluginSpec()
                    plugin.name = blockdev.Plugin.S390
                    plugin.so_name = None
                    blockdev.reinit([plugin], reload=False)

        return self._storage

    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.displayMode == 'g':
            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)

            # 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.displayMode in ['t',
                                  'c']:  # text and command line are the same
            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")
        else:
            raise RuntimeError("Unsupported displayMode: %s" %
                               self.displayMode)

        if addon_paths:
            self._intf.update_paths(addon_paths)

    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 = iutil.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()
Beispiel #17
0
class Anaconda(object):
    def __init__(self):
        import desktop
        from flags import flags

        self._bootloader = None
        self.canReIPL = False
        self.desktop = desktop.Desktop()
        self.dir = None
        self.displayMode = None
        self.extraModules = []
        self.id = None
        self._instClass = None
        self._intf = None
        self.isHeadless = False
        self.ksdata = None
        self.mediaDevice = None
        self.methodstr = None
        self._network = None
        self.opts = None
        self._payload = None
        self.proxy = None
        self.proxyUsername = None
        self.proxyPassword = None
        self.reIPLMessage = None
        self.rescue = False
        self.rescue_mount = True
        self.rootParts = None

        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

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

        return self._bootloader

    @property
    def instClass(self):
        if not self._instClass:
            from installclass import DefaultInstall
            self._instClass = DefaultInstall()

        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 network(self):
        if not self._network:
            import network
            self._network = network.Network()

        return self._network

    @property
    def payload(self):
        # Try to find the packaging 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 flags import flags

                if self.ksdata.ostreesetup:
                    from pyanaconda.packaging.ostreepayload import OSTreePayload
                    klass = OSTreePayload
                elif flags.livecdInstall:
                    from pyanaconda.packaging.livepayload import LiveImagePayload
                    klass = LiveImagePayload
                elif self.ksdata.method.method == "liveimg":
                    from pyanaconda.packaging.livepayload import LiveImageKSPayload
                    klass = LiveImageKSPayload
                else:
                    from pyanaconda.packaging.yumpayload import YumPayload
                    klass = YumPayload

            self._payload = klass(self.ksdata)

        return self._payload

    @property
    def protected(self):
        import stat
        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"))

        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])

        return specs

    @property
    def storage(self):
        if not self._storage:
            import blivet
            self._storage = blivet.Blivet(ksdata=self.ksdata)

            if self.instClass.defaultFS:
                self._storage.setDefaultFSType(self.instClass.defaultFS)

        return self._storage

    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"
        for thread_id, frame in sys._current_frames().iteritems():
            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 = dump_text.encode("utf-8")
        os.write(fd, dump_text)
        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.displayMode == 'g':
            from pyanaconda.ui.gui import GraphicalUserInterface
            self._intf = GraphicalUserInterface(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="gui")
        elif self.displayMode in ['t',
                                  'c']:  # text and command line are the same
            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")
        else:
            raise RuntimeError("Unsupported displayMode: %s" %
                               self.displayMode)

        if addon_paths:
            self._intf.update_paths(addon_paths)

    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 = ROOT_PATH
        if not os.path.isdir("%s/etc/X11" % (root, )):
            os.makedirs("%s/etc/X11" % (root, ), mode=0755)
        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 write(self):
        import network
        self.writeXdriver()

        network.write_sysconfig_network()
        network.disableIPV6()
        network.copyConfigToPath(ROOT_PATH)
        if not self.ksdata:
            self.instClass.setNetworkOnbootDefault()
        self.desktop.write()
Beispiel #18
0
    def test_tui(self, proxy_getter):
        # Create the interface.
        from pyanaconda.ui.tui import TextUserInterface
        self.interface = TextUserInterface(self.storage, self.payload)

        # Check the hubs
        from pyanaconda.ui.tui.hubs.summary import SummaryHub
        self._check_hubs([SummaryHub])

        # Check the actions classes.
        self._check_actions([
            "unsupported-hardware-warning",
            "kernel-warning",
            "installation-summary",
            "installation-progress",
        ])

        # Check the Summary hub.
        self._check_categories(
            SummaryHub, {
                'CustomizationCategory': [],
                'LocalizationCategory': [
                    'language-configuration',
                    'date-time-configuration',
                ],
                'SoftwareCategory': [
                    'software-selection',
                    'software-source-configuration',
                ],
                'SystemCategory': [
                    'network-configuration',
                    'storage-configuration',
                    'shell',
                ],
                'UserSettingsCategory': [
                    'root-configuration',
                    'user-configuration',
                ]
            })

        # Check the screens.
        self._check_screens([
            # Warnings
            "unsupported-hardware-warning",
            "kernel-warning",

            # Installation
            'installation-summary',
            'installation-progress',

            # Localization
            'date-time-configuration',
            'language-configuration',

            # Software
            'software-selection',
            'software-source-configuration',

            # System
            'network-configuration',
            'storage-configuration',
            'shell',

            # User settings
            'root-configuration',
            'user-configuration',
        ])

        # Run general checks on the user interface.
        self._check_interface()
Beispiel #19
0
class Anaconda(object):
    def __init__(self):
        from pyanaconda import desktop

        self._bootloader = None
        self.canReIPL = False
        self.desktop = desktop.Desktop()
        self.dir = None
        self.displayMode = None
        self.extraModules = []
        self.id = None
        self._instClass = None
        self._intf = None
        self.isHeadless = False
        self.ksdata = None
        self.mediaDevice = None
        self.methodstr = None
        self.opts = None
        self._payload = None
        self.proxy = None
        self.proxyUsername = None
        self.proxyPassword = None
        self.reIPLMessage = None
        self.rescue = False
        self.rescue_mount = True
        self.rootParts = None

        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

    @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 DefaultInstall
            self._instClass = DefaultInstall()

        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 packaging 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 flags.livecdInstall:
                    from pyanaconda.packaging.livepayload import LiveImagePayload
                    klass = LiveImagePayload
                elif self.ksdata.method.method == "liveimg":
                    from pyanaconda.packaging.livepayload import LiveImageKSPayload
                    klass = LiveImageKSPayload
                elif flags.dnf:
                    try:
                        from pyanaconda.packaging.dnfpayload import DNFPayload
                        klass = DNFPayload
                    except ImportError:
                        log.critical('Importing DNF  failed.', exc_info=True)
                else:
                    from pyanaconda.packaging.yumpayload import YumPayload
                    klass = YumPayload

            self._payload = klass(self.ksdata)

        return self._payload

    @property
    def protected(self):
        import stat
        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"))

        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])

        return specs

    @property
    def storage(self):
        if not self._storage:
            import blivet
            self._storage = blivet.Blivet(ksdata=self.ksdata)

            if self.instClass.defaultFS:
                self._storage.setDefaultFSType(self.instClass.defaultFS)

        return self._storage

    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"
        for thread_id, frame in sys._current_frames().iteritems():
            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 = dump_text.encode("utf-8")
        os.write(fd, dump_text)
        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.displayMode == 'g':
            from pyanaconda.ui.gui import GraphicalUserInterface
            self._intf = GraphicalUserInterface(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="gui")
        elif self.displayMode in ['t', 'c']: # text and command line are the same
            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")
        else:
            raise RuntimeError("Unsupported displayMode: %s" % self.displayMode)

        if addon_paths:
            self._intf.update_paths(addon_paths)

    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 = ROOT_PATH
        if not os.path.isdir("%s/etc/X11" %(root,)):
            os.makedirs("%s/etc/X11" %(root,), mode=0755)
        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()
Beispiel #20
0
class Anaconda(object):
    def __init__(self):
        self._display_mode = None
        self._interactive_mode = True
        self.gui_startup_failed = False
        self._intf = None
        self.ksdata = None
        self.methodstr = None
        self.additional_repos = None
        self.opts = None
        self._payload = None
        self.proxy = None
        self.decorated = False
        self._storage = None
        self.mehConfig = 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 = None

    def set_from_opts(self, opts):
        """Load argument to variables from self.opts."""
        self.opts = opts
        self.decorated = opts.decorated
        self.proxy = opts.proxy
        self.methodstr = opts.method
        self.additional_repos = opts.addRepo

    @property
    def dbus_launcher(self):
        if not self._dbus_launcher:
            self._dbus_launcher = AnacondaDBusLauncher()

        return self._dbus_launcher

    @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:
            if self.ksdata.ostreesetup.seen:
                from pyanaconda.payload.rpmostreepayload import RPMOSTreePayload
                klass = RPMOSTreePayload
            elif self.opts.liveinst:
                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

    @staticmethod
    def get_protected_devices(opts):
        specs = []

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

        if opts.stage2 and SourceFactory.is_harddrive(opts.stage2):
            specs.append(opts.stage2[3:].split(":", 3)[0])

        for additional_repo in opts.addRepo:
            _name, repo_url = Anaconda._get_additional_repo_name(additional_repo)
            if SourceFactory.is_harddrive(repo_url):
                specs.append(repo_url[3:].split(":", 3)[0])

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

        return specs

    @staticmethod
    def _get_additional_repo_name(repo):
        try:
            name, rest = repo.split(',', maxsplit=1)
        except ValueError:
            raise RuntimeError("addrepo boot option has incorrect format. Correct format is: "
                               "inst.addrepo=<name>,<url>") from None
        return name, rest

    @property
    def storage(self):
        if not self._storage:
            from pyanaconda.storage.initialization import create_storage
            self._storage = create_storage()

            from pyanaconda.storage.initialization import set_storage_defaults_from_kickstart
            set_storage_defaults_from_kickstart(self._storage)

        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 add_additional_repositories_to_ksdata(self):
        from pyanaconda.kickstart import RepoData

        for add_repo in self.additional_repos:
            name, repo_url = self._get_additional_repo_name(add_repo)
            try:
                source = SourceFactory.parse_repo_cmdline_string(repo_url)
            except PayloadSourceTypeUnrecognized:
                log.error("Type for additional repository %s is not recognized!", add_repo)
                return

            repo = RepoData(name=name, baseurl=repo_url, install=False)

            if source.is_nfs or source.is_http or source.is_https or source.is_ftp \
                    or source.is_file:
                repo.enabled = True
            elif source.is_harddrive:
                repo.enabled = True
                repo.partition = source.partition
                repo.iso_path = source.path
                repo.baseurl = "file://"
            else:
                log.error("Source type %s for additional repository %s is not supported!",
                          source.source_type.value, add_repo)
                continue

            self._check_repo_name_uniqueness(repo)
            self.ksdata.repo.dataList().append(repo)

    def _check_repo_name_uniqueness(self, repo):
        """Log if we are adding repository with already used name

        In automatic kickstart installation this will result in using the first defined repo.
        """
        if repo in self.ksdata.repo.dataList():
            log.warning("Repository name %s is not unique. Only the first repo will be used!",
                        repo.name)

    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")

    @property
    def intf(self):
        """The user interface."""
        return self._intf

    def initInterface(self):
        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,
                                                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)

            # 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)
Beispiel #21
0
class Anaconda(object):
    def __init__(self):
        from pyanaconda import desktop

        self._bootloader = None
        self.canReIPL = False
        self.desktop = desktop.Desktop()
        self.dir = None
        self.displayMode = None
        self.gui_startup_failed = False
        self.id = None
        self._instClass = None
        self._intf = None
        self.isHeadless = False
        self.ksdata = None
        self.mediaDevice = None
        self.methodstr = None
        self.opts = None
        self._payload = None
        self.proxy = None
        self.proxyUsername = None
        self.proxyPassword = None
        self.reIPLMessage = None
        self.rescue_mount = True
        self.rootParts = None

        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()

    @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 DefaultInstall
            self._instClass = DefaultInstall()

        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 packaging 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.packaging.rpmostreepayload import RPMOSTreePayload
                    klass = RPMOSTreePayload
                elif flags.livecdInstall:
                    from pyanaconda.packaging.livepayload import LiveImagePayload
                    klass = LiveImagePayload
                elif self.ksdata.method.method == "liveimg":
                    from pyanaconda.packaging.livepayload import LiveImageKSPayload
                    klass = LiveImageKSPayload
                else:
                    from pyanaconda.packaging.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:
            import blivet
            import blivet.arch

            import gi
            gi.require_version("BlockDev", "1.0")

            from gi.repository import BlockDev as blockdev
            self._storage = blivet.Blivet(ksdata=self.ksdata)

            if self.instClass.defaultFS:
                self._storage.setDefaultFSType(self.instClass.defaultFS)

            if blivet.arch.isS390():
                # want to make sure s390 plugin is loaded
                if "s390" not in blockdev.get_available_plugin_names():
                    plugin = blockdev.PluginSpec()
                    plugin.name = blockdev.Plugin.S390
                    plugin.so_name = None
                    blockdev.reinit([plugin], reload=False)

        return self._storage

    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.displayMode == 'g':
            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)

            # 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.displayMode in ['t', 'c']: # text and command line are the same
            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")
        else:
            raise RuntimeError("Unsupported displayMode: %s" % self.displayMode)

        if addon_paths:
            self._intf.update_paths(addon_paths)

    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 = iutil.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()
Beispiel #22
0
class Anaconda(object):
    def __init__(self):
        self._display_mode = None
        self._interactive_mode = True
        self.gui_startup_failed = False
        self._intf = None
        self.ksdata = None
        self.opts = None
        self._payload = None
        self.mehConfig = 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 = None

    def set_from_opts(self, opts):
        """Load argument to variables from self.opts."""
        self.opts = opts

    @property
    def dbus_launcher(self):
        if not self._dbus_launcher:
            self._dbus_launcher = AnacondaDBusLauncher()

        return self._dbus_launcher

    @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:
            # Get the type of the DBus payload module if any.
            payload_type = self._get_dbus_payload_type()

            if payload_type == PAYLOAD_TYPE_RPM_OSTREE:
                from pyanaconda.payload.rpmostreepayload import RPMOSTreePayload
                payload = RPMOSTreePayload()
            elif self.opts.liveinst:
                from pyanaconda.payload.live import LiveOSPayload
                payload = LiveOSPayload()
            elif payload_type == PAYLOAD_TYPE_LIVE_IMAGE:
                from pyanaconda.payload.live import LiveImagePayload
                payload = LiveImagePayload()
            else:
                from pyanaconda.payload.dnf import DNFPayload
                payload = DNFPayload(self.ksdata)

            self._payload = payload

        return self._payload

    @staticmethod
    def _get_dbus_payload_type():
        payloads_proxy = PAYLOADS.get_proxy()
        object_path = payloads_proxy.ActivePayload

        if not object_path:
            return None

        object_proxy = PAYLOADS.get_proxy(object_path)
        return object_proxy.Type

    @staticmethod
    def get_protected_devices(opts):
        specs = []

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

        if opts.stage2 and SourceFactory.is_harddrive(opts.stage2):
            specs.append(opts.stage2[3:].split(":", 3)[0])

        for _repo_name, repo_url in opts.addRepo:
            if SourceFactory.is_harddrive(repo_url):
                specs.append(repo_url[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 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 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")

    @property
    def intf(self):
        """The user interface."""
        return self._intf

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

        # this boot option is meant to be temporary, so just check it directly
        # from kernel boot command line like this
        if "webui" in kernel_arguments:
            from pyanaconda.ui.webui import CockpitUserInterface
            self._intf = CockpitUserInterface(
                None, self.payload, "webui.remote" in kernel_arguments)

            # needs to be refreshed now we know if gui or tui will take place
            # FIXME - what about Cockpit based addons ?
            addon_paths = []
        elif 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(None,
                                                self.payload,
                                                gui_lock=self.gui_initialized,
                                                fullscreen=False)

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

            # needs to be refreshed now we know if gui or tui will take place
            addon_paths = collect_addon_ui_paths(ADDON_PATHS, "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)
Beispiel #23
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.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 = None

    def set_from_opts(self, opts):
        """Load argument to variables from self.opts."""
        self.opts = opts
        self.decorated = opts.decorated
        self.proxy = opts.proxy
        self.updateSrc = opts.updateSrc
        self.methodstr = opts.method
        self.stage2 = opts.stage2
        self.additional_repos = opts.addRepo

    @property
    def dbus_launcher(self):
        if not self._dbus_launcher:
            self._dbus_launcher = AnacondaDBusLauncher()

        return self._dbus_launcher

    @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:
            if self.ksdata.ostreesetup.seen:
                from pyanaconda.payload.rpmostreepayload import RPMOSTreePayload
                klass = RPMOSTreePayload
            elif self.opts.liveinst:
                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 SourceFactory.is_harddrive(self.methodstr):
            specs.append(self.methodstr[3:].split(":", 3)[0])

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

        for additional_repo in self.additional_repos:
            _name, repo_url = self._get_additional_repo_name(additional_repo)
            if SourceFactory.is_harddrive(repo_url):
                specs.append(repo_url[3:].split(":", 3)[0])

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

        return specs

    @staticmethod
    def _get_additional_repo_name(repo):
        name, rest = repo.split(',', maxsplit=1)
        return name, rest

    @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_storage_defaults(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 add_additional_repositories_to_ksdata(self):
        from pyanaconda.kickstart import RepoData

        for add_repo in self.additional_repos:
            name, repo_url = self._get_additional_repo_name(add_repo)
            try:
                source = SourceFactory.parse_repo_cmdline_string(repo_url)
            except PayloadSourceTypeUnrecognized:
                log.error("Type for additional repository %s is not recognized!", add_repo)
                return

            repo = RepoData(name=name, baseurl=repo_url, install=False)

            if source.is_nfs or source.is_http or source.is_https or source.is_ftp \
                    or source.is_file:
                repo.enabled = True
            elif source.is_harddrive:
                repo.enabled = True
                repo.partition = source.partition
                repo.iso_path = source.path
                repo.baseurl = "file://"
            else:
                log.error("Source type %s for additional repository %s is not supported!",
                          source.source_type.value, add_repo)
                continue

            self._check_repo_name_uniqueness(repo)
            self.ksdata.repo.dataList().append(repo)

    def _check_repo_name_uniqueness(self, repo):
        """Log if we are adding repository with already used name

        In automatic kickstart installation this will result in using the first defined repo.
        """
        if repo in self.ksdata.repo.dataList():
            log.warning("Repository name %s is not unique. Only the first repo will be used!",
                        repo.name)

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

        # Get the default fstype from a kickstart file.
        auto_part_proxy = STORAGE.get_proxy(AUTO_PARTITIONING)

        if auto_part_proxy.Enabled and auto_part_proxy.FilesystemType:
            fstype = auto_part_proxy.FilesystemType
            boot_fstype = 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)

        # Set the default LUKS version.
        luks_version = self.instClass.default_luks_version

        if luks_version:
            storage.set_default_luks_version(luks_version)

        # Set the default partitioning.
        storage.set_default_partitioning(self.instClass.default_partitioning)

    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 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()