diff --git a/.travis.yml b/.travis.yml index 7496edc84..b3406ef28 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,4 @@ script: # the "storage-ng-travis-ruby" script is included in the base yastdevel/storage-ng image # see https://github.com/yast/docker-storage-ng/blob/master/storage-ng-travis-ruby - docker run -it -e TRAVIS=1 -e TRAVIS_JOB_ID="$TRAVIS_JOB_ID" yast-bootloader-image storage-ng-travis-ruby + - docker run -it yast-bootloader-image rake check:doc diff --git a/Dockerfile b/Dockerfile index 73b0be3ee..053b8e5e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,2 @@ FROM yastdevel/storage-ng COPY . /usr/src/app - diff --git a/Rakefile b/Rakefile index 08b80f200..8f9b22677 100644 --- a/Rakefile +++ b/Rakefile @@ -8,4 +8,7 @@ Yast::Tasks.configuration do |conf| conf.obs_project = "YaST:storage-ng" # Make sure 'rake osc:sr' fails conf.obs_sr_project = nil + # TODO: improve it, at least do not get worse + # TODO: remove condition when new packaging tasks are accepted to factory + conf.documentation_minimal = 50 if conf.respond_to?(:documentation_minimal=) end diff --git a/package/yast2-bootloader.changes b/package/yast2-bootloader.changes index 87499752d..b260be3c1 100644 --- a/package/yast2-bootloader.changes +++ b/package/yast2-bootloader.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Fri Apr 21 11:28:29 UTC 2017 - jreidinger@suse.com + +- storage-ng: use new wrapper API +- 3.3.7 + +------------------------------------------------------------------- +Thu Apr 13 13:34:12 UTC 2017 - jreidinger@suse.com + +- Add possibility to use trusted boot for EFI (FATE#315831) + ------------------------------------------------------------------- Tue Mar 28 13:32:23 UTC 2017 - jreidinger@suse.com @@ -5,12 +16,32 @@ Tue Mar 28 13:32:23 UTC 2017 - jreidinger@suse.com partition - 3.3.6 +------------------------------------------------------------------- +Fri Mar 24 14:17:00 UTC 2017 - jreidinger@suse.com + +- Report user friendly message when no root partition is detected + instead of internal error. (bsc#1029293) + ------------------------------------------------------------------- Fri Mar 3 15:33:11 CET 2017 - snwint@suse.de - storage-ng: avoid call to old libstorage - 3.3.5 +------------------------------------------------------------------- +Wed Mar 1 17:42:18 UTC 2017 - jreidinger@suse.com + +- provide more helpful error message when invalid arguments for + serial console are provided (bsc#1012383) + +------------------------------------------------------------------- +Wed Mar 1 16:42:18 UTC 2017 - jreidinger@suse.com + +- propose for xen hypervisor vga parameter if framebuffer is used + ( should fix issue with text only environment when fbdev driver + is used ) + (FATE#322200) + ------------------------------------------------------------------- Thu Feb 16 14:47:03 UTC 2017 - ancor@suse.com diff --git a/package/yast2-bootloader.spec b/package/yast2-bootloader.spec index 012dbb747..0d1f5f971 100644 --- a/package/yast2-bootloader.spec +++ b/package/yast2-bootloader.spec @@ -17,7 +17,7 @@ Name: yast2-bootloader -Version: 3.3.6 +Version: 3.3.7 Release: 0 BuildRoot: %{_tmppath}/%{name}-%{version}-build diff --git a/src/lib/bootloader/autoyast_converter.rb b/src/lib/bootloader/autoyast_converter.rb index ab578ad68..e2918845d 100644 --- a/src/lib/bootloader/autoyast_converter.rb +++ b/src/lib/bootloader/autoyast_converter.rb @@ -125,10 +125,10 @@ def import_device_map(data, bootloader) end STAGE1_DEVICES_MAPPING = { - "boot_root" => :RootPartitionDevice, - "boot_boot" => :BootPartitionDevice, + "boot_root" => :root_partition, + "boot_boot" => :boot_partition, "boot_mbr" => :mbr_disk, - "boot_extended" => :ExtendedPartitionDevice + "boot_extended" => :extended_partition }.freeze def import_stage1(data, bootloader) return unless bootloader.name == "grub2" @@ -153,13 +153,13 @@ def import_stage1_devices(data, stage1) # extended partion maybe do not exists, so report it to user if (data["global"]["boot_extended"] == "true" || data["location"] == "extended") && - Yast::BootStorage.ExtendedPartitionDevice.nil? + Yast::BootStorage.extended_partition.nil? raise "boot_extended used in autoyast profile, but there is no extended partition" end STAGE1_DEVICES_MAPPING.each do |key, device| if data["global"][key] == "true" || data["boot_#{key}"] - stage1.add_udev_device(Yast::BootStorage.public_send(device)) + stage1.add_udev_device(Yast::BootStorage.public_send(device).name) end end diff --git a/src/lib/bootloader/boot_record_backup.rb b/src/lib/bootloader/boot_record_backup.rb index b692a0b18..7c3b1e2c5 100644 --- a/src/lib/bootloader/boot_record_backup.rb +++ b/src/lib/bootloader/boot_record_backup.rb @@ -50,7 +50,7 @@ def write # special backup only if device is mbr disk Yast.import "BootStorage" - return if device != Yast::BootStorage.mbr_disk + return if device != Yast::BootStorage.mbr_disk.name copy_br(device, "/boot/backup_mbr") end diff --git a/src/lib/bootloader/config_dialog.rb b/src/lib/bootloader/config_dialog.rb index 0250cf43f..0d702c152 100644 --- a/src/lib/bootloader/config_dialog.rb +++ b/src/lib/bootloader/config_dialog.rb @@ -44,7 +44,7 @@ def guarded_run # F#300779 - Install diskless client (NFS-root) # additional warning that root partition is nfs type -> bootloader will not be installed - device = Yast::BootStorage.disk_with_boot_partition + device = Yast::BootStorage.disk_with_boot_partition.name if device == "/dev/nfs" && Yast::Mode.installation Yast::Popup.Message( diff --git a/src/lib/bootloader/device_map.rb b/src/lib/bootloader/device_map.rb index a54926e91..924ad445f 100644 --- a/src/lib/bootloader/device_map.rb +++ b/src/lib/bootloader/device_map.rb @@ -13,7 +13,6 @@ module Bootloader class DeviceMap extend Forwardable include Yast::Logger - using Y2Storage::Refinements::DevicegraphLists def_delegators :@model, :grub_device_for, :system_device_for, :grub_devices, :add_mapping, :remove_mapping @@ -120,7 +119,7 @@ def order_boot_device # want to modify its MBR. So we get disk of such partition and change order to add it # to top of device map. For details see bnc#887808,bnc#880439 boot_disk = Yast::BootStorage.disk_with_boot_partition - priority_disks = ::Bootloader::Stage1Device.new(boot_disk).real_devices + priority_disks = ::Bootloader::Stage1Device.new(boot_disk.name).real_devices # if none of priority disk is hd0, then choose one and assign it return if any_first_device?(priority_disks) @@ -132,7 +131,7 @@ def fill_mapping # BIOS-ID is not supported in libstorage-ng, so let's simply create a # mapping entry per disk for the time being (see commented code for the # real expected behavior) - staging = Y2Storage::StorageManager.instance.staging + staging = Y2Storage::StorageManager.instance.y2storage_staging staging.disks.each_with_index do |disk, index| add_mapping("hd#{index}", disk.name) end diff --git a/src/lib/bootloader/device_map_dialog.rb b/src/lib/bootloader/device_map_dialog.rb index 8c5f9b5e1..0a1b37163 100644 --- a/src/lib/bootloader/device_map_dialog.rb +++ b/src/lib/bootloader/device_map_dialog.rb @@ -142,7 +142,7 @@ def refresh_disks end def store_order - Yast::BootStorage.mbr_disk = disks.first + Yast::BootStorage.assign_mbr_disk_by_name(disks.first) @device_map.clear_mapping disks.each_with_index do |disk, index| diff --git a/src/lib/bootloader/exceptions.rb b/src/lib/bootloader/exceptions.rb index 16cc4cd78..454ff1a0e 100644 --- a/src/lib/bootloader/exceptions.rb +++ b/src/lib/bootloader/exceptions.rb @@ -25,4 +25,15 @@ def initialize(msg) "Please use YaST2 bootloader to fix it. Details: %s") % msg end end + + # Represents error when serial console arguments are not valid + class InvalidSerialConsoleArguments < BrokenConfiguration + MESSAGE = "Invalid serial console arguments".freeze + def initialize(msg = MESSAGE) + super + end + end + + class NoRoot < RuntimeError + end end diff --git a/src/lib/bootloader/grub2.rb b/src/lib/bootloader/grub2.rb index 96254a74e..86cc2cb0d 100644 --- a/src/lib/bootloader/grub2.rb +++ b/src/lib/bootloader/grub2.rb @@ -17,11 +17,6 @@ module Bootloader class Grub2 < Grub2Base attr_reader :stage1 attr_reader :device_map - # @return [Boolean] - attr_accessor :trusted_boot - - using Y2Storage::Refinements::DevicegraphLists - using Y2Storage::Refinements::Disk def initialize super @@ -30,7 +25,6 @@ def initialize @stage1 = Stage1.new @grub_install = GrubInstall.new(efi: false) @device_map = DeviceMap.new - @trusted_boot = false end # Read settings from disk, overwritting already set values @@ -55,8 +49,6 @@ def read log.info "grub2/device.map does not exist. Using empty one." @device_map = DeviceMap.new end - - @trusted_boot = Sysconfig.from_system.trusted_boot end # Write bootloader settings to disk @@ -89,14 +81,12 @@ def propose # boot, safer option for legacy booting (bnc#872054) self.pmbr_action = :add if Yast::BootStorage.gpt_boot_disk? device_map.propose if Yast::Arch.x86_64 || Yast::Arch.i386 - @trusted_boot = false end def merge(other) super @device_map = other.device_map if !other.device_map.empty? - @trusted_boot = other.trusted_boot unless other.trusted_boot.nil? stage1.merge(other.stage1) end @@ -111,7 +101,7 @@ def summary(simple_mode: false) ), Yast::Builtins.sformat( _("Enable Trusted Boot: %1"), - @trusted_boot ? _("yes") : _("no") + trusted_boot ? _("yes") : _("no") ) ] locations_val = locations @@ -151,7 +141,7 @@ def packages end if Yast::Arch.x86_64 || Yast::Arch.i386 - res << "trustedgrub2" << "trustedgrub2-i386-pc" if @trusted_boot + res << "trustedgrub2" << "trustedgrub2-i386-pc" if trusted_boot end res @@ -160,19 +150,21 @@ def packages # FIXME: refactor with injection like super(prewrite: prewrite, sysconfig = ...) # overwrite BootloaderBase version to save trusted boot def write_sysconfig(prewrite: false) - sysconfig = Bootloader::Sysconfig.new(bootloader: name, trusted_boot: @trusted_boot) + sysconfig = Bootloader::Sysconfig.new(bootloader: name, trusted_boot: trusted_boot) prewrite ? sysconfig.pre_write : sysconfig.write end private def devicegraph - Y2Storage::StorageManager.instance.staging + Y2Storage::StorageManager.instance.y2storage_staging end def gpt_disks_devices boot_devices = stage1.devices - boot_discs = devicegraph.disks.with_name_or_partition(boot_devices) + boot_discs = devicegraph.disks.select do |disk| + boot_devices.any? { |bd| disk.name_or_partition?(bd) } + end gpt_disks = boot_discs.select { |d| d.gpt? } gpt_disks.map { |d| d.name } end @@ -196,12 +188,12 @@ def locations locations << partition_location unless partition_location.empty? if stage1.extended_partition? # TRANSLATORS: extended is here for extended partition. Keep translation short. - locations << Yast::BootStorage.ExtendedPartitionDevice + _(" (extended)") + locations << Yast::BootStorage.extended_partition.name + _(" (extended)") end if stage1.mbr? # TRANSLATORS: MBR is acronym for Master Boot Record, if nothing locally specific # is used in your language, then keep it as it is. - locations << Yast::BootStorage.mbr_disk + _(" (MBR)") + locations << Yast::BootStorage.mbr_disk.name + _(" (MBR)") end locations << stage1.custom_devices if !stage1.custom_devices.empty? @@ -211,10 +203,10 @@ def locations def boot_partition_location if Yast::BootStorage.separated_boot? if stage1.boot_partition? - return Yast::BootStorage.BootPartitionDevice + " (\"/boot\")" + return Yast::BootStorage.boot_partition.name + " (\"/boot\")" end elsif stage1.root_partition? - return Yast::BootStorage.RootPartitionDevice + " (\"/\")" + return Yast::BootStorage.root_partition.name + " (\"/\")" end "" diff --git a/src/lib/bootloader/grub2_widgets.rb b/src/lib/bootloader/grub2_widgets.rb index 528db697a..a46cb2889 100644 --- a/src/lib/bootloader/grub2_widgets.rb +++ b/src/lib/bootloader/grub2_widgets.rb @@ -2,6 +2,7 @@ require "bootloader/generic_widgets" require "bootloader/device_map_dialog" +require "bootloader/serial_console" require "cfa/matcher" Yast.import "BootStorage" @@ -297,13 +298,17 @@ def label def help # TRANSLATORS: TrustedGRUB2 is a name, don't translate it - _("

Trusted Boot will install TrustedGRUB2\n" \ - "instead of regular GRUB2.

\n" \ - "

It means measuring the integrity of the boot process,\n" \ - "with the help from the hardware (a TPM, Trusted Platform Module,\n" \ - "chip).

\n" \ - "

First you need to make sure Trusted Boot is enabled in the BIOS\n" \ - "setup (the setting may be named Security Chip, for example).

\n") + res = _("

Trusted Boot will install TrustedGRUB2\n" \ + "instead of regular GRUB2.

\n" \ + "

It means measuring the integrity of the boot process,\n" \ + "with the help from the hardware (a TPM, Trusted Platform Module,\n" \ + "chip).

\n") + if grub2.name == "grub2" + res += _("

First you need to make sure Trusted Boot is enabled in the BIOS\n" \ + "setup (the setting may be named Security Chip, for example).

\n") + end + + res end def init @@ -315,7 +320,7 @@ def store end def validate - return true if Yast::Mode.config || !value + return true if Yast::Mode.config || !value || grub2.name == "grub2-efi" tpm_files = Dir.glob("/sys/**/pcrs") if !tpm_files.empty? # check for file size does not work, since FS reports it 4096 @@ -460,6 +465,22 @@ def contents ) end + def help + # Translators: do not translate the quoted parts like "unit" + _( + "

When a graphical console is used it allows to use various " \ + "display resolutions. The auto option tries to find " \ + "the best one when booting starts.

\n" \ + "

When a serial console is used the boot output " \ + "will be printed to a serial device like ttyS0. " \ + "At least the --unit option has to be specified, " \ + "and the complete syntax is %s. " \ + "Other parts are optional and if not set, a default is used. " \ + "NUM in commands stands for a positive number like 8. " \ + "Example parameters are serial --speed=38400 --unit=0.

" + ) % syntax + end + def init enable = grub_default.terminal == :serial Yast::UI.ChangeWidget(Id(:console_frame), :Value, enable) @@ -488,6 +509,14 @@ def validate Yast::UI.SetFocus(Id(:console_args)) return false end + if ::Bootloader::SerialConsole.load_from_console_args(console_value).nil? + # Translators: do not translate "unit" + msg = _("To enable the serial console you must provide the corresponding arguments.\n" \ + "The \"unit\" argument is required, the complete syntax is:\n%s") % syntax + Yast::Report.Error(msg) + Yast::UI.SetFocus(Id(:console_args)) + return false + end end true end @@ -533,6 +562,16 @@ def handle(event) private + # Explanation for help and error messages + def syntax + # Translators: NUM is an abbreviation for "number", + # to be substituted in a command like + # "serial --unit=NUM --speed=NUM --parity={odd|even|no} --word=NUM --stop=NUM" + # so do not use punctuation + n = _("NUM") + "serial --unit=#{n} --speed=#{n} --parity={odd|even|no} --word=#{n} --stop=#{n}" + end + def graphical_console_frame CheckBoxFrame( Id(:gfxterm_frame), @@ -568,7 +607,7 @@ def vga_modes_items @vga_modes.sort! do |a, b| res = a["width"] <=> b["width"] - res = a["height"] <=> b["height"] if res == 0 + res = a["height"] <=> b["height"] if res.zero? res end @@ -857,7 +896,11 @@ def secure_boot_widget? end def trusted_boot_widget? - (Yast::Arch.x86_64 || Yast::Arch.i386) && grub2.name == "grub2" + return false if !(Yast::Arch.x86_64 || Yast::Arch.i386) + return true if grub2.name == "grub2" + # for details about grub2 efi trusted boot support see FATE#315831 + return File.exist?("/dev/tpm0") if grub2.name == "grub2-efi" + false end def pmbr_widget? diff --git a/src/lib/bootloader/grub2base.rb b/src/lib/bootloader/grub2base.rb index 886e972af..d6c21acd0 100644 --- a/src/lib/bootloader/grub2base.rb +++ b/src/lib/bootloader/grub2base.rb @@ -3,6 +3,7 @@ require "yast2/execute" require "yast2/target_file" # adds ability to work with cfa in inst-sys require "bootloader/bootloader_base" +require "bootloader/exceptions" require "bootloader/sections" require "bootloader/grub2pwd" require "bootloader/udev_mapping" @@ -42,6 +43,9 @@ class Grub2Base < BootloaderBase attr_accessor :pmbr_action + # @return [Boolean] + attr_accessor :trusted_boot + def initialize super @@ -84,6 +88,8 @@ def read end @sections = ::Bootloader::Sections.new(grub_cfg) log.info "grub sections: #{@sections.all}" + + self.trusted_boot = Sysconfig.from_system.trusted_boot end def write @@ -117,7 +123,9 @@ def propose grub_default.generic_set("SUSE_BTRFS_SNAPSHOT_BOOTING", "true") propose_serial + propose_xen_hypervisor + self.trusted_boot = false nil end @@ -128,11 +136,13 @@ def merge(other) merge_password(other) merge_pmbr_action(other) merge_sections(other) + + self.trusted_boot = other.trusted_boot unless other.trusted_boot.nil? end def enable_serial_console(console) console = SerialConsole.load_from_console_args(console) - raise "Invalid console parameters" unless console + raise ::Bootloader::InvalidSerialConsoleArguments unless console grub_default.serial_console = console.console_args @@ -267,6 +277,14 @@ def propose_serial grub_default.serial_console = console.console_args end + def propose_xen_hypervisor + return if Dir["/dev/fb*"].empty? + + matcher = CFA::Matcher.new(key: "vga") + placer = CFA::ReplacePlacer.new(matcher) + grub_default.xen_hypervisor_params.add_parameter("vga", "gfx-1024x768x16", placer) + end + def propose_resume swap_parts = Yast::BootStorage.available_swap_partitions largest_swap_part = (swap_parts.max_by { |_part, size| size } || [""]).first diff --git a/src/lib/bootloader/grub2efi.rb b/src/lib/bootloader/grub2efi.rb index a6ff8fba2..f99f81c94 100644 --- a/src/lib/bootloader/grub2efi.rb +++ b/src/lib/bootloader/grub2efi.rb @@ -14,7 +14,6 @@ module Bootloader class Grub2EFI < Grub2Base include Yast::Logger attr_accessor :secure_boot - using Y2Storage::Refinements::DevicegraphLists def initialize super @@ -37,13 +36,15 @@ def write super if pmbr_action && Yast::BootStorage.gpt_boot_disk? - efi_partition = filesystems.with_mountpoint("/boot/efi").partitions.first - efi_partition ||= filesystems.with_mountpoint("/boot").partitions.first - efi_partition ||= filesystems.with_mountpoint("/").partitions.first + efi_partition = filesystems.find { |f| f.mountpoint == "/boot/efi" } + efi_partition ||= filesystems.find { |f| f.mountpoint == "/boot" } + efi_partition ||= filesystems.find { |f| f.mountpoint == "/" } raise "could not find boot partiton" unless efi_partition - efi_disk = efi_partition.partitionable + efi_partition = efi_partition.plain_blk_devices.first + + efi_disk = efi_partition.disk # storage-ng # rubocop:disable Style/BlockComments @@ -55,7 +56,7 @@ def write pmbr_setup(efi_disk.name) end - @grub_install.execute(secure_boot: @secure_boot) + @grub_install.execute(secure_boot: @secure_boot, trusted_boot: trusted_boot) true end @@ -88,6 +89,10 @@ def summary(*) Yast::Builtins.sformat( _("Enable Secure Boot: %1"), @secure_boot ? _("yes") : _("no") + ), + Yast::Builtins.sformat( + _("Enable Trusted Boot: %1"), + trusted_boot ? _("yes") : _("no") ) ] end @@ -118,7 +123,8 @@ def packages # overwrite BootloaderBase version to save secure boot def write_sysconfig(prewrite: false) - sysconfig = Bootloader::Sysconfig.new(bootloader: name, secure_boot: @secure_boot) + sysconfig = Bootloader::Sysconfig.new(bootloader: name, + secure_boot: @secure_boot, trusted_boot: trusted_boot) prewrite ? sysconfig.pre_write : sysconfig.write end @@ -128,7 +134,7 @@ def write_sysconfig(prewrite: false) # # @return [Y2Storage::FilesystemsList] def filesystems - staging = Y2Storage::StorageManager.instance.staging + staging = Y2Storage::StorageManager.instance.y2storage_staging staging.filesystems end end diff --git a/src/lib/bootloader/grub_install.rb b/src/lib/bootloader/grub_install.rb index 4478943f4..c921d906c 100644 --- a/src/lib/bootloader/grub_install.rb +++ b/src/lib/bootloader/grub_install.rb @@ -12,7 +12,6 @@ def initialize(efi: false) def execute(devices: [], secure_boot: false, trusted_boot: false) raise "cannot have secure boot without efi" if secure_boot && !efi - raise "cannot have trusted boot with efi" if trusted_boot && efi cmd = basic_cmd(secure_boot, trusted_boot) @@ -37,7 +36,10 @@ def basic_cmd(secure_boot, trusted_boot) # Do skip-fs-probe to avoid error when embedding stage1 # to extended partition cmd << "--force" << "--skip-fs-probe" - cmd << "--directory=/usr/lib/trustedgrub2/#{target}" if trusted_boot + end + + if trusted_boot + cmd << (efi ? "--suse-enable-tpm" : "--directory=/usr/lib/trustedgrub2/#{target}") end cmd << "--no-nvram" << "--removable" if removable_efi? diff --git a/src/lib/bootloader/mbr_update.rb b/src/lib/bootloader/mbr_update.rb index c4b0f0137..9e62aeffc 100644 --- a/src/lib/bootloader/mbr_update.rb +++ b/src/lib/bootloader/mbr_update.rb @@ -14,8 +14,6 @@ module Bootloader # FIXME: make it single responsibility class class MBRUpdate include Yast::Logger - using Y2Storage::Refinements::DevicegraphLists - using Y2Storage::Refinements::Disk # Update contents of MBR (active partition and booting code) def run(stage1) @@ -34,11 +32,11 @@ def run(stage1) private def devicegraph - Y2Storage::StorageManager.instance.staging + Y2Storage::StorageManager.instance.y2storage_staging end def mbr_disk - @mbr_disk ||= Yast::BootStorage.mbr_disk + @mbr_disk ||= Yast::BootStorage.mbr_disk.name end def create_backups @@ -52,7 +50,7 @@ def create_backups end def gpt?(disk) - mbr_storage_object = devicegraph.disks.with(name: disk).first + mbr_storage_object = devicegraph.disks.find { |d| d.name == disk } raise "Cannot find in storage mbr disk #{disk}" unless mbr_storage_object mbr_storage_object.gpt? end @@ -182,13 +180,11 @@ def activatable_partitions(disk) # do not select swap and do not select BIOS grub partition # as it clear its special flags (bnc#894040) - devicegraph.disks.with(name: disk.name).partitions.reject do |part| - [Storage::ID_SWAP, Storage::ID_BIOS_BOOT].include?(part.id) - end + disk.partitions.reject { |p| p.id.is?(:swap, :bios_boot) } end def extended_partition(disk) - part = activatable_partitions(disk).find { |p| p.type == Storage::PartitionType_EXTENDED } + part = activatable_partitions(disk).find { |p| p.type == Y2Storage::PartitionType::EXTENDED } return nil unless part log.info "Using extended partition instead: #{part.inspect}" @@ -229,18 +225,17 @@ def partition_to_activate(loader_device) end def partition_and_disk_to_activate(dev_name) - parts = devicegraph.partitions.with(name: dev_name) - partition = parts.first - mbr_dev = parts.disks.first - - # if real_device is not a partition but a disk - if !partition - mbr_dev = devicegraph.disks.with(name: dev_name).first + device = Y2Storage::BlkDevice.find_by_name(devicegraph, dev_name) + if device.is?(:disk) + mbr_dev = device # (bnc # 337742) - Unable to boot the openSUSE (32 and 64 bits) after installation # if loader_device is disk Choose any partition which is not swap to # satisfy such bios (bnc#893449) partition = activatable_partitions(mbr_dev).first log.info "loader_device is disk device, so use its partition #{partition.inspect}" + else + partition = device + mbr_dev = device.disk end [partition, mbr_dev] end diff --git a/src/lib/bootloader/proposal_client.rb b/src/lib/bootloader/proposal_client.rb index 47f3dfe2f..5cb417ba0 100644 --- a/src/lib/bootloader/proposal_client.rb +++ b/src/lib/bootloader/proposal_client.rb @@ -1,4 +1,5 @@ require "installation/proposal_client" +require "bootloader/exceptions" require "bootloader/main_dialog" require "bootloader/bootloader_factory" @@ -35,6 +36,8 @@ def make_proposal(attrs) force_reset = attrs["force_reset"] auto_mode = Yast::Mode.autoinst || Yast::Mode.autoupgrade + Yast::BootStorage.detect_disks + if (force_reset || !Yast::Bootloader.proposed_cfg_changed) && !auto_mode # force re-calculation of bootloader proposal @@ -61,6 +64,12 @@ def make_proposal(attrs) Yast::PackagesProposal.AddResolvables("yast2-bootloader", :package, bl.packages) construct_proposal_map + rescue ::Bootloader::NoRoot + { + "label_proposal" => [], + "warning_level" => :fatal, + "warning" => _("Cannot detect device mounted as root. Please check partitioning.") + } end def ask_user(param) @@ -156,7 +165,7 @@ def construct_proposal_map # F#300779 - Install diskless client (NFS-root) # kokso: bootloader will not be installed - device = Yast::BootStorage.disk_with_boot_partition + device = Yast::BootStorage.disk_with_boot_partition.name log.info "Type of BootPartitionDevice: #{device}" if device == "/dev/nfs" log.info "Boot partition is nfs type, bootloader will not be installed." diff --git a/src/lib/bootloader/stage1.rb b/src/lib/bootloader/stage1.rb index 6a7e562bd..14d884bd9 100644 --- a/src/lib/bootloader/stage1.rb +++ b/src/lib/bootloader/stage1.rb @@ -17,7 +17,6 @@ module Bootloader class Stage1 extend Forwardable include Yast::Logger - using Y2Storage::Refinements::DevicegraphLists attr_reader :model def_delegators :@model, :generic_mbr?, :generic_mbr=, :activate?, :activate=, :devices, @@ -75,7 +74,7 @@ def clear_devices def boot_partition? if !@boot_partition_device - dev = Yast::BootStorage.BootPartitionDevice + dev = Yast::BootStorage.boot_partition.name kernel_dev = Bootloader::UdevMapping.to_kernel_device(dev) @boot_partition_device = ::Bootloader::Stage1Device.new(kernel_dev) @@ -86,7 +85,7 @@ def boot_partition? def root_partition? if !@root_partition_device - dev = Yast::BootStorage.RootPartitionDevice + dev = Yast::BootStorage.root_partition.name kernel_dev = Bootloader::UdevMapping.to_kernel_device(dev) @root_partition_device = ::Bootloader::Stage1Device.new(kernel_dev) @@ -97,7 +96,7 @@ def root_partition? def mbr? if !@mbr_device - dev = Yast::BootStorage.mbr_disk + dev = Yast::BootStorage.mbr_disk.name kernel_dev = Bootloader::UdevMapping.to_kernel_device(dev) @mbr_device = ::Bootloader::Stage1Device.new(kernel_dev) @@ -107,10 +106,10 @@ def mbr? end def extended_partition? - return false unless Yast::BootStorage.ExtendedPartitionDevice + return false unless Yast::BootStorage.extended_partition if !@extended_partition_device - dev = Yast::BootStorage.ExtendedPartitionDevice + dev = Yast::BootStorage.extended_partition.name kernel_dev = Bootloader::UdevMapping.to_kernel_device(dev) @extended_partition_device = ::Bootloader::Stage1Device.new(kernel_dev) @@ -121,13 +120,13 @@ def extended_partition? def custom_devices known_devices = [ - Yast::BootStorage.BootPartitionDevice, - Yast::BootStorage.RootPartitionDevice, + Yast::BootStorage.boot_partition, + Yast::BootStorage.root_partition, Yast::BootStorage.mbr_disk, - Yast::BootStorage.ExtendedPartitionDevice + Yast::BootStorage.extended_partition ] - known_devices.compact! - known_devices.map! { |d| Bootloader::UdevMapping.to_kernel_device(d) } + known_devices.compact! # extended partition can be nil + known_devices.map! { |d| Bootloader::UdevMapping.to_kernel_device(d.name) } devices.select do |dev| !known_devices.include?(Bootloader::UdevMapping.to_kernel_device(dev)) @@ -149,7 +148,7 @@ def available_locations case Yast::Arch.architecture when "i386", "x86_64" res = available_partitions - res[:mbr] = Yast::BootStorage.mbr_disk + res[:mbr] = Yast::BootStorage.mbr_disk.name return res else @@ -160,23 +159,20 @@ def available_locations end def can_use_boot? - partition = Yast::BootStorage.BootPartitionDevice + part = Yast::BootStorage.boot_partition - parts = partitions.with(name: partition) - - if parts.empty? - log.error "cannot find partition #{partition}" + if !part + log.error "boot partition is not assigned" return false end - log.info "Boot partition info #{parts.first.inspect}" + log.info "Boot partition info #{part.inspect}" # cannot install stage one to xfs as it doesn't have reserved space (bnc#884255) - fs = parts.filesystems.first - return false if fs && fs.type == ::Storage::FsType_XFS + return false if part.filesystem_type == ::Y2Storage::Filesystems::Type::XFS # LVM partition does not have reserved space for stage one - return false if staging.lvm_vgs.partitions.with(name: partition).any? + return false if part.lvm_pv true end @@ -216,7 +212,7 @@ def partitions end def staging - Y2Storage::StorageManager.instance.staging + Y2Storage::StorageManager.instance.y2storage_staging end def include_real_devs?(real_devs) @@ -232,13 +228,13 @@ def available_partitions res = {} if Yast::BootStorage.separated_boot? - res[:boot] = Yast::BootStorage.BootPartitionDevice + res[:boot] = Yast::BootStorage.boot_partition.name else - res[:root] = Yast::BootStorage.RootPartitionDevice + res[:root] = Yast::BootStorage.root_partition.name end if extended_partition? - res[:extended] = Yast::BootStorage.ExtendedPartitionDevice + res[:extended] = Yast::BootStorage.extended_partition.name end res diff --git a/src/lib/bootloader/stage1_device.rb b/src/lib/bootloader/stage1_device.rb index 11d85e0c0..115914f10 100644 --- a/src/lib/bootloader/stage1_device.rb +++ b/src/lib/bootloader/stage1_device.rb @@ -15,7 +15,6 @@ module Bootloader # puts dev.real_devices # => ["/dev/sda1", "/dev/sdb1"] class Stage1Device include Yast::Logger - using Y2Storage::Refinements::DevicegraphLists # @param [String] device intended location of stage1. Device here # means any name under /dev like "/dev/sda", "/dev/system/root" or @@ -40,7 +39,7 @@ def real_devices private def devicegraph - Y2Storage::StorageManager.instance.staging + Y2Storage::StorageManager.instance.y2storage_staging end # underlaying_devices without any caching @@ -57,6 +56,11 @@ def underlaying_devices_for(dev) res.uniq end + def pv_disk(vg) + pvs = usable_pvs(vg) + pvs.map { |p| p.ancestors.find { |a| a.is?(:disk) }.name } + end + # get one level of underlaying devices, so no recursion deeper def underlaying_devices_one_level(dev) # FIXME: there is nothing like this right now in libstorage-ng @@ -64,18 +68,12 @@ def underlaying_devices_one_level(dev) # revisit when such thing exist match = /^\/dev\/(\w+)$/.match(dev) if match && match[1] - vgs = devicegraph.volume_groups.with(vg_name: match[1]) - return usable_pvs(vgs).disks.map(&:name) unless vgs.empty? + vg = devicegraph.lvm_vgs.find { |v| v.vg_name == match[1] } + return pv_disk(vg) if vg end - # FIXME: there is nothing like this right now in libstorage-ng - # a_lv.name #=> "/dev/vgname/lvname" - # revisit when such thing exist - match = /^\/dev\/\w+\/(\w+)$/.match(dev) - if match && match[1] - lvs = devicegraph.logical_volumes.with(lv_name: match[1]) - return usable_pvs(lvs.vgs).map { |pv| pv.blk_device.name } unless lvs.empty? - end + lvs = devicegraph.lvm_lvs.find { |v| v.name == dev } + return usable_pvs(lvs.lvm_vg).map { |v| v.blk_device.name } if lvs && lvs.lvm_vg # TODO: storage-ng # md @@ -102,18 +100,17 @@ def underlaying_devices_one_level(dev) # # Ignores physical volumes on a whole disk. See bnc#980529 # - # @param volumes_group_list [Y2Storage::LvmVgsList] - # @return [Y2Storage::LvmPvsList] - def usable_pvs(volume_groups_list) - pvs = volume_groups_list.physical_volumes - pvs.with { |pv| !Storage.disk?(pv.blk_device) } + # @param volume_group [Y2Storage::LvmVg] + # @return [Array] + def usable_pvs(volume_group) + volume_group.lvm_pvs.reject { |pv| pv.plain_blk_device.is?(:disk) } end # For pure virtual disk devices it is selected /boot partition and its # underlaying devices then for it select on which disks it lives. So result # is disk which contain partition holding /boot. def underlaying_disk_with_boot_partition - underlaying_devices_for(Yast::BootStorage.BootPartitionDevice).map do |part| + underlaying_devices_for(Yast::BootStorage.boot_partition.name).map do |part| disk_dev = Yast::Storage.GetDiskPartition(part) disk_dev["disk"] end diff --git a/src/lib/bootloader/stage1_proposal.rb b/src/lib/bootloader/stage1_proposal.rb index e133acfa4..064bd181c 100644 --- a/src/lib/bootloader/stage1_proposal.rb +++ b/src/lib/bootloader/stage1_proposal.rb @@ -30,6 +30,13 @@ def initialize(stage1) @stage1 = stage1 end + DEVICE_MAPPING = { + root: :root_partition, + boot: :boot_partition, + extended: :extended_partition, + mbr: :mbr_disk + }.freeze + # Set "boot_*" flags in the globals map according to the boot device selected # with parameter selected_location. Only a single boot device can be selected # with this function. The function cannot be used to set a custom boot device. @@ -48,10 +55,9 @@ def assign_bootloader_device(selected_location) stage1.clear_devices case selected_location - when :root then stage1.add_udev_device(Yast::BootStorage.RootPartitionDevice) - when :boot then stage1.add_udev_device(Yast::BootStorage.BootPartitionDevice) - when :extended then stage1.add_udev_device(extended_partition) - when :mbr then stage1.add_udev_device(Yast::BootStorage.mbr_disk) + when :root, :boot, :extended, :mbr + device = Yast::BootStorage.public_send(DEVICE_MAPPING[selected_location]) + stage1.add_udev_device(device.name) when :none then log.info "Resetting bootloader device" when Array if selected_location.first != :custom @@ -66,8 +72,6 @@ def assign_bootloader_device(selected_location) # x86_64 specific stage1 proposal class X64 < Stage1Proposal - using Y2Storage::Refinements::DevicegraphLists - def propose selected_location = propose_boot_location log.info "propose_x86 (#{selected_location})" @@ -82,7 +86,7 @@ def propose # partition can remain activated, which causes less problems with # other installed OSes like Windows (older versions assign the C: # drive letter to the activated partition). - used_disks = ::Bootloader::Stage1Device.new(Yast::BootStorage.mbr_disk).real_devices + used_disks = ::Bootloader::Stage1Device.new(Yast::BootStorage.mbr_disk.name).real_devices stage1.activate = used_disks.none? { |d| any_boot_flag_partition?(d) } stage1.generic_mbr = false else @@ -96,17 +100,17 @@ def propose private def any_boot_flag_partition?(disk_name) - disks = devicegraph.disks.with(name: disk_name) - return false unless disks.first.has_partition_table + disk = devicegraph.disks.find { |d| d.name == disk_name } + return false unless disk.partition_table - legacy_boot = disks.first.partition_table.partition_legacy_boot_flag_supported? - disks.partitions.any? do |p| + legacy_boot = disk.partition_table.partition_legacy_boot_flag_supported? + disk.partitions.any? do |p| legacy_boot ? p.legacy_boot? : p.boot? end end def devicegraph - Y2Storage::StorageManager.instance.staging + Y2Storage::StorageManager.instance.y2storage_staging end def propose_boot_location @@ -117,7 +121,7 @@ def propose_boot_location # see bug #279837 comment #53 selected_location = separated_boot? ? :boot : :root if boot_partition_on_mbr_disk? - if logical_boot? && extended_partition + if logical_boot? && Yast::BootStorage.extended_partition log.info "/boot is on logical partition and extended detected, extended proposed" selected_location = :extended end @@ -142,12 +146,6 @@ def separated_boot? Yast::BootStorage.separated_boot? end - def extended_partition - init_boot_info unless @boot_initialized - - @extended - end - def logical_boot? init_boot_info unless @boot_initialized @@ -164,26 +162,23 @@ def init_boot_info return if @boot_initialized @boot_initialized = true - boot_part = devicegraph.partitions.with(name: Yast::BootStorage.BootPartitionDevice).first - @logical_boot = boot_part.type == Storage::PartitionType_LOGICAL + boot_part = Yast::BootStorage.boot_partition + @logical_boot = boot_part.type.is?(:logical) @boot_with_btrfs = with_btrfs?(boot_part) # check for sure also underlaying partitions - disk_name = Yast::BootStorage.disk_with_boot_partition - devicegraph.disks.with(name: disk_name).partitions.each do |p| - @extended = p.name if p.type == Storage::PartitionType_EXTENDED + Yast::BootStorage.disk_with_boot_partition.partitions.each do |p| next unless underlaying_boot_partition_devices.include?(p.name) @boot_with_btrfs = with_btrfs?(p) - @logical_boot = true if p.type == Storage::PartitionType_LOGICAL + @logical_boot = true if p.type.is?(:logical) end end def with_btrfs?(partition) - partition.filesystem.type == ::Storage::FsType_BTRFS - rescue Storage::WrongNumberOfChildren, Storage::DeviceHasWrongType - # No filesystem in the partition - false + type = partition.filesystem_type + return false unless type + type.is?(:btrfs) end # determine the underlaying devices for the "/boot" partition (either the @@ -191,13 +186,13 @@ def with_btrfs?(partition) # "/boot" is built) def underlaying_boot_partition_devices @underlaying_boot_partition_devices ||= - ::Bootloader::Stage1Device.new(Yast::BootStorage.BootPartitionDevice).real_devices + ::Bootloader::Stage1Device.new(Yast::BootStorage.boot_partition.name).real_devices end def boot_partition_on_mbr_disk? underlaying_boot_partition_devices.any? do |dev| - disk = devicegraph.disks.with_name_or_partition(dev).first - disk && disk.name == Yast::BootStorage.mbr_disk + disk = devicegraph.disks.find { |d| d.name_or_partition?(dev) } + disk == Yast::BootStorage.mbr_disk end end end @@ -229,7 +224,8 @@ def propose # and raise exception. # powernv do not have prep partition, so we do not have any partition # to activate (bnc#970582) - elsif Yast::BootStorage.disk_with_boot_partition == "/dev/nfs" || Yast::Arch.board_powernv + elsif Yast::BootStorage.disk_with_boot_partition.name == "/dev/nfs" || + Yast::Arch.board_powernv stage1.activate = false stage1.generic_mbr = false return @@ -255,7 +251,7 @@ def proposed_prep_partition same_disk_part = partitions.find do |part| disk = Yast::Storage.GetDiskPartition(part)["disk"] - Yast::BootStorage.disk_with_boot_partition == disk + Yast::BootStorage.disk_with_boot_partition.name == disk end if same_disk_part diff --git a/src/modules/BootStorage.rb b/src/modules/BootStorage.rb index cb1b1c3e5..7b27bf9b5 100644 --- a/src/modules/BootStorage.rb +++ b/src/modules/BootStorage.rb @@ -21,14 +21,24 @@ require "storage" require "y2storage" require "bootloader/udev_mapping" +require "bootloader/exceptions" module Yast class BootStorageClass < Module include Yast::Logger - using Y2Storage::Refinements::DevicegraphLists - using Y2Storage::Refinements::Disk - attr_accessor :mbr_disk + # Disk where to place MBR code. By default one with /boot partition + # @return [Y2Storage::Disk] + attr_reader :mbr_disk + # Partition where lives /boot. If there is not separated /boot, / is used instead. + # @return [Y2Storage::Partition] + attr_reader :boot_partition + # Partition where / lives. + # @return [Y2Storage::Partition] + attr_reader :root_partition + # Extended partition on same disk as /boot, nil if there is none + # @return [Y2Storage::Partition, nil] + attr_reader :extended_partition def main textdomain "bootloader" @@ -36,16 +46,6 @@ def main Yast.import "Arch" Yast.import "Mode" - # string sepresenting device name of /boot partition - # same as RootPartitionDevice if no separate /boot partition - @BootPartitionDevice = "" - - # string representing device name of / partition - @RootPartitionDevice = "" - - # string representing device name of extended partition - @ExtendedPartitionDevice = "" - # FATE#305008: Failover boot configurations for md arrays with redundancy # list includes physical disks used for md raid @@ -53,7 +53,11 @@ def main end def staging - Y2Storage::StorageManager.instance.staging + Y2Storage::StorageManager.instance.y2storage_staging + end + + def assign_mbr_disk_by_name(dev_name) + @mbr_disk = staging.disks.find { |d| d.name == dev_name } end def gpt_boot_disk? @@ -66,7 +70,7 @@ def gpt_boot_disk? return false unless current_bl.respond_to?(:stage1) targets = current_bl.stage1.devices - boot_disks = staging.disks.with_name_or_partition(targets) + boot_disks = staging.disks.select { |d| targets.any? { |t| d.name_or_partition?(t) } } boot_disks.any? { |disk| disk.gpt? } end @@ -109,11 +113,10 @@ def possible_locations_for_stage1 # Get extended partition for given partition or disk def extended_partition_for(device) - disk_list = staging.disks.with_name_or_partition(device) - return nil if disk_list.empty? + disk = staging.disks.find { |d| d.name_or_partition?(device) } + return nil unless disk - part = disk_list.partitions.with(type: Storage::PartitionType_EXTENDED).first - part ? part.name : nil + disk.partitions.find { |p| p.type.is?(:extended) } end # FIXME: merge with BootSupportCheck @@ -130,9 +133,9 @@ def bootloader_installable? detect_disks Builtins.y2milestone( "Boot partition device: %1", - BootStorage.BootPartitionDevice + BootStorage.boot_partition.inspect ) - dev = Storage.GetDiskPartition(BootStorage.BootPartitionDevice) + dev = Storage.GetDiskPartition(BootStorage.boot_partition.name) Builtins.y2milestone("Disk info: %1", dev) # MD, but not mirroring is OK # FIXME: type detection by name deprecated @@ -143,7 +146,7 @@ def bootloader_installable? info = {} Builtins.foreach(parts) do |p| if Ops.get_string(p, "device", "") == - BootStorage.BootPartitionDevice + BootStorage.boot_partition.name info = deep_copy(p) end end @@ -156,7 +159,7 @@ def bootloader_installable? # EVMS # FIXME: type detection by name deprecated - elsif Builtins.search(BootPartitionDevice(), "/dev/evms/") == 0 + elsif Builtins.search(boot_partition.name, "/dev/evms/") == 0 Builtins.y2milestone("Cannot install bootloader on EVMS") return false end @@ -173,21 +176,21 @@ def bootloader_installable? # If the filesystem is in a virtual device (like a LUKS or LVM volume), it # returns the (first) underlying partition or disk. def find_blk_device_at_mountpoint(mountpoint) - fses = staging.filesystems.with_mountpoint(mountpoint) - return nil if fses.empty? + fs = staging.filesystems.find { |f| f.mountpoint == mountpoint } + return nil unless fs + + part = fs.ancestors.find { |a| a.is?(:partition) } + return part if part - partitions = fses.partitions - partitions = fses.lvm_vgs.partitions if partitions.empty? - return partitions.first unless partitions.empty? + disk = fs.ancestors.find { |a| a.is?(:disk) } + return disk if disk - disks = fses.disks - disks = fses.lvm_vgs.disks if disks.empty? - disks.first + nil end # Sets properly boot, root and mbr disk. def detect_disks - return unless @RootPartitionDevice.empty? # quit if already detected + return if root_partition # quit if already detected # While calling "yast clone_system" and while cloning bootloader # in the AutoYaST module, libStorage has to be set to "normal" # mode in order to read mountpoints correctly. @@ -203,28 +206,28 @@ def detect_disks # The AutoYaST config mode does access to the system. # bnc#942360 - root_blk_device = find_blk_device_at_mountpoint("/") + @root_partition = find_blk_device_at_mountpoint("/") + raise ::Bootloader::NoRoot, "Missing '/' mount point" unless @root_partition - boot_blk_device = find_blk_device_at_mountpoint("/boot") - boot_blk_device = root_blk_device if !boot_blk_device + @boot_partition = find_blk_device_at_mountpoint("/boot") + @boot_partition ||= @root_partition - # TODO: @RootPartitionDevice and @BootPartitionDevice should be the - # BlkDevice object itself not its name - - @RootPartitionDevice = root_blk_device.name - @BootPartitionDevice = boot_blk_device.name - - log.info "RootPartitionDevice #{@RootPartitionDevice}" - log.info "BootPartitionDevice #{@BootPartitionDevice}" + log.info "root partition #{root_partition.inspect}" + log.info "boot partition #{boot_partition.inspect}" # get extended partition device (if exists) - @ExtendedPartitionDevice = extended_partition_for(@BootPartitionDevice) + @extended_partition = extended_partition_for(boot_partition) @mbr_disk = disk_with_boot_partition Mode.SetMode(old_mode) if old_mode == "autoinst_config" end + # resets disk configuration. Clears cache from #detect_disks + def reset_disks + @boot_partition = @root_partition = @mbr_disk = @extended_partition = nil + end + def prep_partitions target_map = Storage.GetTargetMap @@ -241,18 +244,15 @@ def prep_partitions end def disk_with_boot_partition - boot_device = BootPartitionDevice() - - partition = Storage::Partition.find_by_name(staging, boot_device) - partitionable = partition.partition_table.partitionable + disk = boot_partition.disk - log.info "Boot device - disk: #{partitionable.name}" + log.info "Boot device - disk: #{disk}" - partitionable.name + disk end def separated_boot? - BootPartitionDevice() != RootPartitionDevice() + boot_partition != root_partition end # Get map of swap partitions @@ -260,7 +260,7 @@ def separated_boot? def available_swap_partitions ret = {} - Storage::Swap.all(staging).each do |swap| + staging.filesystems.select { |f| f.type.is?(:swap) }.each do |swap| blk_device = swap.blk_devices[0] ret[blk_device.name] = blk_device.size / 1024 end @@ -309,18 +309,16 @@ def crypto_devices end def encrypted_boot? - dev = BootPartitionDevice() - log.info "boot device = #{dev}" - result = !!crypto_devices[dev] + dev = boot_partition + log.info "boot device = #{dev.inspect}" + # storage-ng + dev_name = dev ? dev.name : "" # FIXME this should not happen + result = !!crypto_devices[dev_name] log.info "encrypted_boot? = #{result}" result end - - publish :variable => :BootPartitionDevice, :type => "string" - publish :variable => :RootPartitionDevice, :type => "string" - publish :variable => :ExtendedPartitionDevice, :type => "string" end BootStorage = BootStorageClass.new diff --git a/src/modules/BootSupportCheck.rb b/src/modules/BootSupportCheck.rb index 58804826b..da26db173 100644 --- a/src/modules/BootSupportCheck.rb +++ b/src/modules/BootSupportCheck.rb @@ -19,8 +19,6 @@ module Yast class BootSupportCheckClass < Module include Yast::Logger - using Y2Storage::Refinements::DevicegraphLists - using Y2Storage::Refinements::Disk def main textdomain "bootloader" @@ -103,11 +101,11 @@ def correct_loader_type(lt) def check_gpt_reserved_partition return true unless stage1.mbr? - disk = staging.disks.with(name: BootStorage.mbr_disk).first - boot_device = staging.partitions.with(name: BootStorage.BootPartitionDevice).first + disk = BootStorage.mbr_disk + boot_device = BootStorage.boot_partition return true unless disk.gpt? - return true if !boot_device.has_filesystem || boot_device.filesystem.type != ::Storage::FsType_BTRFS - return true if disk.partitions.any? { |p| p.partition_id == ::Storage::ID_BIOS_BOOT } + return true if boot_device.filesystem_type != ::Y2Storage::Filesystems::Type::BTRFS + return true if disk.partitions.any? { |p| p.id.is?(:bios_boot) } Builtins.y2error("Used together boot from MBR, gpt, btrfs and without bios_grub partition.") # TRANSLATORS: description of technical problem. Do not translate technical terms unless native language have well known translation. @@ -132,7 +130,7 @@ def check_boot_device =begin devices = Storage.GetTargetMap - boot_device = BootStorage.BootPartitionDevice + boot_device = BootStorage.boot_partition.name # FIXME: big part of this method should be in BootStorage # check if boot device is on raid0 @@ -201,9 +199,9 @@ def check_activate_partition return true if stage1.activate? # there is already activate flag - disks = staging.disks.with(name: Yast::BootStorage.mbr_disk) - if disks.first.has_partition_table - legacy_boot = disks.first.partition_table.partition_legacy_boot_flag_supported? + disk = Yast::BootStorage.mbr_disk + if disk.partition_table + legacy_boot = disk.partition_table.partition_legacy_boot_flag_supported? return true if disks.partitions.any? { |p| legacy_boot ? p.legacy_boot? : p.boot? } end @@ -242,7 +240,7 @@ def stage1 end def staging - Y2Storage::StorageManager.instance.staging + Y2Storage::StorageManager.instance.y2bootloader_staging end end diff --git a/src/modules/Bootloader.rb b/src/modules/Bootloader.rb index 5846e750e..62d6c498d 100644 --- a/src/modules/Bootloader.rb +++ b/src/modules/Bootloader.rb @@ -204,7 +204,7 @@ def Propose # @return a list of summary lines def Summary(simple_mode: false) # kokso: additional warning that root partition is nfs type -> bootloader will not be installed - if BootStorage.disk_with_boot_partition == "/dev/nfs" + if BootStorage.disk_with_boot_partition.name == "/dev/nfs" log.info "Bootloader::Summary() -> Boot partition is nfs type, bootloader will not be installed." return _("The boot partition is of type NFS. Bootloader cannot be installed.") end diff --git a/test/autoyast_converter_test.rb b/test/autoyast_converter_test.rb index edd78fb2d..cb36da5ea 100644 --- a/test/autoyast_converter_test.rb +++ b/test/autoyast_converter_test.rb @@ -95,6 +95,13 @@ describe ".export" do let(:bootloader) { Bootloader::Grub2.new } + + before do + devicegraph_stub("storage_lvm.yaml") + # FIXME: not needed when switched to lazy loading + Yast::BootStorage.detect_disks + end + it "export loader type" do expect(subject.export(bootloader)["loader_type"]).to eq "grub2" end diff --git a/test/boot_record_backup_test.rb b/test/boot_record_backup_test.rb index 19f7d1d31..14eb94e7b 100644 --- a/test/boot_record_backup_test.rb +++ b/test/boot_record_backup_test.rb @@ -14,6 +14,10 @@ subject { Bootloader::BootRecordBackup.new("/dev/sda") } + before do + allow(Yast::BootStorage).to receive(:mbr_disk).and_return(double(name: "/dev/sda")) + end + describe "#restore" do it "returns true if backup is successfully restored" do allow(Yast::SCR).to receive(:Read).with(SIZE_PATH, anything).and_return(10) @@ -81,7 +85,6 @@ end it "store backup of device first 512 bytes to /boot/backup_mbr if it is MBR of primary disk" do - allow(Yast::BootStorage).to receive(:mbr_disk).and_return("/dev/sda") expect(Yast::SCR).to receive(:Execute).with(BASH_PATH, /bin\/dd.* of=\/boot\/backup_mbr/) subject.write diff --git a/test/boot_storage_test.rb b/test/boot_storage_test.rb index 6c2efa2bc..2024d8366 100644 --- a/test/boot_storage_test.rb +++ b/test/boot_storage_test.rb @@ -79,7 +79,7 @@ it "raises exception if there is no mount point for root" do allow(Yast::Storage).to receive(:GetMountPoints).and_return({}) - expect { subject.detect_disks }.to raise_error(RuntimeError) + expect { subject.detect_disks }.to raise_error(::Bootloader::NoRoot) end it "sets BootStorage.mbr_disk" do diff --git a/test/data/storage-ng/lvm_whole_disk.yml b/test/data/storage-ng/lvm_whole_disk.yml index fccd974e2..2260bb074 100644 --- a/test/data/storage-ng/lvm_whole_disk.yml +++ b/test/data/storage-ng/lvm_whole_disk.yml @@ -23,6 +23,7 @@ size: 5112 MiB file_system: ext4 label: home + mount_point: "/home" uuid: f72a2e11-1a58-4618-88d5-4a9cced3fcb5 - lvm_lv: @@ -30,6 +31,7 @@ size: 8 GiB file_system: ext4 label: local + mount_point: "/local" uuid: a4339246-1c17-4957-aa66-535f6d0d6393 - lvm_lv: @@ -37,6 +39,7 @@ size: 25 GiB file_system: ext4 label: opt + mount_point: "/opt" uuid: 69474311-830d-472f-aa77-08794e5c8a57 - lvm_lv: @@ -44,6 +47,7 @@ size: 10 GiB file_system: ext4 label: root + mount_point: "/" uuid: bbf1ac6a-65c6-4596-b822-6b62b19c9a64 - lvm_lv: @@ -51,6 +55,7 @@ size: 2 GiB file_system: swap label: swap + mount_point: swap uuid: 1b69e6bc-de2a-4999-b31a-dccc27c71290 lvm_pvs: diff --git a/test/device_map_dialog_test.rb b/test/device_map_dialog_test.rb index ab4658893..c1277107b 100644 --- a/test/device_map_dialog_test.rb +++ b/test/device_map_dialog_test.rb @@ -19,6 +19,7 @@ allow(Yast::UI).to receive(:QueryWidget).and_return("/dev/sda") allow(Yast::UI).to receive(:OpenDialog).and_return(true) allow(Yast::UI).to receive(:CloseDialog).and_return(true) + allow(Yast::BootStorage).to receive(:assign_mbr_disk_by_name) end def mock_ui_events(*events) diff --git a/test/grub2_efi_test.rb b/test/grub2_efi_test.rb index ec407f97c..a412b3d50 100644 --- a/test/grub2_efi_test.rb +++ b/test/grub2_efi_test.rb @@ -13,8 +13,8 @@ describe "#read" do it "reads secure boot configuration from sysconfig" do - sysconfig = double(Bootloader::Sysconfig, secure_boot: true) - expect(Bootloader::Sysconfig).to receive(:from_system).and_return(sysconfig) + sysconfig = double(Bootloader::Sysconfig, secure_boot: true, trusted_boot: true) + expect(Bootloader::Sysconfig).to receive(:from_system).and_return(sysconfig).at_least(:once) subject.read @@ -36,28 +36,30 @@ subject.write end - xit "calls grub2-install with respective secure boot configuration" do + xit "calls grub2-install with respective secure boot and trusted boot configuration" do # This test fails (only!) in Travis with # Failure/Error: subject.write Storage::Exception: Storage::Exception grub_install = double(Bootloader::GrubInstall) - expect(grub_install).to receive(:execute).with(secure_boot: true) + expect(grub_install).to receive(:execute).with(secure_boot: true, trusted_boot: true) allow(Bootloader::GrubInstall).to receive(:new).and_return(grub_install) subject.secure_boot = true + subject.trusted_boot = true subject.write end - xit "writes secure boot configuration to bootloader sysconfig" do + xit "writes secure boot and trusted boot configuration to bootloader sysconfig" do # This test fails (only!) in Travis with # Failure/Error: subject.write Storage::Exception: Storage::Exception sysconfig = double(Bootloader::Sysconfig) expect(sysconfig).to receive(:write) expect(Bootloader::Sysconfig).to receive(:new) - .with(bootloader: "grub2-efi", secure_boot: true) + .with(bootloader: "grub2-efi", secure_boot: true, trusted_boot: true) .and_return(sysconfig) subject.secure_boot = true + subject.trusted_boot = true subject.write end diff --git a/test/grub2_test.rb b/test/grub2_test.rb index 1cc7dd288..817b48028 100644 --- a/test/grub2_test.rb +++ b/test/grub2_test.rb @@ -74,6 +74,7 @@ .with(devices: ["/dev/sda", "/dev/sdb1"], trusted_boot: false) expect(Bootloader::GrubInstall).to receive(:new).with(efi: false).and_return(grub2_install) + subject.trusted_boot = false subject.write end @@ -164,7 +165,7 @@ end - describe "#summary" do + xdescribe "#summary" do before do stage1 = double(can_use_boot?: true, extended_partition?: false).as_null_object allow(Bootloader::Stage1).to receive(:new).and_return(stage1) diff --git a/test/grub2_widgets_test.rb b/test/grub2_widgets_test.rb index 79e824fda..2231406f1 100644 --- a/test/grub2_widgets_test.rb +++ b/test/grub2_widgets_test.rb @@ -483,7 +483,7 @@ def stub_widget_value(id, value) it "is valid if serial console arguments are provided" do stub_widget_value(:console_frame, true) - stub_widget_value(:console_args, "console=ttyS0,9600n8") + stub_widget_value(:console_args, "serial --unit=0 --speed=9600 --parity=no --stop=8") expect(subject.validate).to eq true end @@ -496,6 +496,16 @@ def stub_widget_value(id, value) expect(Yast::UI).to receive(:SetFocus).with(Id(:console_args)) expect(subject.validate).to eq false end + + it "reports an error if serial console is not correct" do + stub_widget_value(:console_frame, true) + stub_widget_value(:console_args, "serial --speed=5") + + expect(Yast::Report).to receive(:Error) + expect(Yast::UI).to receive(:SetFocus).with(Id(:console_args)) + expect(subject.validate).to eq false + end + end context "initialization" do @@ -681,3 +691,20 @@ def stub_widget_value(id, value) subject.handle end end + +describe Bootloader::TrustedBootWidget do + before do + assign_bootloader + end + + it_behaves_like "labeled widget" + + it "check if trusted platform is found for legacy boot when enabled" do + expect(Dir).to receive(:glob).and_return([]) + expect(Yast::Popup).to receive(:ContinueCancel).and_return(false) + + allow(subject).to receive(:value).and_return(true) + + expect(subject.validate).to eq false + end +end diff --git a/test/grub2base_test.rb b/test/grub2base_test.rb index 66717ce38..c032b695b 100644 --- a/test/grub2base_test.rb +++ b/test/grub2base_test.rb @@ -27,6 +27,22 @@ subject.read end + + it "reads trusted boot configuration from sysconfig" do + mocked_sysconfig = ::Bootloader::Sysconfig.new(trusted_boot: true) + expect(::Bootloader::Sysconfig).to receive(:from_system).and_return(mocked_sysconfig) + + subject.read + + expect(subject.trusted_boot).to eq true + + mocked_sysconfig = ::Bootloader::Sysconfig.new(trusted_boot: false) + expect(::Bootloader::Sysconfig).to receive(:from_system).and_return(mocked_sysconfig) + + subject.read + + expect(subject.trusted_boot).to eq false + end end describe "write" do @@ -310,6 +326,24 @@ end end + context "xen hyperviser kernel parameters proposal" do + it "do nothing if there is no framebuffer" do + allow(Dir).to receive(:[]).and_return([]) + + subject.propose + + expect(subject.grub_default.xen_hypervisor_params.parameter("vga")).to eq false + end + + it "propose vga parameter if there is framebuffer" do + allow(Dir).to receive(:[]).and_return(["/dev/fb0"]) + + subject.propose + + expect(subject.grub_default.xen_hypervisor_params.parameter("vga")).to eq "gfx-1024x768x16" + end + end + it "proposes gfx mode to auto" do subject.propose @@ -337,6 +371,12 @@ expect(subject.grub_default.serial_console).to eq "serial --unit=1 --speed=4800 --parity=no --word=8" end + + it "proposes to disable trusted boot" do + subject.propose + + expect(subject.trusted_boot).to eq false + end end describe "#disable_serial_console" do @@ -450,5 +490,14 @@ expect(subject.pmbr_action).to eq :nothing end + + it "overwrites trusted boot configuration if merged define it" do + subject.trusted_boot = true + other.trusted_boot = false + + subject.merge(other) + + expect(subject.trusted_boot).to eq false + end end end diff --git a/test/grub_install_test.rb b/test/grub_install_test.rb index 70aeaff6f..6b7390ec2 100644 --- a/test/grub_install_test.rb +++ b/test/grub_install_test.rb @@ -93,6 +93,17 @@ def expect_grub2_install(target, device: nil, removable: false) subject.execute end + + it "passes suse-enable-tpm option when trusted boot is requested" do + stub_arch("x86_64") + stub_efivars + + expect(Yast::Execute).to receive(:on_target) do |arg| + expect(arg).to include("--suse-enable-tpm") + end + + subject.execute(trusted_boot: true) + end end context "initialized with efi:false" do @@ -150,6 +161,16 @@ def expect_grub2_install(target, device: nil, removable: false) subject.execute(devices: []) end + it "pass directory argument when trusted boot is requested" do + stub_arch("x86_64") + + expect(Yast::Execute).to receive(:on_target) do |arg| + expect(arg).to include("--directory=/usr/lib/trustedgrub2/i386-pc") + end + + subject.execute(devices: ["/dev/sda"], trusted_boot: true) + end + it "raise exception on aarch64" do stub_arch("aarch64") diff --git a/test/stage1_device_test.rb b/test/stage1_device_test.rb index 61c5a3ece..57213dfe2 100644 --- a/test/stage1_device_test.rb +++ b/test/stage1_device_test.rb @@ -86,7 +86,8 @@ it "skips disks used as partitionless lvm devices" do devicegraph_stub("lvm_whole_disk.yml") - allow(Yast::BootStorage).to receive(:BootPartitionDevice).and_return("/dev/system/root") + # FIXME: won't be needed when boot_partition lazy loads + Yast::BootStorage.detect_disks subject = Bootloader::Stage1Device.new("/dev/system") expect(subject.real_devices).to eq(["/dev/sda"]) diff --git a/test/test_helper.rb b/test/test_helper.rb index 71244b09e..28445f4aa 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -51,6 +51,10 @@ def devicegraph_stub(name) path = File.join(File.dirname(__FILE__), "data", "storage-ng", name) storage = Y2Storage::StorageManager.fake_from_yaml(path) storage.probed.copy(storage.staging) + # clears cache for storage devices + Yast::BootStorage.reset_disks + # unmock detect disks as we have it + allow(Yast::BootStorage).to receive(:detect_disks).and_call_original end def mock_disk_partition