示例#1
0
文件: be.py 项目: surajrav/middleware
    def mount(self, path=None):
        if not path:
            path = os.tmpfile()

        bsd.nmount(source=self.fullname, fspath=path, fstype='zfs')

        return path
示例#2
0
文件: be.py 项目: 650elx/middleware
    def mount(self, path=None):
        if not path:
            path = os.tmpfile()

        bsd.nmount(
            source=self.fullname,
            fspath=path,
            fstype='zfs'
        )

        return path
示例#3
0
class VolumeDiskImportTask(ProgressTask):
    def verify(self, src, dest_path, fstype=None):
        disk = self.dispatcher.call_sync('disks.partition_to_disk', src)
        if not disk:
            raise VerifyException(errno.ENOENT,
                                  "Partition {0} not found".format(src))

        return ['disk:{0}'.format(disk)]

    def run(self, src, dest_path, fstype=None):
        if not fstype:
            try:
                fstype, _ = system('/usr/sbin/fstyp', src)
            except SubprocessException:
                raise TaskException(errno.EINVAL,
                                    'Cannot figure out filesystem type')

        if fstype == 'ntfs':
            try:
                bsd.kld.kldload('/boot/kernel/fuse.ko')
            except OSError, err:
                raise TaskException(err.errno, err.message)

        src_mount = tempfile.mkdtemp()

        try:
            bsd.nmount(source=src, fspath=src_mount, fstype=fstype)
        except OSError, err:
            raise TaskException(err.errno,
                                "Cannot mount disk: {0}".format(str(err)))
示例#4
0
    def run(self, src, dest_path, fstype=None):
        if not fstype:
            try:
                fstype, _ = system('/usr/sbin/fstyp', src)
            except SubprocessException:
                raise TaskException(errno.EINVAL, 'Cannot figure out filesystem type')

        if fstype == 'ntfs':
            try:
                bsd.kld.kldload('/boot/kernel/fuse.ko')
            except OSError as err:
                raise TaskException(err.errno, str(err))

        src_mount = tempfile.mkdtemp()

        try:
            bsd.nmount(source=src, fspath=src_mount, fstype=fstype)
        except OSError as err:
            raise TaskException(err.errno, "Cannot mount disk: {0}".format(str(err)))

        def callback(srcfile, dstfile):
            self.set_progress(self.copied / self.nfiles * 100, "Copying {0}".format(os.path.basename(srcfile)))

        self.set_progress(0, "Counting files...")
        self.nfiles = count_files(src_mount)
        self.copied = 0
        failures = []

        try:
            copytree(src_mount, dest_path, progress_callback=callback)
        except shutil.Error as err:
            failures = list(err)

        try:
            bsd.unmount(src_mount, bsd.MountFlags.FORCE)
        except OSError:
            pass

        bsd.kld.kldunload('fuse')
        os.rmdir(src_mount)
        return failures
示例#5
0
def MountFilesystems(bename, mountpoint, **kwargs):
    """
    Mount the necessary filesystems, and clean up on error.
    The filesystems are bename -> mountpoint, freenas-boot/grub -> mountpoint/boot/grub,
    devfs -> mountpoint/dev, tmpfs mountpoint/var
    We also create mountpoint/boot/grub
    """
    mounted = []
    try:
        LogIt("Mounting {} on {}".format(bename, mountpoint))
        bsd.nmount(source=bename,
                   fspath=mountpoint,
                   fstype="zfs")
        mounted = [mountpoint]
        
        grub_path = "{}/boot/grub".format(mountpoint)
        LogIt("Mounting grub on {}".format(grub_path))
        os.makedirs(grub_path, 0o755)
        bsd.nmount(source="freenas-boot/grub",
                   fspath=grub_path,
                   fstype="zfs")
        mounted.append(grub_path)
        
        dev_path = os.path.join(mountpoint, "dev")
        LogIt("Mounting dev on {}".format(dev_path))
        os.makedirs(dev_path, 0o755)
        bsd.nmount(source="devfs",
                   fspath=dev_path,
                   fstype="devfs")
        mounted.append(dev_path)
        
    except os.error as e:
        LogIt("Got exception {} while mounting; have mounted {}".format(str(e), mounted))
        for path in mounted:
            try:
                bsd.unmount(path)
            except:
                raise InstallationError("Unable to mount filesystems")
    except BaseException as e:
        LogIt("Got base exception {}; have mounted {}".format(str(e), mounted))
        raise InstallationError("Error while mounting filesystems")
示例#6
0
def UpgradePossible():
    """
    An upgrade is possible if there is one (and only one) freenas-boot pool,
    and if that pool has an installation for the same project as us.  We'll
    determine the project by importing the pool, checking for a bootfs dataset,
    and mounting it to look at etc/version, which should startwith the same
    name as our project.  If any of those actions fail, return false.
    """
    global found_bootpool
    if not found_bootpool:
        LogIt("Boot pool has not been found, so no upgrade is possible")
        return False

    status = Dialog.MessageBox(
        Title(),
        "Checking for upgradable {} installation".format(Project()),
        width=45,
        height=10,
        wait=False)
    status.clear()
    status.run()
    try:
        try:
            zfs.import_pool(found_bootpool, "freenas-boot", {})
        except:
            LogIt("Could not import freenas-boot")
            return False
        boot_pool = None
        try:
            boot_pool = zfs.get("freenas-boot")
            try:
                bootfs = boot_pool.properties["bootfs"].value
                LogIt("bootfs = {}".format(bootfs))
                # Next we try to mount it
                try:
                    bsd.nmount(
                        source=bootfs,
                        fspath="/mnt",
                        fstype="zfs",
                        flags=bsd.MountFlags.RDONLY,
                    )
                except BaseException as e:
                    LogIt("Couldn't mount, got exception {}".format(e))
                    raise
                try:
                    with open("/mnt/etc/version") as f:
                        version = f.read().rstrip()
                    if version.startswith(Project()):
                        return True
                    LogIt("{} does not start with {}".format(
                        version, Project()))
                except:
                    LogIt("Could not open version file")
                    pass
                finally:
                    bsd.unmount("/mnt")
            except:
                LogIt("Could not get bootfs property, or mount dataset")

        except:
            LogIt("Could not get freenas-boot pool")
        finally:
            if boot_pool:
                zfs.export_pool(boot_pool)
    except:
        LogIt("Could not find unimported freenas-boot pool")
    LogIt("Returning false")
    return False
示例#7
0
def InstallGrub(chroot, disks, bename, efi=False):
    # Tell beadm to activate the dataset, and make the grub
    # configuration.
    # To do that, we need to change some file.
    os.environ["PATH"] = os.environ["PATH"] + ":/usr/local/bin:/usr/local/sbin"
    grub_files = ["{}/usr/local/sbin/beadm".format(chroot),
                  "{}/conf/base/etc/local/grub.d/10_ktrueos".format(chroot)]
    backup_data = {}
    for data_file in grub_files:
        LogIt("Backing up {}".format(data_file))
        with open(data_file, "r") as f:
            backup_data[data_file] = [x.rstrip() for x in f]
        with open(data_file, "w") as f:
            for line in backup_data[data_file]:
                if line.startswith("ROOTFS="):
                    LogIt("Setting {} -> {}".format(line, "ROOTFS={}".format(bename)))
                    print("ROOTFS={}".format(bename), file=f)
                else:
                    print(line, file=f)
    x = "{}/etc/local".format(chroot)
    cleanit = None
    if os.path.islink(x):
        # If /usr/local/etc is a symlink to /etc/local, we need to chagne it
        try:
            cleanit = os.readlink("{}/etc/local".format(chroot))
            LogIt("Getting rid of {}/etc/local".format(chroot))
            os.remove("{}/etc/local".format(chroot))
        except:
            pass
    if not os.path.exists(x):
        try:
            os.symlink("/conf/base/etc/local", x)
        except:
            pass

    os.environ["GRUB_TERMINAL_OUTPUT"] = "console serial"
    if efi:
        with open("{}/conf/base/etc/local/default/grub".format(chroot), "r") as f:
            lines = [x.rstrip() for x in f]
        with open("{}/conf/base/etc/local/default/grub".format(chroot), "w") as f:
            LogIt("Editing default/grub")
            for line in lines:
                LogIt("\t{}".format(line))
                if "GRUB_TERMINAL_OUTPUT=console" in line:
                    line = line.replace("GRUB_TERMINAL_OUTPUT=console", "GRUB_TERMINAL_OUTPUT=gfxterm")
                    LogIt("\t\t-> {}".format(line))
                print(line, file=f)
        
    for disk_name in disks:
        LogIt("InstallGrub:  disk={}".format(disk_name))
        disk = Utils.Disk(disk_name)
        if disk is None:
            LogIt("Cannot find disk info for {}".format(disk_name))
            raise InstallationError("Cannot find information for {}".format(disk_name))
        if efi:
            sysctl.sysctlbyname("kern.geom.debugflags", old=False, new=16)
            sysctl.sysctlbyname("kern.geom.label.disk_ident.enable", old=False, new=0)
            try:
                RunCommand("/sbin/glabel", "label", "efibsd", "/dev/{}p1".format(disk.name))
            except RunCommandException as e:
                LogIt("glabel got {}".format(str(e)))
                
            try:
                os.makedirs("{}/boot/efi".format(chroot), 0o755)
            except:
                pass
            LogIt("Attempting to mount /dev/{}p1 on {}/boot/efi".format(disk.name, chroot))
            bsd.nmount(source="/dev/{}p1".format(disk.name),
                       fspath="{}/boot/efi".format(chroot),
                       fstype="msdosfs")
            LogIt("Attempting to run grub-install in chrooted environment")
            RunCommand("/usr/local/sbin/grub-install",
                       "--efi-directory=/boot/efi",
                       "--removable",
                       "--target=x86_64-efi",
                       "/dev/{}".format(disk.name),
                       chroot=chroot)
            LogIt("Attempting to unmount {}/boot/efi".format(chroot))
            bsd.unmount("{}/boot/efi".format(chroot))
        else:
            RunCommand("/usr/local/sbin/grub-install",
                       "--modules=zfs part_gpt",
                       "/dev/{}".format(disk.name),
                       chroot=chroot)
    RunCommand("/usr/local/sbin/beadm", "activate",
               os.path.basename(bename),
               chroot=chroot)
    RunCommand("/usr/local/sbin/grub-mkconfig",
               "-o", "/boot/grub/grub.cfg",
               chroot=chroot)
    # Now put the grub files back to what they should be
    for name, data in backup_data.items():
        LogIt("Restoring {}".format(name))
        with open(name, "w") as f:
            for line in data:
                print(line, file=f)
                
    if cleanit:
        try:
            p = "{}/etc/local".format(chroot)
            os.remove(p)
            os.symlink(cleanit, p)
        except BaseException as e:
            LogIt("Got exception {} while trying to clean /etc/local fixup".format(str(e)))
示例#8
0
def Install(**kwargs):
    """
    This does the grunt-work of actually doing the install.
    The possible arguments are:
    - config	Object containing configuration.  This is where the download URL and
            	package directories will be specified.
    - interactive	Whether or not to be interactive.  If true (default), then
		bsd.Dialog will be used to for status and error messages.
    - disks	An array of Disk objects to install to.  If set, then the disks
    		will be partitioned and erased.  If NOT set, then the installer
		will create a new boot environment on the existing freenas-boot pool.
    - efi	Boolean indicating whether or not to use EFI (default is False).
    - upgrade_from	An unimported ZFSPool object to install to.  This must be set
    			when upgrading, and when creating a new BE on an existing pool.
    - upgrade	Boolean indicating whether or not to upgrade.  Requires upgrade_from to
		be valid.
    - data_dir	A string indicating the location of the /data.  Normally this will just
		be "/data", but if installing from something other than the ISO, it will
		be necessary to specify it.
    - password	A string indicating the root password.  Ignored for upgrades; may be None
    		(indicating no password, not recommended).
    - partitions	An array of Partition objects (see Utils).  Note that the OS
    			partition will always be installed last.
    - post_install	An array of callable objects, which will be called after installation,
    			as func(mount_point=/path, **kwargs).  MUST BE AN ARRAY.
    - package_handler	Call-back for the start of each package.  Arguments are
			(index [int], name [string], packages [array of package names])
    			be installed.
    - progress_handler	Call-back after each file/directory is installed.  Arguments are **kwargs,
    			will [currently] be either done=True (indicating the package is installed),
    			or (total=int [number of objects], index=int [current index], name=string
    			[name of object that was just installed]).
    - manifest	A manifest object.  Must be set.
    - package_directory	A path where the package files are located.  The package files must
    			already be located in this directory.
    - trampoline	A boolean indicating whether the post-install scripts should be run
    			on reboot (True, default) or during the install (False).
    """
    LogIt("Install({})".format(kwargs))
    orig_kwargs = kwargs.copy()

    config = kwargs.get("config", Configuration.SystemConfiguration())
    interactive = kwargs.get("interactive", True)
    disks = kwargs.get("disks", [])
    efi = kwargs.get("efi", False)
    upgrade_pool = kwargs.get("upgrade_from", None)
    upgrade = kwargs.get("upgrade", False)
    data_dir = kwargs.get("data_dir", "/data")
    password = kwargs.get("password", None)
    extra_partitions = kwargs.get("partitions", [])
    post_install = kwargs.get("post_install", [])
    package_notifier = kwargs.get("package_handler", None)
    progress_notifier = kwargs.get("progress_handler", None)
    manifest = kwargs.get("manifest", None)
    trampoline = kwargs.get("trampoline", True)
    # The default is based on ISO layout
    package_dir = kwargs.get("package_directory", "/.mount/{}/Packages".format(Project()))

    if type(post_install) != list:
        post_install = [post_install]
        
    if not manifest:
        if interactive:
            try:
                Dialog.MessageBox(Title(),
                                  "No manifest specified for the installation",
                                  height=7, width=45).run()
            except:
                pass
        raise InstallationError("No manifest specified for the installation")
                    
    config.SetPackageDir(package_dir)
    
    mount_point = tempfile.mkdtemp()
    
    # Quick sanity check
    if upgrade and upgrade_pool is None:
        if interactive:
            Dialog.MessageBox(Title(), "\nNo pool to upgrade from",
                              height=7, width=30).run()
        raise InstallationError("Upgrade selected but not previous boot pool selected")

    if disks is None and upgrade_pool is None:
        if interactive:
            Dialog.MessageBox(Title(), "\nNo disks or previous pool selected",
                              height=10, width=30).run()
        raise InstallationError("No disks or previous boot pool selected")
    
    if IsTruenas():
        # We use a 16g swap partition in TrueNAS.
        # Note that this is only used if the disks are being formatted.
        extra_partitions.append(Partition(type="swap", index="3", size=16*1024*1024*1024))
        def make_tn_swap(mount_point=None, **kwargs):
            # This uses the previously-defined variables, not kwargs
            if disks and mount_point:
                try:
                    RunCommand("/sbin/gmirror", "label", "-b", "prefer",
                               ["{}p3".format(disk.name) for disk in disks])
                    with open(os.path.join(mount_point, "data/fstab.swap"), "w") as swaptab:
                        print("/dev/mirror/swap.eli\tnone\tswap\tsw\t0\t0", file=swaptab)
                except RunCommandException as e:
                    LogIt("Could not create mirrored swap: {}".format(str(e)))
        post_install.append(make_tn_swap)
    # First step is to see if we're upgrading.
    # If so, we want to copy files from the active BE to
    # a location in /tmp, so we can copy them back later.
    # This will import, and then export, the freenas-boot pool.
    
    if upgrade_pool and upgrade:
        upgrade_dir = SaveConfiguration(interactive=interactive,
                                        pool=upgrade_pool)
    else:
        upgrade_dir = None

    # Second step is to see if we're formatting drives.
    # If so, we first will destroy the freenas-boot pool;
    # after that, we will partition the drives.  How we partition
    # depends on the boot method -- efi or bios.  We set the
    # BE name to "default" and create the freenas-boot pool, and
    # then the grub dataset.
    #
    # If we're NOT formatting the drive, we set the pool name
    # to time.strftime("default-%Y%m%d-%H%M%S")
    
    LogIt("disks = {}".format(disks))
    if disks:
        # This means we're formatting
        # We need to know what size and types to make the partitions.
        # If we're using EFI, then we need a 100mbyte msdosfs partition;
        # otherwise a 512k bios-boot.  If we have any extra partitions,
        # we'll take those into account as well.  For the big freebsd-zfs
        # partition, we'll take the minimum of the remaining space,
        # rounded down to the nearest gbyte.
        gByte = 1024 * 1024 * 1024
        if efi:
            # 100mbytes for efi partition
            used = 100 * 1024 * 1024
            boot_part = Partition(type="efi",
                                  index=1,
                                  size=used)
        else:
            # BIOS partition gets 512kbytes
            used = 512 * 1024
            boot_part = Partition(type="bios-boot",
                                  index=1,
                                  size=used)
        partitions = [boot_part]

        # For now, we always make the freenas-boot partition index 2, and place
        # it at the end of the disk.
        next_index = 3
        for part in (extra_partitions or []):
            # We will ignore the index given here.
            part.index = next_index
            used += part.size
            LogIt("Additional partition {}".format(part))
            partitions.append(part)
            next_index += 1

        # At this point, used is the sum of the partitions, in bytes.
        # This isn't really correct - we should be rounding the size up
        # to the blocksize of the disk.  But partitioning behaves strangely
        # sometimes with flash drives.  As a result, when we do the actual
        # partitioning, we use the smart-size (e.g., 1G), which rounds down.
        
        min_size = 0
        for disk in disks:
            # If the remaining space is too small, this installation won't work well.
            size = disk.size
            size = size - used
            if size < gByte:
                if size < 0:
                    fspace = "no free space after the other partitions"
                else:
                    fspace = "free space is {}, minimum is 1Gbyte".format(SmartSize(size))
                name = disk.name
                LogIt("Disk {} is too small {}".format(name, fspace))
                ssize = SmartSize(disk.size)
                if interactive:
                    Dialog.MessageBox(Title(),
                                      "Disk {} is too small ({})".format(name, ssize),
                                      height=10, width=25).run()
                raise InstallationException("Disk {} is too small ({})".format(name, ssize))
            if (size < min_size) or (not min_size):
                min_size = size
        if min_size == 0:
            if interactive:
                Dialog.MessageBox(Title(),
                                  "Unable to find the size of any of the selected disks",
                                  height=15, weidth=60).run()
            raise InstallationError("Unable to find disk size")
        
        # Round min_size down to a gbyte
        part_size = int(min_size / gByte) * gByte
        os_part = Partition(type="freebsd-zfs",
                            index=2,
                            size=part_size,
                            os=True)
        LogIt("OS partition {}".format(os_part))
        partitions.append(os_part)
                
        # We need to destroy any existing freenas-boot pool.
        # To do that, we may first need to import the pool.
        if upgrade_pool is None:
            try:
                old_pools = list(zfs.find_import(name="freenas-boot"))
            except libzfs.ZFSException as e:
                LogIt("Got ZFS error {} while trying to import freenas-boot for destruction".format(str(e)))
                old_pools = []
        else:
            old_pools = [upgrade_pool]
            # We'll be destroying it, so..
            upgrade_pool = None

        for pool in old_pools:
            try:
                dead_pool = zfs.import_pool(pool, "freenas-boot", {})
                if dead_pool is None:
                    dead_pool = zfs.get("freenas-boot")
                zfs.destroy("freenas-boot")
            except libzfs.ZFSException as e:
                LogIt("Trying to destroy a freenas-boot pool got error {}".format(str(e)))
            
        try:
            freenas_boot = FormatDisks(disks, partitions, interactive)
        except BaseException as e:
            LogIt("FormatDisks got exception {}".format(str(e)))
            raise
        
        bename = "freenas-boot/ROOT/default"
    else:
        # We need to import the pool (we exported it above if upgrade_pool)
        try:
            if upgrade_pool:
                freenas_boot = zfs.import_pool(upgrade_pool, "freenas-boot", {})
            else:
                freenas_boot = None
                pools = list(zfs.find_import(name="freenas-boot"))
                if len(pools) > 1:
                    raise InstallationError("There are multiple unimported freenas-boot pools")
                if len(pools) == 1:
                    freenas_boot = zfs.import_pool(upgrade_pool, "freenas-boot", {})
            if freenas_boot is None:
                freenas_boot = zfs.get("freenas-boot")
        except libzfs.ZFSException as e:
            LogIt("Got ZFS error {} while trying to import pool".format(str(e)))
            if interactive:
                Dialog.MessageBox("Error importing boot pool",
                                  "The {} Installer was unable to import the boot pool:\n\n\t{}".format(Project(), str(e)),
                                  height=25, width=60).run()
            raise InstallationError("Unable to import boot pool")

        bename = time.strftime("freenas-boot/ROOT/default-%Y%m%d-%H%M%S")
        
    # Next, we create the dataset, and mount it, and then mount
    # the grub dataset.
    # We also mount a devfs and tmpfs in the new environment.

    LogIt("BE name is {}".format(bename))
    try:
        freenas_boot.create(bename, fsopts={
            "mountpoint" : "legacy",
            "sync"       : "disabled",
        })
    except libzfs.ZFSException as e:
        LogIt("Could not create BE {}: {}".format(bename, str(e)))
        if interactive:
            Dialog.MessageBox(Title(),
                              "An error occurred creatint the installation boot environment\n" +
                              "\n\t{}".format(str(e)),
                              height=25, width=60).run()
        raise InstallationError("Could not create BE {}: {}".format(bename, str(e)))
    
    MountFilesystems(bename, mount_point)
    # After this, any exceptions need to have the filesystems unmounted
    try:
        # If upgrading, copy the stashed files back
        if upgrade_dir:
            RestoreConfiguration(save_path=upgrade_dir,
                                 interactive=interactive,
                                 destination=mount_point)
        else:
            if os.path.exists(data_dir):
                try:
                    copytree(data_dir, "{}/data".format(mount_point),
                             progress_callback=lambda src, dst: LogIt("Copying {} -> {}".format(src, dst)))
                except:
                    pass
            # 
            # We should also handle some FN9 stuff
            # In this case, we want the newer database file, for migration purposes
            # XXX -- this is a problem when installing from FreeBSD
            for dbfile in ["freenas-v1.db", "factory-v1.db"]:
                if os.path.exists("/data/{}".format(dbfile)):
                    copytree("/data/{}".format(dbfile), "{}/data/{}".format(mount_point, dbfile))

        # After that, we do the installlation.
        # This involves mounting the new BE,
        # and then running the install code on it.

        installer = Installer.Installer(manifest=manifest,
                                        root=mount_point,
                                        config=config)

        if installer.GetPackages() is not True:
            LogIt("Installer.GetPackages() failed")
            raise InstallationError("Unable to load packages")
        
        # This should only be true for the ISO installer.
        installer.trampoline = trampoline
        
        start_time = time.time()
        try:
            installer.InstallPackages(progressFunc=progress_notifier,
                                      handler=package_notifier)
        except BaseException as e:
            LogIt("InstallPackaages got exception {}".format(str(e)))
            raise InstallationError("Could not install packages")
        # Packages installed!
        if interactive:
            try:
                status = Dialog.MessageBox(Title(), "Preparing new boot environment",
                                           height=5, width=35, wait=False)
                status.clear()
                status.run()
            except:
                pass
        for f in ["{}/conf/default/etc/fstab".format(mount_point),
                  "{}/conf/base/etc/fstab".format(mount_point)
                  ]:
            try:
                os.remove(f)
            except:
                LogIt("Unable to remove {} -- ignoring".format(f))
                    
        try:
            with open("{}/etc/fstab".format(mount_point), "w") as fstab:
                print("freenas-boot/grub\t/boot/grub\tzfs\trw,noatime\t1\t0", file=fstab)
        except OSError as e:
            LogIt("Unable to create fstab: {}".format(str(e)))
            raise InstallationError("Unable to create filesystem table")
        try:
            os.link("{}/etc/fstab".format(mount_point),
                    "{}/conf/base/etc/fstab".format(mount_point))
        except OSError as e:
            LogIt("Unable to link /etc/fstab to /conf/base/etc/fstab: {}".format(str(e)))
            
        # Here, I should change module_path in boot/loader.conf, and get rid of the kernel line
        try:
            lines = []
            boot_config = "{}/boot/loader.conf".format(mount_point)
            with open(boot_config, "r") as bootfile:
                for line in bootfile:
                    line = line.rstrip()
                    if line.startswith("module_path="):
                        lines.append('module_path="/boot/kernel;/boot/modules;/usr/local/modules"')
                    elif line.startswith("kernel="):
                        lines.append('kernel="kernel"')
                    else:
                        lines.append(line)
            with open(boot_config, "w") as bootfile:
                for line in lines:
                    print(line, file=bootfile)
        except BaseException as e:
            LogIt("While modifying loader.conf, got exception {}".format(str(e)))
            # Otherwise I'll ignore it, I think
                        
        # This is to support Xen
        try:
            hvm = RunCommand("/usr/local/sbin/dmidecode", "-s", "system-product-name",
                             chroot=mount_point)
            if hvm == "HVM domU":
                with open(os.path.join(mount_point, "boot", "loader.conf.local"), "a") as f:
                    print('hint.hpet.0.clock="0"', file=f)
        except BaseException as e:
            LogIt("Got an exception trying to set XEN boot loader hint: {}".format(str(e)))
            
        # Now I have to mount a tmpfs on var
        try:
            LogIt("Mounting tmpfs on var")
            bsd.nmount(source="tmpfs",
                       fspath=os.path.join(mount_point, "var"),
                       fstype="tmpfs")
        except BaseException as e:
            LogIt("Got exception {} while trying to mount {}/var: {}".format(mount_point, str(e)))
            raise InstallationError("Unable to mount temporary space in newly-created BE")
        # Now we need to populate a data structure
        mtree_command = ["/usr/sbin/mtree", "-deUf" ]
        if os.path.exists("/usr/sbin/mtree"):
            mtree_command.append("{}/etc/mtree/BSD.var.dist".format(mount_point))
            mtree_command.extend(["-p", "{}/var".format(mount_point)])
            chroot=None
        else:
            mtree_command.extend(["/etc/mtree/BSD.var.dist", "-p", "/var"])
            chroot=mount_point

        try:
            RunCommand(*mtree_command,
                       chroot=chroot)
        except RunCommandException as e:
            LogIt("{} (chroot={}) failed: {}".format(mtree_command, chroot, str(e)))
            raise InstallationError("Unable to prepare new boot environment")

        try:
            # Now we need to install grub
            # We do this even if we didn't format the disks.
            # But if we didn't format the disks, we need to use the same type
            # of boot loader.
            if interactive:
                try:
                    status = Dialog.MessageBox(Title(), "Installing boot loader",
                                               height=5, width=35, wait=False)
                    status.clear()
                    status.run()
                except:
                    pass
            # We've just repartitioned, so rescan geom
            geom.scan()
            # Set the boot dataset
            freenas_boot.properties["bootfs"].value = bename
            LogIt("Set bootfs to {}".format(bename))
            # This is EXTREMELY ANNOYING.
            # I'd like to use libzfs to set the property here, but
            # I have to do it in the chrooted environment, because otherwise
            # zfs returns an error and doesn't set it.
            #freenas_boot.properties["cachefile"].value = "/boot/zfs/rpool.cache"
            try:
                RunCommand("/sbin/zpool",
                           "set", "cachefile=/boot/zfs/rpool.cache",
                           "freenas-boot",
                           chroot=mount_point)
            except RunCommandException as e:
                LogIt("Got exception {} while trying to set cachefile".format(str(e)))
                raise InstallationException("Could not set cachefile on boot pool")
            LogIt("Set cachefile to /boot/zfs/rpool.cache")
            # We need to set the serial port stuff in the database before running grub,
            # because it'll use that in the configuration file it generates.
            try:
                SaveSerialSettings(mount_point)
            except:
                raise InstallationError("Could not save serial console settings")

            try:
                # All boot pool disks are partitioned using the same type.
                # Or the darkness rises and squit once again rule the earth.
                # (It's happened.)
                use_efi = Utils.BootPartitionType(freenas_boot.disks[0]) == "efi"
                InstallGrub(chroot=mount_point,
                            disks=freenas_boot.disks,
                            bename=bename, efi=use_efi)
            except RunCommandException as e:
                LogIt("Command {} failed: {} (code {})".format(e.command, e.message, e.code))
                raise InstallationError("Boot loader installation failure")
            except BaseException as e:
                LogIt("InstallGrub got exception {}".format(str(e)))
                raise
    
            if interactive:
                try:
                    status = Dialog.MessageBox(Title(), "Finalizing installation",
                                               height=5, width=35, wait=False)
                    status.clear()
                    status.run()
                except BaseException as e:
                    LogIt("Finalizing got exception {}".format(str(e)))
                    
            # This is FN9 specific
            with open("{}/data/first-boot".format(mount_point), "wb"):
                pass
            if upgrade:
                for sentinel in ["/data/cd-upgrade", "/data/need-update"]:
                    with open(mount_point + sentinel, "wb") as f:
                        pass
            elif password is not None:
                if interactive:
                    try:
                        status = Dialog.MessageBox(Title(), "\nSetting root password",
                                                   height=7, width=35, wait=False)
                        status.clear()
                        status.run()
                    except:
                        pass
                try:
                    RunCommand("/etc/netcli", "reset_root_pw", password,
                               chroot=mount_point)
                except RunCommandException as e:
                    LogIt("Setting root password: {}".format(str(e)))
                    raise InstallationError("Unable to set root password")
        except BaseException as e:
            LogIt("Got exception {} during configuration".format(str(e)))
            if interactive:
                try:
                    Dialog.MessageBox(Title(),
                                      "Error during configuration",
                                      height=7, width=35).run()
                except:
                    pass
            raise

        # Let's turn sync back to default for the dataset
        try:
            ds = zfs.get_dataset(bename)
        except libzfs.ZFSException as e:
            LogIt("Got ZFS error {} while trying to get {} dataset".format(str(e), bename))
            raise InstallationError("Could not fid newly-created BE {}".format(bename))
        try:
            ds.properties["sync"].inherit()
        except BaseException as e:
            LogIt("Unable to set sync on {} to inherit: {}".format(bename, str(e)))
            # That's all I'm going to do for now

        # We save the manifest
        manifest.Save(mount_point)

        # Okay!  Now if there are any post-install functions, we call them
        for fp in post_install:
            fp(mount_point=mount_point, **kwargs)

        # And we're done!
        end_time = time.time()
    except InstallationError as e:
        # This is the outer try block -- it needs to ensure mountpoints are
        # cleaned up
        LogIt("Outer block got error {}".format(str(e)))
        if interactive:
            try:
                Dialog.MessageBox("{} Installation Error".format(Project()),
                                  e.message,
                                  height=25, width=50).run()
            except:
                pass
        raise
    except BaseException as e:
        LogIt("Outer block got base exception {}".format(str(e)))
        raise
    finally:
        if package_dir is None:
            LogIt("Removing downloaded packages directory {}".format(cache_dir))
            shutil.rmtree(cache_dir, ignore_errors=True)
        UnmountFilesystems(mount_point)

    LogIt("Exporting freenas-boot at end of installation")
    try:
        zfs.export_pool(freenas_boot)
    except libzfs.ZFSException as e:
        LogIt("Could not export freenas boot: {}".format(str(e)))
        raise

    if interactive:
        total_time = int(end_time - start_time)
        Dialog.MessageBox(Title(),
                          "The {} installer has finished the installation in {} seconds".format(Project(), total_time),
                          height=8, width=40).run()
示例#9
0
def SaveConfiguration(**kwargs):
    interactive = kwargs.get("interactive", False)
    upgrade_pool = kwargs.get("pool", None)
    if interactive:
        status = Dialog.MessageBox(Title(),
                                   "Mounting boot pool for upgrade_pool",
                                   height=7, width=35, wait=False)
        status.clear()
        status.run()
    upgrade_dir = tempfile.mkdtemp()
    try:
        mount_point = tempfile.mkdtemp()
        zfs.import_pool(upgrade_pool,
                        "freenas-boot",
                        {})
        LogIt("Imported old freenas-boot")
        freenas_boot = zfs.get("freenas-boot")
        try:
            LogIt("Looking for bootable dataset")
            bootfs = freenas_boot.properties["bootfs"].value
            if bootfs is None:
                if interactive:
                    try:
                        Dialog.MessageBox(Title(),
                                          "No active boot environment for upgrade",
                                          height=7, width=35).run()
                    except:
                        pass
                raise InstallerError("No active boot environment for upgrade")
            
            LogIt("Found dataset {}".format(bootfs))
            bsd.nmount(source=bootfs,
                       fspath=mount_point,
                       fstype="zfs",
                       flags=bsd.MountFlags.RDONLY,
            )
            LogIt("Mounted pool")
            if interactive:
                status = Dialog.MessageBox(Title(),
                                           "Copying configuration files for update",
                                           height=7, width=36, wait=False)
                status.clear()
                status.run()
            try:
                # Copy files now.
                for path in upgrade_paths:
                    src = os.path.join(mount_point, path)
                    dst = os.path.join(upgrade_dir, path)
                    if os.path.exists(src):
                        try:
                            os.makedirs(os.path.dirname(dst))
                        except:
                            pass
                        LogIt("Copying {} -> {}".format(src, dst))
                        copytree(src, dst,
                                 progress_callback=lambda s, d: LogIt("\t{} -> {}".format(s, d)))
                return upgrade_dir
            except BaseException as e:
                LogIt("While copying, got exception {}".format(str(e)))
                raise
            finally:
                LogIt("Unmounting pool")
                bsd.unmount(mount_point)

        except BaseException as e:
            LogIt("But got an excetion {}".format(str(e)))
        finally:
            LogIt("Exporting old freenas-boot pool")
            zfs.export_pool(freenas_boot)
    except InstallationError:
        raise
    except:
        if interactive:
            Dialog.MessageBox(Title(),
                              "Saving configuration files for upgrade_pool has failed",
                              height=10, width=45).run()
        raise
    finally:
        try:
            os.rmdir(mount_point)
        except:
            pass