def delprop(self, key): "Delete a Boot Loader property" self._prop_validate(key, validate_value=False) # Check pseudoproperties: if key == BootLoader.PROP_BOOT_TARGS: raise BootmgmtUnsupportedOperationError("key `%s' may not be " "deleted" % key) try: del self._bl_props[key] self.dirty = True except KeyError as err: raise BootmgmtUnsupportedOperationError( "key `%s' does not exist" % key, err)
def autogenerate_boot_instances(bootconfig): sbia = SolarisBootInstanceAutogenerator() # XXX - Handle bootconfig instances that have boot_class != disk if bootconfig.boot_class != BootConfig.BOOT_CLASS_DISK: raise BootmgmtUnsupportedOperationError('XXX - Fix Me') # Use libbe_py to get the list of boot environments, then iterate # over the list, creating a new SolarisDiskBootInstance for each # Note that the title will just be the last portion of the bootfs # (i.e. <pool>/ROOT/<title>) retcode, belist = libbe_py.beList() if retcode != 0: sbia._debug('libbe_py.beList() failed; return code was ' + str(retcode)) return [] inst_list = [] for bootenv in belist: if bootenv.get('orig_be_name', None) is None: continue # skip over snapshots bootinst = SolarisDiskBootInstance(None, title=bootenv['orig_be_name'], bootfs=bootenv['root_ds']) if bootenv['active'] is True: sbia._debug('default boot instance is:\n' + str(bootinst)) bootinst.default = True inst_list.append(bootinst) return inst_list
def load_config(self): """Load boot instances and GRUB properties from the menu.lst file""" if self._boot_config.boot_class == BootConfig.BOOT_CLASS_DISK: self._load_config_disk() self.dirty = False # We just loaded a clean config from disk! else: raise BootmgmtUnsupportedOperationError('XXX - Fix Me')
def _zfs_boot_data_rootdir_disk(self): if self._boot_config.boot_fstype != 'zfs': raise BootmgmtUnsupportedOperationError( 'Filesystem %s not ' 'supported by the ZFS boot block' % self._boot_config.boot_fstype) return self._boot_config.zfstop
def setprop(self, propname, value): """Setting properties is not supported on BIOS systems""" if propname == SystemFirmware.PROP_BOOT_DEVICE: raise BootmgmtWriteError('Properties are read-only on systems ' 'with BIOS firmware') raise BootmgmtUnsupportedOperationError( 'Properties cannot be set ' 'on systems with BIOS firmware')
def getprop(self, propname): if not propname == SystemFirmware.PROP_BOOT_DEVICE: raise BootmgmtUnsupportedOperationError('Property not supported') # libdevinfo's devfs_bootdev_get_list returns an ordered list of # boot devices. The form of the return value is a tuple of tuples: # ((<physpath>, (<logicalpath1>, <logicalpath2>, ...), ...) if propname == SystemFirmware.PROP_BOOT_DEVICE: return devfs_bootdev_get_list()
def _menu_lst_dir_disk(self): fstype = self._boot_config.boot_fstype if fstype != 'zfs' and fstype != 'ufs': raise BootmgmtUnsupportedOperationError('Unknown filesystem: %s' % fstype) if fstype == 'zfs': menu_lst_dir = self._boot_config.zfstop elif fstype == 'ufs': menu_lst_dir = self._boot_config.get_root() return menu_lst_dir
def __init__(self, flags, **kwargs): "" # Weed out unsupported flags: if BootConfig.BCF_MIGRATE in flags: raise BootmgmtUnsupportedOperationError(self.__class__.__name__ + ': Migration is not \ supported') # Save the image's root directory: self.odd_image_root = kwargs.get('oddimage_root', None) if self.odd_image_root is None: raise BootmgmtArgumentError('Missing oddimage_root argument') super(self.__class__, self).__init__(flags, boot_class=BootConfig.BOOT_CLASS_ODD, **kwargs)
def _write_config(self, basepath): """There are two files that need to be written: the menu.lst file, using information from the BootConfig instance to which we have a reference, and the bootlst program (which will be copied from the data source boot instance's mounted filesystem.) """ if self._boot_config is None: msg = 'Cannot _write_config(%s) - _boot_config is None' % basepath self._debug(msg) raise BootmgmtInterfaceCodingError(msg) elif self._boot_config.boot_class != BootConfig.BOOT_CLASS_DISK: msg = ('ZFS boot block boot loader does not support non-disk ' 'configs') raise BootmgmtUnsupportedOperationError(msg) return self._write_config_disk(basepath)
def _write_config_disk(self, basepath): """Write the boot loader's configuration file and boot program to disk""" if self._boot_config.boot_fstype != 'zfs': raise BootmgmtUnsupportedOperationError( 'Filesystem type %s ' 'not supported by the SPARC ZFS boot block' % self._boot_config.boot_fstype) dataroot_dir = self._zfs_boot_data_rootdir_disk() generic_tuples = self._write_config_generic(basepath, dataroot_dir) bootlst_tuples = self._write_bootlst(basepath, dataroot_dir) if basepath is None: return None tuples = [] if generic_tuples is not None: tuples += generic_tuples if bootlst_tuples is not None: tuples += bootlst_tuples for idx, item in enumerate(tuples): if (item[BootConfig.IDX_FILETYPE] == BootConfig.OUTPUT_TYPE_FILE and item[BootConfig.IDX_DESTNAME] in (ZFSBootLoader.MENU_LST_PATH, ZFSBootLoader.BOOTLST_PATH)): # Make a copy of the tuple so we can change it: item = list(item) item[BootConfig.IDX_DESTNAME] = ( '%(' + DiskBootConfig.TOKEN_ZFS_RPOOL_TOP_DATASET + ')s' + item[BootConfig.IDX_DESTNAME]) # Update tuple in the list: tuples[idx] = tuple(item) return tuples
def _write_config(self, basepath): """The only file that needs to be written is the menu.lst file, using information from the BootConfig instance to which we have a reference. Information from the boot loader's properties is also used to determine which commands are emitted at the global level""" if self._boot_config is None: msg = ('Cannot _write_config(%s) - _boot_config is None' % str(basepath)) self._debug(msg) raise BootmgmtInterfaceCodingError(msg) # Determine the type of boot configuration we're dealing with, then # determine the filesystem type that will hold the menu.lst. Only # then can we tell the caller the appropriate path to copy it into. if self._boot_config.boot_class == BootConfig.BOOT_CLASS_DISK: return self._write_config_disk(basepath) elif self._boot_config.boot_class == BootConfig.BOOT_CLASS_ODD: return self._write_config_odd(basepath) else: raise BootmgmtUnsupportedOperationError('XXX - Fix Me')
def probe(cls, **kwargs): """Probe for Legacy GRUB files for use with the BootConfig passed in""" if get_current_arch_string() != 'x86': cls._debug('Legacy GRUB boot loader not supported on this ' 'platform') return (None, None) bootconfig = kwargs.get('bootconfig', None) if (bootconfig is None or bootconfig.boot_class is None): return (None, None) if (bootconfig.boot_class == BootConfig.BOOT_CLASS_DISK and bootconfig.boot_fstype is not None): return LegacyGRUBBootLoader._probe_disk(**kwargs) elif bootconfig.boot_class == BootConfig.BOOT_CLASS_ODD: return LegacyGRUBBootLoader._probe_odd(**kwargs) else: raise BootmgmtUnsupportedOperationError('XXX - Fix Me')
def probe(**kwargs): """Probe for ZFS boot block files for use with the BootConfig passed in""" try: OBPBootLoader.probe_generic(**kwargs) except BootmgmtError: return (None, None) bootconfig = kwargs.get('bootconfig', None) if (bootconfig is None or bootconfig.boot_class is None): return (None, None) if (bootconfig.boot_class == BootConfig.BOOT_CLASS_DISK and bootconfig.boot_fstype == 'zfs'): return ZFSBootLoader._probe_disk(**kwargs) else: raise BootmgmtUnsupportedOperationError( 'ZFSBootLoader only ' 'supports ZFS-based disk boot ' 'configurations')
def autogen(self, bootconfig): "The workhorse of the autogenerator" # XXX - Handle bootconfig instances that have boot_class != disk if bootconfig.boot_class != BootConfig.BOOT_CLASS_DISK: raise BootmgmtUnsupportedOperationError('XXX - Fix Me') # This is only supported on x86: if get_current_arch_string() != 'x86': self._debug('Chainloader entry autogeneration only supported on ' 'x86') return [] try: helper_cmd = ['/usr/lib/boot/bootmgmt-helper-chain'] script_output = Popen.check_call(helper_cmd, stdout=Popen.STORE, stderr=Popen.STORE) script_stdout = script_output.stdout except OSError as error_exc: self._debug('Executing helper script failed: %s' % error_exc) return [] except CalledProcessError as cpe: self._debug('Helper script returned %d' % cpe.returncode) if cpe.popen and cpe.popen.stdout: self._debug('stdout was: %s\n' % cpe.popen.stdout) if cpe.popen and cpe.popen.stderr: self._debug('stderr was: %s\n' % cpe.popen.stderr) return [] inst_list = [] lineno = 0 for line in script_stdout.splitlines(): lineno += 1 self._debug('Output line %d: "%s"' % (lineno, line)) if line.startswith('#') or line.strip() == '': continue try: title, disk, partition, active = line.split(':') disk = int(disk) # partition can be empty, an int or a comma-separated list of # strings if partition.strip() != '': if partition.find(',') != -1: partition = tuple(partition.split(',')) else: partition = int(partition) else: partition = None active = True if active == 'True' else False except ValueError: self._debug('Malformed output line from helper: "%s"' % line) continue if partition is None: chain_info = (disk,) else: chain_info = (disk, partition) bootinst = ChainDiskBootInstance(None, title=title, chaininfo=chain_info, forceactive=active) inst_list.append(bootinst) self._debug('%d line(s) read from helper script.' % lineno) self._debug('%d boot instances autogenerated.' % len(inst_list)) return inst_list
def __init__(self, flags, **kwargs): """ Initialize the basic set of attributes for all BootConfig classes ----------------------------------------------------------------- Argument| Valid Value(s) --------+-------------------------------------------------------- flags | <Tuple of flags that modify the behavior of this | BootConfig object> [tuple] | | Allowed values in the tuple: | ---------------------------- | BootConfig.BCF_CREATE: Create a new boot | configuration. If one already | exists, it will be discarded. | If this flag is not present and | no boot configuration exists, | an exception | (BootmgmtConfigurationReadError) | will be raised. | BootConfig.BCF_ONESHOT:If True, only the final boot | configuration files will be | created when the | commit_boot_config() is called. | This is useful for one-shot | creation of boot configurations | for installation media. | BootConfig.BCF_AUTOGEN:The set of boot instances will be | automatically generated by | scanning the system. The list of | boot instances found by the scan | will be available after | the BootConfig object is created. | This set of boot instances can | then be tailored before calling | commit_boot_config(). Note that | the set of BootInstance objects | added to this object's boot_instances | are only guaranteed to include | Solaris boot instances. | BootConfig.BCF_MIGRATE:If supported, the existing boot | configuration will be migrated | from an older form to a newer | form (i.e. conversion from legacy | GRUB's menu.lst to GRUB2's | configuration format). The conversion | is performed at commit_boot_config() | time. Cannot be used with the | BCF_CREATE flag. | platform| [optional] The target system architecture / firmware for (keyword| which this boot configuration will be written. Useful arg) | for the creation of boot configuration files for network | boot instances, or when a boot configuration is created | on a system of a different architecture / firmware than | the target. If this is not supplied, the assumption is | that the boot configuration will be for the current | system. Supported tuple values are: | { ('sparc', 'obp' (or None)), | ('x86', 'bios' (or None)), | ('x86', 'uefi64') } | If a particular BootConfig subclass does not support | manipulation of a different platform's boot | configuration, a BootmgmtNotSupportedError will be | raised. ----------------------------------------------------------------- """ self.boot_instances = [] self.boot_class = kwargs.get('boot_class', None) self.boot_fstype = kwargs.get('boot_fstype', None) self._platform = kwargs.get('platform', None) self._dirty = False self._flags = flags self.boot_loader = self._get_boot_loader(**kwargs) if (BootConfig.BCF_CREATE in self._flags and BootConfig.BCF_MIGRATE in self._flags): raise BootmgmtUnsupportedOperationError( 'Migration cannot be combined with creation') if BootConfig.BCF_CREATE in self._flags: self._new_boot_config(**kwargs) else: # _load_boot_config raises BootmgmtConfigurationReadError self._load_boot_config(**kwargs) self.dirty = False if BootConfig.BCF_AUTOGEN in self._flags: self._autogenerate_config(**kwargs)
def delprop(self, propname): """Deleting properties is not supported on BIOS systems""" raise BootmgmtUnsupportedOperationError( 'Properties cannot be ' 'deleted on systems with BIOS firmware')