def mount(self, libvirt=False): """ Mount the specified image to local host as block device. :param libvirt: Only mount if needed for libvirt (i.e. if mount not supported by libvirt 0.12) :return: True if successful, otherwise False """ # Files can be mounted by libvirt if libvirt: return True out, rc = cziso.run_command("kpartx -a %s" % self.file) if rc != 0: self.logger.error("Unable to mount %s as a control loop device") return False out, rc = cziso.run_command("losetup -a") for line in out: if line.find(self.file) >= 0: matcher = re.search("(/dev/loop\d+)", line) if matcher: self.loop_device = matcher.group(1) self.logger.info("Mounted image %s as %s" % (self.file, self.loop_device)) return True if not self.loop_device: self.logger.error("Unable to find loop device for %s" % self.file) return False return True
def promote_cloned_vols(self): """ Find out if there any dependent vols on our vol. If so promote them so they are independent of ours. :return: True if no dependent vols or if successfully promoted. False if error. """ out, rc = cziso.run_command("ssh %s zfs list -o name,origin" % self.nas) children_re = re.compile("(\S+)\s+%s/%s@\S+" % (self.pool, self.vol)) child_vols = [] for line in out: matcher = children_re.match(line) if matcher is not None: child_vols.append(matcher.group(1)) for vol in child_vols: self.logger.info( "Promoting depending volume %s (dependent on %s)" % (vol, self.vol)) out, rc = cziso.run_command("ssh %s zfs promote %s" % (self.nas, vol)) if rc != 0: self.logger.error("Error promoting volume %s" % vol) return False self.logger.info("Volume %s successfully promoted" % vol) return True
def _get_disk_info(self): """ Find the provided image partitions on local host and disk size :return: A tuple containing the disk size and string array containing location of image partitions """ mount = self.get_mount() if self.get_mount() is None: self.logger.error("Disk is not mounted") return None, None out, rc = cziso.run_command("fdisk -l %s" % mount) if rc != 0: cziso.abort("Unable to run fdisk command") for line in out: if self.size_gb == 0: matcher = re.search("^Disk \S+: ([\d\.]+) GB", line) if matcher is not None: size_gb_float = float(matcher.group(1)) self.size_gb = int(math.ceil(size_gb_float)) self.logger.info("Disk size is %i GB" % self.size_gb) matcher = re.match("^(%s\S+).*\s+(\S+)$" % mount, line) if matcher: if matcher.group(2) == "Linux": self.partitions.append(matcher.group(1)) if self.size_gb == 0: cziso.abort("Unable to find disk size of %s" % self) return self.size_gb, self.partitions
def exists(self): """ Verifies specified VM image zvol exists on NAS device :return: True if image exists; otherwise False """ out, rc = cziso.run_command("ssh %s zfs list %s/%s" % (self.nas, self.pool, self.vol)) return rc == 0
def unmount(self): """ Unmount the specified image from localhost :return: True if successful; otherwise False """ out, rc = cziso.run_command("rocks remove host storagemap %s %s" % (self.nas, self.vol)) if rc != 0: self.logger.error("Unable to unmount zvol at %s" % self.mount) return False self.mountpoint = None return True
def is_mapped(self): out, rc = cziso.run_command("rocks list host storagemap %s" % self.nas) if rc != 0: cziso.abort("Unable to list current storagemap") mapped_pattern = "^%s\s+%s.*\s+(\S*mapped)\s+.*" % (self.vol, self.pool) self.logger.debug("Looking for pattern '%s'" % mapped_pattern) for line in out: matcher = re.search(mapped_pattern, line) if matcher is not None: mapped_status = matcher.group(1) self.logger.debug("Status of vol %s is %s" % (self.vol, mapped_status)) return mapped_status == "mapped" return False
def create(self, size): """ Create the image file :param size An integer containing the file size in GB :return: True if image created; otherwise False """ out, rc = cziso.run_command("qemu-img create -f %s %s %iG" % (self.qemu_type, self.file, size)) if rc != 0: self.logger.error("Unable to create image: %s" % "\n".join(out)) return False self.logger.info("Created image file %s (%i GB)" % (self.file, size)) return True
def unmount(self): """ Unmount the specified image from localhost :return: True if successful; otherwise False """ if self.loop_device is None: self.logger.debug("No loop device needs to be unmounted") return True out, rc = cziso.run_command("kpartx -d %s" % self.file) if rc != 0: self.logger.error("Unable to remove loop device %s" % self.loop_device) return False self.loop_device = None return True
def fsck(self): """ Runs fsck on disk to repair any issues :return: True if successful; otherwise False """ self.logger.info("Running fsck on disk partitions") self._get_disk_info() if not self.partitions: cziso.abort("Unable to find any partitions on disk") for partition in self.partitions: out, rc = cziso.run_command("fsck -y %s" % partition) if rc != 0: self.unmount() cziso.abort("Problem running fsck -y on partition: %s" % "\n".join(out)) self.logger.debug("fsck output: %s" % "\n".join(out))
def create(self, size): """ Create the image file :param size An integer containing the file size in GB :return: True if image created; otherwise False """ out, rc = cziso.run_command( "rocks add host storagemap %s %s %s %s %i img_sync=false" % (self.nas, self.pool, self.vol, self.hostname, size)) if rc != 0: self.logger.error("Unable to create zvol to %s: %s" % (self.vol, "\n".join(out))) return False self.logger.info("Created ZFS vol %s (%i GB)" % (self, size)) self.mountpoint = out[1] return True
def update(self, zip_path, out_dir=os.getcwd()): """ Generate new Clonezilla Live ISOs for both the custom and regular cases. :param zip_path: A string containing the path to a Clonezilla zip release :param out_dir: A string containing a path to where the ISOs should be written :return: A tuple containing the path to the regular and custom ISOs """ self.logger.info("Generating custom ISO for %s" % zip_path) cz_version = os.path.splitext(os.path.basename(zip_path))[0] tmp = self.create_temp_directory() self.logger.debug("Created temporary directory %s" % tmp) # unpack zip zip_dir = os.path.join(tmp, "zip") out, rc = cziso.run_command("unzip %s -d %s" % (zip_path, zip_dir)) if rc != 0: cziso.abort("Unable to unzip %s: %s" % (zip_path, "\n".join(out))) # generate regular ISO regular_iso = os.path.join(out_dir, "%s-regular.iso" % cz_version) cziso.generate_iso(self.genisoimage_command, zip_dir, regular_iso) # customize file isolinux_file = os.path.join(zip_dir, "syslinux", "isolinux.cfg") if not os.path.exists(isolinux_file): cziso.abort("Unable to find %s" % isolinux_file) self.logger.info("Editing %s" % isolinux_file) cziso.file_edit(isolinux_file, Clonezilla.CUSTOMIZATIONS) # generate custom ISO custom_iso = os.path.join(out_dir, "%s-custom.iso" % cz_version) cziso.generate_iso(self.genisoimage_command, zip_dir, custom_iso) # cleanup self.logger.debug("Removing temporary directory %s" % tmp) shutil.rmtree(tmp) return regular_iso, custom_iso
def delete(self): """ Remove the image file :return: True if image deleted; otherwise False """ if self.is_mapped(): self.unmount() if not self.promote_cloned_vols(): self.logger.error("Volume %s is not removable" % self.vol) return False out, rc = cziso.run_command("rocks remove host storageimg %s %s %s" % (self.nas, self.pool, self.vol)) if rc != 0: self.logger.error("Unable to delete image: %s" % "\n".join(out)) return False return True
def __init__(self, image): """ Constructor for ZFS vol backed VM image. :param image: The URI of the image of zfs://nas/pool/vol format """ Image.__init__(self, image, "block", "raw") matcher = ZfsVol.match(image) self.nas = matcher.group(1) self.pool = matcher.group(2) self.vol = matcher.group(3) self.logger.debug( "Creating ZfsVol instance for vol %s in pool %s at %s" % (self.vol, self.pool, self.nas)) out, rc = cziso.run_command( "rocks report host attr localhost attr=hostname") if rc != 0: cziso.abort("Unable to determine physical hostname") self.hostname = out[0] self.mountpoint = None
def mount(self, libvirt=False): """ Mount the specified image to local host as block device. :param libvirt: Only mount if needed for libvirt (i.e. if mount not supported by libvirt 0.12) :return: True if successful, otherwise False """ # ZFS mounts not supported by our libvirt version so always mount # check if already mounted if self.mountpoint is not None: return True out, rc = cziso.run_command( "rocks add host storagemap %s %s %s %s 10 img_sync=false" % (self.nas, self.pool, self.vol, self.hostname)) if rc != 0: self.logger.error("Unable to mount zvol to %s" % self.hostname) return False self.mountpoint = out[1] self.logger.info("Mounted zvol %s to %s" % (self.vol, self.mountpoint)) return True