예제 #1
0
    def run(self, props):
        if 'train' in props:
            train_to_set = props.get('train')
            conf = Configuration.Configuration()
            conf.LoadTrainsConfig()
            trains = conf.AvailableTrains() or []
            if trains:
                trains = list(trains.keys())
            if train_to_set not in trains:
                raise TaskException(
                    errno.ENOENT,
                    '{0} is not a valid train'.format(train_to_set))
            self.configstore.set('update.train', train_to_set)

        if 'check_auto' in props:
            self.configstore.set('update.check_auto', props['check_auto'])

        if 'internal' in props:
            conf = Configuration.SystemConfiguration()
            if 'internal' not in conf.ListUpdateServers():
                conf.AddUpdateServer(
                    Configuration.UpdateServer(
                        'internal',
                        'http://update-int.ixsystems.com/FreeNAS/',
                        signing=False))

            conf.SetUpdateServer(
                'internal' if props['internal'] else 'default')

        cache_dir = self.dispatcher.call_sync('update.update_cache_getter',
                                              'cache_dir')
        check_updates(self.dispatcher,
                      self.configstore,
                      cache_dir=cache_dir,
                      check_now=True)

        self.dispatcher.dispatch_event('update.changed',
                                       {'operation': 'update'})
예제 #2
0
def do_install():
    """
    Do the UI for the install.
    This will either return, or raise an exception.  DialogEscape means that
    the installer should start over.
    
    If we have any command-line arguments, let's handle them now
    """
    arg_parser = argparse.ArgumentParser(description=Title(), prog="Installer")
    arg_parser.register('type', 'bool',
                        lambda x: x.lower() in ["yes", "y", "true", "t"])
    arg_parser.add_argument('-p',
                            '--project',
                            dest='project',
                            default=Project(),
                            help="Specify project (default {})".format(
                                Project()))
    arg_parser.add_argument('-T',
                            '--train',
                            dest="train",
                            help="Specify train name")
    arg_parser.add_argument('-U',
                            '--url',
                            dest="url",
                            help="URL to use when fetching files")
    arg_parser.add_argument('-D',
                            "--data",
                            dest='data_dir',
                            help='Path to /data prototype directory')
    arg_parser.add_argument('-M',
                            '--manifest',
                            dest='manifest',
                            help="Path to manifest file")
    arg_parser.add_argument('-P',
                            '--packages',
                            dest='package_dir',
                            help='Path to package files')
    arg_parser.add_argument(
        "-B",
        "--trampoline",
        dest='trampoline',
        default=True,
        type='bool',
        help="Run post-install scripts on reboot (default)")
    args = arg_parser.parse_args()
    if args:
        LogIt("Command line args: {}".format(args))

    SetProject(args.project)

    try:
        validate_system()
    except ValidationError as e:
        LogIt("Could not validate system: {}".format(e.message))
        Dialog.MessageBox(
            Title(),
            "\nSystem memory is too small.  Minimum memory size is 8Gbytes",
            height=10,
            width=45).run()
        return

    if args.manifest:
        if os.path.exists(args.manifest):
            manifest_path = args.manifest
        else:
            Dialog.MessageBox(
                Title(),
                "A manifest file was specified on the command line, but does not exist.  The manifest file specified was\n\n\t{}"
                .format(args.manifest),
                height=15,
                width=45).run()
            raise InstallationError(
                "Command-line manifest file {} does not exist".foramt(
                    args.manifet))
    else:
        manifest_path = "/.mount/{}-MANIFEST".format(Project())
        if not os.path.exists(manifest_path):
            manifest_path = None

    package_dir = args.package_dir or "/.mount/{}/Packages".format(Project())
    if not os.path.exists(package_dir):
        # This will be used later to see if we should try downloading
        package_dir = None
    # If we aren't given a URL, we can try to use the default url.
    # If we have a manifest file, we can figure out train;
    # if we don't have a train or manifest file, we're not okay.
    if (not manifest_path and not args.train):
        LogIt("Command-line URL {}, train {}, manifest {}".format(
            args.url, args.train, manifest_path))
        box = Dialog.MessageBox(Title(), "", height=15, width=45)
        box.text = "Neither a manifest file nor train were specified"
        box.run()
        raise InstallationError("Incorrect command-line arguments given")

    conf = Configuration.SystemConfiguration()
    if conf is None:
        raise RuntimeError("No configuration?!")

    # Okay, if we're going to have to download, let's make an update server object
    if args.url:
        temp_update_server = Configuration.UpdateServer(
            name="Installer Server", url=args.url, signing=False)
        # This is SO cheating
        # It can't write to the file, but it does that after setting it.
        try:
            conf.AddUpdateServer(temp_update_server)
        except:
            pass
        conf.SetUpdateServer("Installer Server", save=False)

    # If we have a train, and no manifest file, let's grab one

    if manifest_path:
        manifest = Manifest.Manifest()
        try:
            manifest.LoadPath(manifest_path)
        except:
            manifest = None
    else:
        manifest = None

    if args.train and not manifest:
        try:
            status = Dialog.MessageBox(
                Title(),
                "Attempting to download manifest for train {}".format(
                    args.train),
                height=15,
                width=30,
                wait=False)
            status.clear()
            status.run()
        except:
            pass
        try:
            manifest = conf.FindLatestManifest(train=args.train,
                                               require_signature=False)
        except:
            manifest = None

    # At this point, if we don't have a manifest, we can't do anything
    if manifest is None:
        LogIt("Could not load a manifest")
        text = "Despite valiant efforts, no manifest file could be located."

        Dialog.MessageBox(Title(), text, height=15, width=30).run()
        raise InstallationError("Unable to locate a manifest file")

    LogIt("Manifest:  Version {}, Train {}, Sequence {}".format(
        manifest.Version(), manifest.Train(), manifest.Sequence()))
    do_upgrade = False
    boot_method = None
    disks = SelectDisks()
    if not disks:
        try:
            Dialog.MessageBox(Title(),
                              "No suitable disks were found for installation",
                              height=15,
                              width=60).run()
        except:
            pass
        raise InstallationError("No disks selected for installation")

    if found_bootpool:
        if UpgradePossible():
            text = """The {} installer can upgrade the existing {} installation.
Do you want to upgrade?""".format(Project(), Project())
            yesno = Dialog.YesNo("Perform Upgrade",
                                 text,
                                 height=12,
                                 width=60,
                                 yes_label="Upgrade",
                                 no_label="Do not Upgrade",
                                 default=True)
            do_upgrade = yesno.result
        else:
            Dialog.MessageBox("No upgrade possible", "").run()

    format_disks = True
    if found_bootpool:
        # If the selected disks are not the same as the existing boot-pool
        # disks, then we _will_ be formatting, and do not ask this question.
        disk_set = set([x.name for x in disks])
        pool_set = set([Utils.Disk(x).name for x in found_bootpool.disks])
        LogIt("disk_set = {}, pool_set = {}".format(disk_set, pool_set))
        if pool_set == disk_set:
            yesno = Dialog.YesNo(
                Title(),
                "The {} installer can reformat the disk{}, or create a new boot environment.\nReformatting will erase all of your data"
                .format(Project(), "s" if len(disks) > 1 else ""),
                height=10,
                width=60,
                yes_label="Re-format",
                no_label="Create New BE",
                default=True)
            format_disks = yesno.result
            yesno.clear()

    if format_disks:
        # If there is already a freenas-boot, and we're not using all of
        # the disks in it, then this will cause problems.
        # If we made it this far, there is only one freenas-boot pool.
        if found_bootpool:
            pool_disks = [Utils.Disk(x) for x in found_bootpool.disks]

            disk_set = set([x.name for x in disks])
            pool_set = set([x.name for x in pool_disks])
            LogIt("disk_set = {}, pool_set = {}".format(disk_set, pool_set))
            if not pool_set <= disk_set:
                # This means there would be two freenas-boot pools, which
                # is too much of a problem.
                yesno = Dialog.YesNo(
                    Title(),
                    "The existing boot pool contains disks that are not in the selected set of disks, which would result in errors.  Select Start Over, or press Escape, otherwise the {} installer will destroy the existing pool"
                    .format(Project()),
                    width=60,
                    yes_label="Destroy Pool",
                    no_label="Start over",
                    default=False)
                yesno.prompt += "\nSelected Disks: " + " ,".join(
                    sorted([x.name for x in disks]))
                yesno.prompt += "\nPool Disks:     " + " ,".join(
                    sorted([x.name for x in pool_disks]))
                if yesno.result is False:
                    raise Dialog.DialogEscape

        current_method = BootMethod()
        yesno = Dialog.YesNo(
            "Boot Method",
            "{} can boot via BIOS or (U)EFI.  Selecting the wrong method can result in a non-bootable system"
            .format(Project()),
            height=10,
            width=60,
            yes_label="BIOS",
            no_label="(U)EFI",
            default=False if current_method == "efi" else True)
        if yesno.result is True:
            boot_method = "bios"
        else:
            boot_method = "efi"

    if not do_upgrade:
        # Ask for root password
        while True:
            password_fields = [
                Dialog.FormItem(
                    Dialog.FormLabel("Password:"******"",
                                     width=20,
                                     maximum_input=50,
                                     hidden=True)),
                Dialog.FormItem(
                    Dialog.FormLabel("Confirm Password:"******"",
                                     width=20,
                                     maximum_input=50,
                                     hidden=True)),
            ]
            try:
                password_input = Dialog.Form(
                    "Root Password",
                    "Enter the root password.  (Escape to quit, or select No Password)",
                    width=60,
                    height=15,
                    cancel_label="No Password",
                    form_height=10,
                    form_items=password_fields)
                results = password_input.result
                if results and results[0].value.value != results[1].value.value:
                    Dialog.MessageBox("Password Error",
                                      "Passwords did not match",
                                      width=35,
                                      ok_label="Try again").run()
                    continue
                else:
                    new_password = results[0].value.value if results else None
                    break
            except Dialog.DialogEscape:
                try:
                    Diallog.MessageBox("No Password Selected",
                                       "You have selected an empty password",
                                       height=7,
                                       width=35).run()
                except:
                    pass
                new_password = None
                break

    # I'm not sure if this should be done here, or in Install()

    if package_dir is None:
        cache_dir = tempfile.mkdtemp()
    else:
        cache_dir = package_dir

    try:
        Utils.GetPackages(manifest, conf, cache_dir, interactive=True)
    except BaseException as e:
        LogIt("GetPackages raised an exception {}".format(str(e)))
        if package_dir is None:
            shutil.rmtree(cache_dir, ignore_errors=True)
        raise
    LogIt("Done getting packages?")
    # Let's confirm everything
    text = "The {} Installer will perform the following actions:\n\n".format(
        Project())
    height = 10
    if format_disks:
        text += "* The following disks will be reformatted, and all data lost:\n"
        height += 1
        for disk in disks:
            text += "\t* {} {} ({}bytes)\n".format(disk.name,
                                                   disk.description[:25],
                                                   SmartSize(disk.size))
            height += 1
        if found_bootpool:
            text += "* The existing boot pool will be destroyed\n"
            height += 1
        text += "* {} Booting\n".format(
            "BIOS" if boot_method is "bios" else "(U)EFI")
    else:
        text += "* A new Boot Environment will be created\n"
        height += 1

    if do_upgrade:
        text += "* {} will be upgraded\n".format(Project())
    else:
        text += "* {} will be freshly installed\n".format(Project())
    height += 1

    yesno.prompt = text
    yesno.default = False
    yesno = Dialog.YesNo("{} Installation Confirmation".format(Project()),
                         text,
                         height=min(15, height),
                         width=60,
                         default=False)
    if yesno.result == False:
        LogIt("Installation aborted at first confirmation")
        raise Dialog.DialogEscape

    if format_disks:
        yesno = Dialog.YesNo(
            "LAST CHANCE",
            "The {} installer will format the selected disks and all data on them will be erased.\n\nSelect Start Over or hit Escape to start over!"
            .format(Project()),
            height=10,
            width=50,
            yes_label="Continue",
            no_label="Start Over",
            default=False)
        if yesno.result is False:
            LogIt("Installation aborted at second confirmation")
            raise Dialog.DialogEscape

    # This may take a while, it turns out
    try:
        status = Dialog.MessageBox(Title(),
                                   "\nBeginning installation",
                                   height=7,
                                   width=25,
                                   wait=False)
        status.clear()
        status.run()
    except:
        pass
    # Okay, time to do the install
    with InstallationHandler() as handler:
        try:
            Install.Install(
                interactive=True,
                manifest=manifest,
                config=conf,
                package_directory=cache_dir,
                disks=disks if format_disks else None,
                efi=True if boot_method is "efi" else False,
                upgrade_from=found_bootpool if found_bootpool else None,
                upgrade=do_upgrade,
                data_dir=args.data_dir if args.data_dir else "/data",
                package_handler=handler.start_package,
                progress_handler=handler.package_update,
                password=None if do_upgrade else new_password,
                trampoline=args.trampoline)
        except BaseException as e:
            LogIt("Install got exception {}".format(str(e)))
            raise
    return