yast/yast-installation

View on GitHub
src/lib/installation/clients/inst_system_analysis.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# ------------------------------------------------------------------------------
# Copyright (c) 2006-2012 Novell, Inc. All Rights Reserved.
#
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, contact Novell, Inc.
#
# To contact Novell about this file by physical or electronic mail, you may find
# current contact information at www.novell.com.
# ------------------------------------------------------------------------------

# File:  clients/inst_system_analysis.ycp
# Package:  Installation
# Summary:  Installation mode selection, system analysis
# Authors:  Jiri Srain <jsrain@suse.cz>
#    Lukas Ocilka <locilka@suse.cz>

require "yast"
require "y2storage"
require "y2storage/inhibitors"

module Yast
  class InstSystemAnalysisClient < Client
    include Yast::Logger

    def initialize
      super
      textdomain "installation"
    end

    def main
      Yast.import "UI"

      # Require here to break dependency cycle (bsc#1070996)
      require "autoinstall/activate_callbacks"

      Yast.import "Arch"
      Yast.import "GetInstArgs"
      Yast.import "Hotplug"
      Yast.import "InstData"
      Yast.import "Kernel"
      Yast.import "Packages"
      Yast.import "Popup"
      Yast.import "Product"
      Yast.import "ProductFeatures"
      Yast.import "Progress"
      Yast.import "Report"
      Yast.import "Wizard"
      Yast.import "PackageCallbacks"

      Yast.include self, "installation/misc.rb"
      Yast.include self, "packager/storage_include.rb"
      Yast.include self, "packager/load_release_notes.rb"

      # This dialog in not interactive
      # always return `back when came from the previous dialog
      return :back if GetInstArgs.going_back

      @packager_initialized = false
      @inhibitors = nil

      Wizard.SetContents(_("Analyzing the Computer"), Empty(), "", false, false)

      # Do hardware probing
      #
      # This must happen before submodule descriptions are initialized; module
      # constructors might depend on it.
      # In autoinst mode, this has been called already.

      actions_todo = []
      actions_doing = []
      actions_functions = []

      Builtins.y2milestone("Probing done: %1", Installation.probing_done)
      # skip part of probes as it doesn't change, but some parts (mostly disks
      # that can be activated) need rerun see BNC#865579
      if !Installation.probing_done
        # TRANSLATORS: progress steps in system probing
        if !(Arch.s390 || Arch.board_iseries)
          actions_todo      << _("Probe USB devices")
          actions_doing     << _("Probing USB devices...")
          actions_functions << fun_ref(method(:ActionUSB), "boolean ()")

          actions_todo      << _("Probe FireWire devices")
          actions_doing     << _("Probing FireWire devices...")
          actions_functions << fun_ref(method(:ActionFireWire), "boolean ()")
        end

        WFM.CallFunction("inst_features", [])
      end

      actions_todo      << _("Probe hard disks")
      actions_doing     << _("Probing hard disks...")
      actions_functions << fun_ref(method(:ActionHDDProbe), "boolean ()")

      # FATE #302980: Simplified user config during installation
      actions_todo      << _("Search for system files")
      actions_doing     << _("Searching for system files...")
      actions_functions << fun_ref(method(:FilesFromOlderSystems), "boolean ()")

      # skip the repository initialization on both Online and Full medium,
      # do it only on the standard medium layout (openSUSE Leap)
      skip_software = Mode.update && !Y2Packager::MediumType.standard?
      # we cannot initialize during update software manager until we know target partition
      # as base product is not known
      if !skip_software
        actions_todo      << _("Initialize software manager")
        actions_doing     << _("Initializing software manager...")
        actions_functions << fun_ref(method(:InitInstallationRepositories), "boolean ()")
      end

      Progress.New(
        # TRANSLATORS: dialog caption
        _("System Probing"),
        " ",
        actions_todo.size,
        actions_todo,
        actions_doing,
        # TRANSLATORS: dialog help
        _("YaST is probing computer hardware and installed systems now.")
      )

      actions_functions.each do |run_function|
        Progress.NextStage
        # Bugzilla #298049
        # Allow to abort the probing
        ui_ret = UI.PollInput
        if ui_ret == :abort
          Builtins.y2milestone("Abort pressed")

          if Popup.ConfirmAbort(:painless)
            Builtins.y2warning("User decided to abort the installation")
            return :abort
          end
        end

        begin
          ret = run_function.call
          Builtins.y2milestone("Function %1 returned %2", run_function, ret)
        rescue AbortException
          return :abort
        end

        # Return in case of restart is needed
        return ret if ret == :restart_yast
      end
      Installation.probing_done = true

      Progress.Finish

      return :abort if !skip_software && !@packager_initialized

      :next
    end

    # Function definitions -->

    #  USB initialization
    def ActionUSB
      Hotplug.StartUSB

      true
    end

    # FireWire (ieee1394) initialization
    def ActionFireWire
      Hotplug.StartFireWire

      true
    end

    #  Hard disks initialization
    #
    # @raise [AbortException] if an error is found and the installation must
    #   be aborted because of such error
    def ActionHDDProbe
      inhibit_storage

      init_storage
      devicegraph = storage_manager.probed

      # additonal error when HW was not found
      drivers_info = _(
        "\nCheck 'drivers.suse.com' if you need specific hardware drivers for installation."
      )

      drivers_info = "" if !ProductFeatures.GetBooleanFeature("globals", "show_drivers_info")

      # This error message is only shown when no disks where found during a normal
      # installation. The autoinstallation case will be handled later by AutoYaST at
      # https://github.com/yast/yast-autoinstallation/blob/8e414637d8157462bee5e1ee29c5d2e747754670/src/modules/AutoinstStorage.rb#L334
      if devicegraph.empty? && !Mode.auto
        Report.Error(
          Builtins.sformat(
            # TRANSLATORS: Error pop-up
            _(
              "No hard disks were found for the installation.\n" \
              "Please check your hardware!\n" \
              "%1\n"
            ),
            drivers_info
          )
        )

        return false
      end

      true
    end

    def InitInstallationRepositories
      # disable callbacks
      PackageCallbacks.RegisterEmptyProgressCallbacks

      ret = true

      Packages.InitializeCatalogs

      if Packages.InitFailed
        # popup message
        Popup.Message(
          _("Failed to initialize the software repositories.\nAborting the installation.")
        )
        ret = false
      else
        @packager_initialized = true
        Packages.InitializeAddOnProducts

        # bnc#886608: Adjusting product name (for &product; macro) right after we
        # initialize libzypp and get the base product name (intentionally not translated)
        UI.SetProductName(Product.name || "SUSE Linux")
      end

      # reregister callbacks
      PackageCallbacks.RestorePreviousProgressCallbacks

      ret
    end

    def FilesFromOlderSystems
      # FATE #300421: Import ssh keys from previous installations
      # FATE #120103: Import Users From Existing Partition
      # FATE #302980: Simplified user config during installation
      Builtins.y2milestone("PreInstallFunctions -- start --")
      WFM.CallFunction("inst_pre_install", [])
      Builtins.y2milestone("PreInstallFunctions -- end --")

      true
    end

  private

    # Inhibit various storage features, e.g. MD RAID auto assembly
    def inhibit_storage
      return if @inhibitors

      @inhibitors = Y2Storage::Inhibitors.new
      @inhibitors.inhibit
    end

    # Return the activate callbacks for libstorage-ng
    #
    # When running AutoYaST, it will use a different set of callbacks.
    # Otherwise, it just delegates on yast2-storage-ng which callbacks
    # to use.
    #
    # @return [Storage::ActivateCallbacks,nil] Activate callbacks to use
    #   or +nil+ for default.
    def activate_callbacks
      return nil unless Mode.auto

      Y2Autoinstallation::ActivateCallbacks.new
    end

    # Activates high level devices (RAID, multipath, LVM, encryption...)
    # and (re)probes
    #
    # Reprobing ensures we don't bring bug#806454 back and invalidates cached
    # proposal, so we are also safe from bug#865579.
    #
    # @raise [AbortException] if an error is found and the installation must
    #   be aborted because of such error
    def init_storage
      success = storage_manager.activate(activate_callbacks)
      success &&= storage_manager.probe
      return if success

      log.info "A storage error was raised and the installation must be aborted."
      raise AbortException, "User aborted"
    end

    # @return [Y2Storage::StorageManager]
    def storage_manager
      @storage_manager ||= Y2Storage::StorageManager.instance
    end
  end
end