コード例 #1
0
ファイル: uefi_amd64.py プロジェクト: tai271828/maas
    def _find_and_copy_bootloaders(self, destination, log_missing=True):
        if not super()._find_and_copy_bootloaders(destination, False):
            # If a previous copy of the UEFI AMD64 Grub files can't be found
            # see the files are on the system from an Ubuntu package install.
            # The package uses a different filename than what MAAS uses so
            # when we copy make sure the right name is used.
            missing_files = []

            if os.path.exists("/usr/lib/shim/shim.efi.signed"):
                atomic_symlink(
                    "/usr/lib/shim/shim.efi.signed",
                    os.path.join(destination, "bootx64.efi"),
                )
            else:
                missing_files.append("bootx64.efi")

            if os.path.exists(
                    "/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed"):
                atomic_symlink(
                    "/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed",
                    os.path.join(destination, "grubx64.efi"),
                )
            else:
                missing_files.append("grubx64.efi")

            if missing_files != [] and log_missing:
                err_msg = (
                    "Unable to find a copy of %s in the SimpleStream and the "
                    "packages shim-signed, and grub-efi-amd64-signed are not "
                    "installed. The %s bootloader type may not work." %
                    (", ".join(missing_files), self.name))
                try_send_rack_event(EVENT_TYPES.RACK_IMPORT_ERROR, err_msg)
                maaslog.error(err_msg)
                return False
        return True
コード例 #2
0
    def _find_and_copy_bootloaders(self, destination, log_missing=True):
        """Attempt to copy bootloaders from the previous snapshot

        :param destination: The path to link the bootloaders to
        :param log_missing: Log missing files, default True

        :return: True if all bootloaders have been found and copied, False
                 otherwise.
        """
        boot_sources_base = os.path.realpath(os.path.join(destination, ".."))
        previous_snapshot = os.path.join(boot_sources_base, "current")
        files_found = True
        for bootloader_file in self.bootloader_files:
            bootloader_src = os.path.join(previous_snapshot, bootloader_file)
            bootloader_src = os.path.realpath(bootloader_src)
            bootloader_dst = os.path.join(destination, bootloader_file)
            if os.path.exists(bootloader_src):
                # Copy files if their realpath is inside the previous snapshot
                # as once we're done the previous snapshot is deleted. Symlinks
                # to other areas of the filesystem are maintained.
                if boot_sources_base in bootloader_src:
                    atomic_copy(bootloader_src, bootloader_dst)
                else:
                    atomic_symlink(bootloader_src, bootloader_dst)
            else:
                files_found = False
                if log_missing:
                    err_msg = (
                        "Unable to find a copy of %s in the SimpleStream or a "
                        "previously downloaded copy. The %s bootloader type "
                        "may not work." % (bootloader_file, self.name)
                    )
                    try_send_rack_event(EVENT_TYPES.RACK_IMPORT_ERROR, err_msg)
                    maaslog.error(err_msg)
        return files_found
コード例 #3
0
    def get_template(self, purpose, arch, subarch):
        """Gets the best avaliable template for the boot method.

        Templates are loaded each time here so that they can be changed on
        the fly without restarting the provisioning server.

        :param purpose: The boot purpose, e.g. "local".
        :param arch: Main machine architecture.
        :param subarch: Sub-architecture, or "generic" if there is none.
        :return: `tempita.Template`
        """
        pxe_templates_dir = self.get_template_dir()
        for filename in gen_template_filenames(purpose, arch, subarch):
            template_name = os.path.join(pxe_templates_dir, filename)
            try:
                return tempita.Template.from_filename(
                    template_name, encoding="UTF-8"
                )
            except IOError as error:
                if error.errno != ENOENT:
                    raise
        else:
            error = (
                "No PXE template found in %r for:\n"
                "  Purpose: %r, Arch: %r, Subarch: %r\n"
                "This can happen if you manually power up a node when its "
                "state is not one that allows it. Is the node in the "
                "'New' or 'Ready' states? It needs to be Enlisting, "
                "Commissioning or Allocated."
                % (pxe_templates_dir, purpose, arch, subarch)
            )
            try_send_rack_event(EVENT_TYPES.RACK_IMPORT_ERROR, error)
            raise AssertionError(error)
コード例 #4
0
def update_targets_conf(snapshot):
    """Runs tgt-admin to update the new targets from "maas.tgt"."""
    # Ensure that tgt is running before tgt-admin is used.
    service_monitor.ensureService("tgt").wait(30)

    # Update the tgt config.
    targets_conf = os.path.join(snapshot, 'maas.tgt')

    # The targets_conf may not exist in the event the BootSource is broken
    # and images havn't been imported yet. This fixes LP:1655721
    if not os.path.exists(targets_conf):
        return

    try:
        call_and_check(
            sudo([
                get_path('/usr/sbin/tgt-admin'),
                '--conf',
                targets_conf,
                '--update',
                'ALL',
            ]))
    except ExternalProcessError as e:
        msg = "Unable to update TGT config: %s" % e
        try_send_rack_event(EVENT_TYPES.RACK_IMPORT_WARNING, msg)
        maaslog.warning(msg)
コード例 #5
0
ファイル: boot_resources.py プロジェクト: th3architect/maas
def link_bootloaders(destination):
    """Link the all the required file from each bootloader method.
    :param destination: Directory where the loaders should be stored.
    """
    for _, boot_method in BootMethodRegistry:
        try:
            boot_method.link_bootloader(destination)
        except BaseException:
            msg = "Unable to link the %s bootloader.", boot_method.name
            try_send_rack_event(EVENT_TYPES.RACK_IMPORT_ERROR, msg)
            maaslog.error(msg)
コード例 #6
0
    def _link_simplestream_bootloaders(self, stream_path, destination):
        """Link the bootloaders downloaded from the SimpleStream into the
        destination(tftp root).

        :param stream_path: The path to the bootloaders in the SimpleStream
        :param destination: The path to link the bootloaders to
        """
        for bootloader_file in self.bootloader_files:
            bootloader_src = os.path.join(stream_path, bootloader_file)
            bootloader_dst = os.path.join(destination, bootloader_file)
            if os.path.exists(bootloader_src):
                atomic_symlink(bootloader_src, bootloader_dst)
            else:
                err_msg = (
                    "SimpleStream is missing required bootloader file '%s' "
                    "from bootloader %s." % (bootloader_file, self.name))
                try_send_rack_event(EVENT_TYPES.RACK_IMPORT_ERROR, err_msg)
                maaslog.error(err_msg)
コード例 #7
0
ファイル: boot_resources.py プロジェクト: th3architect/maas
def import_images(sources):
    """Import images.  Callable from the command line.

    :param config: An iterable of dicts representing the sources from
        which boot images will be downloaded.
    """
    if len(sources) == 0:
        msg = "Can't import: region did not provide a source."
        try_send_rack_event(EVENT_TYPES.RACK_IMPORT_WARNING, msg)
        maaslog.warning(msg)
        return False

    msg = "Starting rack boot image import"
    maaslog.info(msg)
    try_send_rack_event(EVENT_TYPES.RACK_IMPORT_INFO, msg)

    with ClusterConfiguration.open() as config:
        storage = FilePath(config.tftp_root).parent().path

    with tempdir("keyrings") as keyrings_path:
        # XXX: Band-aid to ensure that the keyring_data is bytes. Future task:
        # try to figure out why this sometimes happens.
        for source in sources:
            if "keyring_data" in source and not isinstance(
                    source["keyring_data"], bytes):
                source["keyring_data"] = source["keyring_data"].encode("utf-8")

        # We download the keyrings now  because we need them for both
        # download_all_image_descriptions() and
        # download_all_boot_resources() later.
        sources = write_all_keyrings(keyrings_path, sources)

        # The region produces a SimpleStream which is similar, but not
        # identical to the actual SimpleStream. These differences cause
        # validation to fail. So grab everything from the region and trust it
        # did proper filtering before the rack.
        image_descriptions = download_all_image_descriptions(
            sources, validate_products=False)
        if image_descriptions.is_empty():
            msg = ("Finished importing boot images, the region does not have "
                   "any boot images available.")
            try_send_rack_event(EVENT_TYPES.RACK_IMPORT_WARNING, msg)
            maaslog.warning(msg)
            return False

        meta_file_content = image_descriptions.dump_json()
        if meta_contains(storage, meta_file_content):
            maaslog.info("Finished importing boot images, the region does not "
                         "have any new images.")
            try_send_rack_event(EVENT_TYPES.RACK_IMPORT_INFO, msg)
            maaslog.info(msg)
            return False

        product_mapping = map_products(image_descriptions)

        try:
            snapshot_path = download_all_boot_resources(
                sources, storage, product_mapping)
        except Exception as e:
            try_send_rack_event(
                EVENT_TYPES.RACK_IMPORT_ERROR,
                "Unable to import boot images: %s" % e,
            )
            maaslog.error(
                "Unable to import boot images; cleaning up failed snapshot "
                "and cache.")
            # Cleanup snapshots and cache since download failed.
            cleanup_snapshots_and_cache(storage)
            raise

    maaslog.info("Writing boot image metadata.")
    write_snapshot_metadata(snapshot_path, meta_file_content)

    maaslog.info("Linking boot images snapshot %s" % snapshot_path)
    link_bootloaders(snapshot_path)

    # If we got here, all went well.  This is now truly the "current" snapshot.
    update_current_symlink(storage, snapshot_path)

    # Now cleanup the old snapshots and cache.
    maaslog.info("Cleaning up old snapshots and cache.")
    cleanup_snapshots_and_cache(storage)

    # Import is now finished.
    msg = "Finished importing boot images."
    maaslog.info(msg)
    try_send_rack_event(EVENT_TYPES.RACK_IMPORT_INFO, msg)
    return True
コード例 #8
0
    def _find_and_copy_bootloaders(self,
                                   destination,
                                   log_missing=True,
                                   bootloader_files=None):
        if bootloader_files is None:
            bootloader_files = self.bootloader_files
        boot_sources_base = os.path.realpath(os.path.join(destination, '..'))
        default_search_path = os.path.join(boot_sources_base, 'current')
        syslinux_search_path = os.path.join(default_search_path, 'syslinux')
        # In addition to the default search path search the previous
        # syslinux subdir as well. Previously MAAS didn't copy all of the
        # files required for PXE into the root tftp path. Also search the
        # paths the syslinux-common and pxelinux Ubuntu packages installs files
        # to on Xenial.
        search_paths = [
            default_search_path,
            syslinux_search_path,
            '/usr/lib/PXELINUX',
            '/usr/lib/syslinux/modules/bios',
        ]
        files_found = []
        for search_path in search_paths:
            for bootloader_file in bootloader_files:
                bootloader_src = os.path.join(search_path, bootloader_file)
                bootloader_src = os.path.realpath(bootloader_src)
                bootloader_dst = os.path.join(destination, bootloader_file)
                if (os.path.exists(bootloader_src)
                        and not os.path.exists(bootloader_dst)):
                    # If the file was found in a previous snapshot copy it as
                    # once we're done the previous snapshot will be deleted. If
                    # the file was found elsewhere on the filesystem create a
                    # symlink so we stay current with that source.
                    if boot_sources_base in bootloader_src:
                        atomic_copy(bootloader_src, bootloader_dst)
                    else:
                        atomic_symlink(bootloader_src, bootloader_dst)
                    files_found.append(bootloader_file)

        missing_files = [
            bootloader_file for bootloader_file in bootloader_files
            if bootloader_file not in files_found
        ]
        if missing_files != []:
            files_are_missing = True
            if log_missing:
                err_msg = (
                    "Unable to find a copy of %s in the SimpleStream or in "
                    "the system search paths %s. The %s bootloader type may "
                    "not work." % (', '.join(missing_files),
                                   ', '.join(search_paths), self.name))
                try_send_rack_event(EVENT_TYPES.RACK_IMPORT_ERROR, err_msg)
                maaslog.error(err_msg)
        else:
            files_are_missing = False

        syslinux_search_paths = [
            syslinux_search_path,
            '/usr/lib/syslinux/modules/bios',
        ]
        for search_path in syslinux_search_paths:
            if os.path.exists(search_path):
                syslinux_src = os.path.realpath(search_path)
                syslinux_dst = os.path.join(destination, 'syslinux')
                if destination in os.path.realpath(syslinux_src):
                    shutil.copy(bootloader_src, bootloader_dst)
                else:
                    atomic_symlink(syslinux_src, syslinux_dst)
                break

        return files_are_missing