# # platform.py: Architecture-specific information # # Copyright (C) 2009-2011 # Red Hat, Inc. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # 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, see . # # Authors: Chris Lumens # from blivet import arch from blivet.devicelibs import raid from blivet.size import Size from pyanaconda.anaconda_loggers import get_module_logger from pyanaconda.core.i18n import _, N_ from pyanaconda.modules.storage.partitioning.specification import PartSpec log = get_module_logger(__name__) # Names of stage1 constrains. PLATFORM_DEVICE_TYPES = "device_types" PLATFORM_FORMAT_TYPES = "format_types" PLATFORM_MOUNT_POINTS = "mountpoints" PLATFORM_MAX_END = "max_end" PLATFORM_RAID_LEVELS = "raid_levels" PLATFORM_RAID_METADATA = "raid_metadata" # Descriptions of stage1 bootloader devices. PARTITION_DESCRIPTION = N_("First sector of boot partition") RAID_DESCRIPTION = N_("RAID Device") MBR_DESCRIPTION = N_("Master Boot Record") EFI_DESCRIPTION = N_("EFI System Partition") PREP_BOOT_DESCRIPTION = N_("PReP Boot Partition") APPLE_BOOTSTRAP_DESCRIPTION = N_("Apple Bootstrap Partition") DASD_DESCRIPTION = N_("DASD") ZFCP_DESCRIPTION = N_("zFCP") class Platform(object): """A base class for a platform. A class containing platform-specific information and methods for use during installation. The intent is to eventually encapsulate all the architecture quirks in one place to avoid lots of platform checks throughout anaconda. """ @property def packages(self): """Packages required for this platform. :return: a list of package names """ return [] @property def non_linux_format_types(self): """Format types of devices with non-linux operating systems.""" return [] @property def stage1_suggestion(self): """The platform-specific suggestion about the stage1 device. :return: a string """ return _("You must include at least one disk as an install target.") @property def stage1_descriptions(self): """The platform-specific descriptions of the stage1 device. :return: a dictionary of device types and their descriptions """ return {} @property def stage1_constraints(self): """The platform-specific constraints for the stage1 device. :return: a dictionary of constraints """ return { PLATFORM_DEVICE_TYPES: [], PLATFORM_FORMAT_TYPES: [], PLATFORM_MOUNT_POINTS: [], PLATFORM_MAX_END: None, PLATFORM_RAID_LEVELS: [], PLATFORM_RAID_METADATA: [], } @property def partitions(self): """The default platform-specific partitions. :return: a list of specifications """ partitions = [ self._bootloader_partition, self._boot_partition ] return list(filter(None, partitions)) @property def _bootloader_partition(self): """The default bootloader partition for this platform. Return the required platform-specific bootloader partition information. These are typically partitions that do not get mounted, like biosboot or prepboot, but may also include the /boot/efi partition. :return: a specification or None """ return None @property def _boot_partition(self): """The default /boot partition for this platform. :return: a specification or None """ return PartSpec( mountpoint="/boot", size=Size("1GiB") ) class X86(Platform): @property def non_linux_format_types(self): """Format types of devices with non-linux operating systems.""" # XXX hpfs, if reported by blkid/udev, will end up with a type of None return ["vfat", "ntfs", "hpfs"] @property def stage1_suggestion(self): """The platform-specific suggestion about the stage1 device.""" return _( "You must include at least one MBR- or " "GPT-formatted disk as an install target." ) @property def stage1_descriptions(self): """The platform-specific descriptions of the stage1 device.""" return { "disk": _(MBR_DESCRIPTION), "partition": _(PARTITION_DESCRIPTION), "mdarray": _(RAID_DESCRIPTION) } @property def stage1_constraints(self): """The platform-specific constraints for the stage1 device.""" constraints = { PLATFORM_DEVICE_TYPES: ["disk"] } return dict(super().stage1_constraints, **constraints) @property def _bootloader_partition(self): """The default bootloader partition for this platform.""" return PartSpec( fstype="biosboot", size=Size("1MiB") ) class EFI(Platform): @property def non_linux_format_types(self): """Format types of devices with non-linux operating systems.""" # XXX hpfs, if reported by blkid/udev, will end up with a type of None return ["vfat", "ntfs", "hpfs"] @property def stage1_suggestion(self): """The platform-specific suggestion about the stage1 device.""" return _( "For a UEFI installation, you must include " "an EFI System Partition on a GPT-formatted " "disk, mounted at /boot/efi." ) @property def stage1_descriptions(self): """The platform-specific descriptions of the stage1 device.""" return { "partition": _(EFI_DESCRIPTION), "mdarray": _(RAID_DESCRIPTION) } @property def stage1_constraints(self): """The platform-specific constraints for the stage1 device.""" constraints = { PLATFORM_FORMAT_TYPES: ["efi"], PLATFORM_DEVICE_TYPES: ["partition", "mdarray"], PLATFORM_MOUNT_POINTS: ["/boot/efi"], PLATFORM_RAID_LEVELS: [raid.RAID1], PLATFORM_RAID_METADATA: ["1.0"], } return dict(super().stage1_constraints, **constraints) @property def _bootloader_partition(self): """The default bootloader partition for this platform.""" return PartSpec( mountpoint="/boot/efi", fstype="efi", size=Size("500MiB"), max_size=Size("600MiB"), grow=True ) class Aarch64EFI(EFI): @property def non_linux_format_types(self): """Format types of devices with non-linux operating systems.""" return ["vfat", "ntfs"] class ArmEFI(EFI): @property def non_linux_format_types(self): """Format types of devices with non-linux operating systems.""" return ["vfat", "ntfs"] class PPC(Platform): @property def stage1_constraints(self): """The platform-specific constraints for the stage1 device.""" constraints = { PLATFORM_DEVICE_TYPES: ["partition"] } return dict(super().stage1_constraints, **constraints) class IPSeriesPPC(PPC): @property def stage1_suggestion(self): """The platform-specific suggestion about the stage1 device.""" return _( "You must include a PReP Boot Partition " "within the first 4GiB of an MBR- " "or GPT-formatted disk." ) @property def stage1_descriptions(self): """The platform-specific descriptions of the stage1 device.""" return {"partition": _(PREP_BOOT_DESCRIPTION)} @property def stage1_constraints(self): """The platform-specific constraints for the stage1 device.""" constraints = { PLATFORM_FORMAT_TYPES: ["prepboot"], PLATFORM_MAX_END: Size("4 GiB") } return dict(super().stage1_constraints, **constraints) @property def _bootloader_partition(self): """The default bootloader partition for this platform.""" return PartSpec( fstype="prepboot", size=Size("4MiB") ) class NewWorldPPC(PPC): @property def non_linux_format_types(self): """Format types of devices with non-linux operating systems.""" return ["hfs", "hfs+"] @property def stage1_suggestion(self): """The platform-specific suggestion about the stage1 device.""" return _( "You must include an Apple Bootstrap " "Partition on an Apple Partition Map-" "formatted disk." ) @property def stage1_descriptions(self): """The platform-specific descriptions of the stage1 device.""" return {"partition": _(APPLE_BOOTSTRAP_DESCRIPTION)} @property def stage1_constraints(self): """The platform-specific constraints for the stage1 device.""" constraints = { PLATFORM_FORMAT_TYPES: ["appleboot"] } return dict(super().stage1_constraints, **constraints) @property def _bootloader_partition(self): """The default bootloader partition for this platform.""" return PartSpec( fstype="appleboot", size=Size("1MiB") ) class PowerNV(PPC): @property def stage1_suggestion(self): """The platform-specific suggestion about the stage1 device.""" return _("You must include at least one disk as an install target.") @property def stage1_descriptions(self): """The platform-specific descriptions of the stage1 device.""" return {"partition": _(PARTITION_DESCRIPTION)} class PS3(PPC): pass class S390(Platform): @property def stage1_suggestion(self): """The platform-specific suggestion about the stage1 device.""" return _( "You must include at least one MBR- or " "DASD-formatted disk as an install target." ) @property def stage1_descriptions(self): """The platform-specific descriptions of the stage1 device.""" return { "dasd": _(DASD_DESCRIPTION), "zfcp": _(ZFCP_DESCRIPTION), "disk": _(MBR_DESCRIPTION), "partition": _(PARTITION_DESCRIPTION) } @property def stage1_constraints(self): """The platform-specific constraints for the stage1 device.""" constraints = { PLATFORM_DEVICE_TYPES: ["disk", "partition"] } return dict(super().stage1_constraints, **constraints) @property def _boot_partition(self): """The default /boot partition for this platform.""" return PartSpec( mountpoint="/boot", size=Size("1GiB"), lv=False ) class ARM(Platform): @property def stage1_suggestion(self): """The platform-specific suggestion about the stage1 device.""" return _( "You must include at least one MBR-formatted " "disk as an install target." ) @property def stage1_descriptions(self): """The platform-specific descriptions of the stage1 device.""" return { "disk": _(MBR_DESCRIPTION), "partition": _(PARTITION_DESCRIPTION) } @property def stage1_constraints(self): """The platform-specific constraints for the stage1 device.""" constraints = { PLATFORM_DEVICE_TYPES: ["disk"] } return dict(super().stage1_constraints, **constraints) def get_platform(): """Check the architecture of the system and return an instance of a Platform subclass to match. If the architecture could not be determined, raise an exception.""" if arch.is_ppc(): ppc_machine = arch.get_ppc_machine() if ppc_machine == "PMac" and arch.get_ppc_mac_gen() == "NewWorld": return NewWorldPPC() elif ppc_machine in ["iSeries", "pSeries"]: return IPSeriesPPC() elif ppc_machine == "PowerNV": return PowerNV() elif ppc_machine == "PS3": return PS3() else: raise SystemError("Unsupported PPC machine type: %s" % ppc_machine) elif arch.is_s390(): return S390() elif arch.is_efi(): if arch.is_aarch64(): return Aarch64EFI() elif arch.is_arm(): return ArmEFI() else: return EFI() elif arch.is_x86(): return X86() elif arch.is_arm(): return ARM() else: raise SystemError("Could not determine system architecture.") platform = get_platform()