def UnmountFilesystems(mountpoint): """ This attempts to unmount all of the filesystems. Note that it unmounts /var """ try: for directory in ["boot/grub", "dev", "var"]: try: path = os.path.join(mountpoint, directory) LogIt("Attempting to unmount {}".format(path)) bsd.unmount(path) except BaseException as e: LogIt("Unable to unmount {}: {}".format(path, str(e))) raise try: bsd.unmount(mountpoint) except BaseException as e: LogIt("Unable to unmount BE: {}".format(str(e))) raise try: os.rmdir(mountpoint) except BaseException as e: LogIt("Could not remove {}: {}".format(mountpoint, str(e))) except: raise InstallationError("Unable to unmount filesystems in new Boot Environment")
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")
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
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
def umount(name): with contextlib.suppress(OSError): bsd.unmount(os.path.join('/nfs', name))
def umount(name): bsd.unmount(os.path.join('/nfs', name))
def umount(name): try: bsd.unmount(os.path.join('/nfs', name)) except OSError as err: logger.warning('Cannot unmount {0}: {1}'.format(name, 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, err: failures = err.message try: bsd.unmount(src_mount, bsd.MountFlags.FORCE) except OSError: pass bsd.kld.kldunload('fuse') os.rmdir(src_mount) return failures @description("Exports active volume") @accepts(str) class VolumeDetachTask(Task): def verify(self, name): if not self.datastore.exists('volumes', ('name', '=', name)): raise VerifyException(errno.ENOENT, 'Volume {0} not found'.format(name))
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)))
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