def from_other_image(cls, input_image, output_dir, output_subformat=None): """Convert the other disk image into an image of this type. Args: input_image (DiskRepresentation): Existing image representation. output_dir (str): Output directory to store the new image in. output_subformat (str): Any relevant subformat information. Returns: RAW: representation of newly created raw image. """ file_name = os.path.basename(input_image.path) file_prefix, _ = os.path.splitext(file_name) output_path = os.path.join(output_dir, file_prefix + ".img") if (input_image.disk_format == 'vmdk' and input_image.disk_subformat == 'streamOptimized'): helper = helper_select([('qemu-img', '1.2.0'), 'vmdktool']) # Special case: qemu-img < 1.2.0 can't read streamOptimized VMDKs if helper.name == 'vmdktool': # Note that vmdktool takes its arguments in unusual order - # output file comes before input file helper.call(['-s', output_path, input_image.path]) return cls(output_path) helpers['qemu-img'].call( ['convert', '-O', 'raw', input_image.path, output_path]) return cls(output_path)
def test_select_install_name_only(self, mock_install, *_): """Select and install a helper from a list of names only.""" helpers['vmdktool']._installed = False helpers['qemu-img']._installed = False helper = helper_select(['fatdisk', 'vmdktool', 'qemu-img']) self.assertEqual(helper, helpers['vmdktool']) mock_install.assert_called_once_with()
def _create_file(path, disk_subformat="rockridge", files=None, **kwargs): """Create an ISO file. Args: path (str): Location to create the ISO file. disk_subformat (str): Defaults to "rockridge". Set to "" to not include Rock Ridge extensions. files (list): List of files to include in this ISO (required) **kwargs: unused """ if not files: raise RuntimeError("Unable to create an empty ISO file") # We can use mkisofs, genisoimage, or xorriso, and fortunately # all three take similar parameters args = [ '-output', path, '-full-iso9660-filenames', '-iso-level', '2', '-allow-lowercase' ] if disk_subformat == 'rockridge': args.append('-r') args += files helper = helper_select(['mkisofs', 'genisoimage', 'xorriso']) if helper.name == "xorriso": args = ['-as', 'mkisofs'] + args helper.call(args)
def test_select_name_version(self): """Select a helper from a list of names and versions.""" helper = helper_select([('fatdisk', '1.4'), # not installed ('vmdktool', '2.0'), # version too low ('qemu-img', '2.1.0'), # just right ]) self.assertEqual(helper, helpers['qemu-img'])
def from_other_image(cls, input_image, output_dir, output_subformat=None): """Convert the other disk image into an image of this type. Args: input_image (DiskRepresentation): Existing image representation. output_dir (str): Output directory to store the new image in. output_subformat (str): Any relevant subformat information. Returns: QCOW2: representation of newly created qcow2 image file """ file_name = os.path.basename(input_image.path) (file_prefix, _) = os.path.splitext(file_name) output_path = os.path.join(output_dir, file_prefix + ".qcow2") if (input_image.disk_format == 'vmdk' and input_image.disk_subformat == 'streamOptimized'): helper = helper_select([('qemu-img', '1.2.0'), 'vmdktool']) # Special case: qemu-img < 1.2.0 can't read streamOptimized VMDKs if helper.name == 'vmdktool': # vmdktool can convert streamOptimized VMDK to raw # Convert vmdk to raw, then raw to qcow2 # Note that vmdktool takes its arguments in unusual order - # output file comes before input file from COT.disks import RAW try: temp_image = RAW.from_other_image(input_image, output_dir) return cls.from_other_image(temp_image, output_dir, output_subformat) finally: os.remove(temp_image.path) helpers['qemu-img'].call( ['convert', '-O', 'qcow2', input_image.path, output_path]) return cls(output_path)
def test_select_install_name_only(self, mock_install, *_): """Select and install a helper from a list of names only.""" helpers['vmdktool']._installed = False helpers['qemu-img']._installed = False helper = helper_select(['fatdisk', 'vmdktool', 'qemu-img']) self.assertEqual(helper, helpers['vmdktool']) mock_install.assert_called_once_with()
def test_select_name_version(self): """Select a helper from a list of names and versions.""" helper = helper_select([('fatdisk', '1.4'), # not installed ('vmdktool', '2.0'), # version too low ('qemu-img', '2.1.0'), # just right ]) self.assertEqual(helper, helpers['qemu-img'])
def from_other_image(cls, input_image, output_dir, output_subformat=None): """Convert the other disk image into an image of this type. Args: input_image (DiskRepresentation): Existing image representation. output_dir (str): Output directory to store the new image in. output_subformat (str): Any relevant subformat information. Returns: RAW: representation of newly created raw image. """ file_name = os.path.basename(input_image.path) file_prefix, _ = os.path.splitext(file_name) output_path = os.path.join(output_dir, file_prefix + ".img") if (input_image.disk_format == 'vmdk' and input_image.disk_subformat == 'streamOptimized'): helper = helper_select([('qemu-img', '1.2.0'), 'vmdktool']) # Special case: qemu-img < 1.2.0 can't read streamOptimized VMDKs if helper.name == 'vmdktool': # Note that vmdktool takes its arguments in unusual order - # output file comes before input file helper.call(['-s', output_path, input_image.path]) return cls(output_path) helpers['qemu-img'].call(['convert', '-O', 'raw', input_image.path, output_path]) return cls(output_path)
def test_select_install_name_version(self, mock_install_v, mock_install_q, *_): """Select and install a helper from a list of names and versions.""" helpers['vmdktool']._installed = False helpers['qemu-img']._installed = False helper = helper_select([('fatdisk', '1.4'), # not installable ('vmdktool', '2.0'), # version too low ('qemu-img', '2.1.0'), # just right ]) self.assertEqual(helper, helpers['qemu-img']) mock_install_v.assert_called_once_with() mock_install_q.assert_called_once_with()
def test_select_install_name_version(self, mock_install_v, mock_install_q, *_): """Select and install a helper from a list of names and versions.""" helpers['vmdktool']._installed = False helpers['qemu-img']._installed = False helper = helper_select([('fatdisk', '1.4'), # not installable ('vmdktool', '2.0'), # version too low ('qemu-img', '2.1.0'), # just right ]) self.assertEqual(helper, helpers['qemu-img']) mock_install_v.assert_called_once_with() mock_install_q.assert_called_once_with()
def _create_file(path, disk_subformat="rockridge", files=None, **kwargs): """Create an ISO file. Args: path (str): Location to create the ISO file. disk_subformat (str): Defaults to "rockridge". Set to "" to not include Rock Ridge extensions. files (list): List of files to include in this ISO (required) **kwargs: unused """ if not files: raise RuntimeError("Unable to create an empty ISO file") # We can use mkisofs, genisoimage, or xorriso, and fortunately # all three take similar parameters args = ['-output', path, '-full-iso9660-filenames', '-iso-level', '2', '-allow-lowercase'] if disk_subformat == 'rockridge': args.append('-r') args += files helper = helper_select(['mkisofs', 'genisoimage', 'xorriso']) if helper.name == "xorriso": args = ['-as', 'mkisofs'] + args helper.call(args)
def from_other_image(cls, input_image, output_dir, output_subformat=None): """Convert the other disk image into an image of this type. Args: input_image (DiskRepresentation): Existing image representation. output_dir (str): Output directory to store the new image in. output_subformat (str): Any relevant subformat information. Returns: QCOW2: representation of newly created qcow2 image file """ file_name = os.path.basename(input_image.path) (file_prefix, _) = os.path.splitext(file_name) output_path = os.path.join(output_dir, file_prefix + ".qcow2") if (input_image.disk_format == 'vmdk' and input_image.disk_subformat == 'streamOptimized'): helper = helper_select([('qemu-img', '1.2.0'), 'vmdktool']) # Special case: qemu-img < 1.2.0 can't read streamOptimized VMDKs if helper.name == 'vmdktool': # vmdktool can convert streamOptimized VMDK to raw # Convert vmdk to raw, then raw to qcow2 # Note that vmdktool takes its arguments in unusual order - # output file comes before input file from COT.disks import RAW try: temp_image = RAW.from_other_image(input_image, output_dir) return cls.from_other_image(temp_image, output_dir, output_subformat) finally: os.remove(temp_image.path) helpers['qemu-img'].call(['convert', '-O', 'qcow2', input_image.path, output_path]) return cls(output_path)
def test_select_name_only(self): """Select a helper from a list of names only.""" helper = helper_select(['fatdisk', 'vmdktool', 'qemu-img']) self.assertEqual(helper, helpers['vmdktool'])
def from_other_image(cls, input_image, output_dir, output_subformat="streamOptimized"): """Convert the other disk image into an image of this type. Args: input_image (DiskRepresentation): Existing image representation. output_dir (str): Output directory to store the new image in. output_subformat (str): VMDK subformat string. Defaults to "streamOptimized" if unset. Returns: VMDK: representation of newly created VMDK file. .. note:: Creation of streamOptimized subformat VMDKs (ESXi's preferred subformat for OVAs, hence COT's default subformat) is more complex than it seems due to the underlying helpers required. - Prior to QEMU 2.1.0, ``qemu-img`` effectively can't write streamOptimized subformat at all (it tends to error out). - In QEMU 2.1.0 through 2.5.0, ``qemu-img`` supports output to streamOptimized subformat, but it outputs VMDK images declaring version 1 of the VMDK format, which newer versions of ESXi (and probably other VMware products) reject with the message ``"Not a supported disk format (sparse VMDK version too old)"``. - In QEMU 2.5.1 and later, ``qemu-img`` produces "version 3" VMDK images, which suffices to make ESXi happy. - ``vmdktool`` (any released version) also makes "version 3" VMDKs, but is less likely to be available on most user systems, and it can only convert from RAW format images to streamOptimized VMDK. So, when creating streamOptimized VMDKs, if we have QEMU 2.5.1+, we're golden. Else, if we have ``vmdktool``, use it, after converting the :attr:`input_image` to RAW format first if necessary. Else, fail back to QEMU 2.1.0+ but warn the user that the resulting image may not be usable with ESXi. """ file_name = os.path.basename(input_image.path) (file_prefix, _) = os.path.splitext(file_name) output_path = os.path.join(output_dir, file_prefix + ".vmdk") if output_subformat == "streamOptimized": helper = helper_select([ ('qemu-img', '2.5.1'), # best option, all needed functionality 'vmdktool', # supports VMDK v.3, but only converts from RAW ('qemu-img', '2.1.0'), # fallback - produces VMDK v.1 ]) if helper.name == 'vmdktool': if input_image.disk_format != 'raw': # vmdktool needs a raw image as input from COT.disks import RAW temp_image = None try: temp_image = RAW.from_other_image( input_image, output_dir) return cls.from_other_image(temp_image, output_dir, output_subformat) finally: if temp_image is not None: os.remove(temp_image.path) temp_image = None # Note that vmdktool takes its arguments in unusual order - # output file comes before input file helper.call(['-z9', '-v', output_path, input_image.path]) return cls(output_path) # else, fall through to default (qemu-img), with one extra: if helpers['qemu-img'].version < StrictVersion("2.5.1"): logger.warning( "QEMU version %s produces 'version 1' VMDK images, which" " newer versions of VMware ESXi will reject with the" " message '%s'.\nIn order to generate the preferred" " 'version 3' images, please upgrade to QEMU 2.5.1 or" " later, or install vmdktool.", str(helpers['qemu-img'].version), "Not a supported disk format" " (sparse VMDK version too old)") helpers['qemu-img'].call([ 'convert', '-O', 'vmdk', '-o', 'subformat={0}'.format(output_subformat), input_image.path, output_path ]) return cls(output_path)
def test_select_name_only(self): """Select a helper from a list of names only.""" helper = helper_select(['fatdisk', 'vmdktool', 'qemu-img']) self.assertEqual(helper, helpers['vmdktool'])
def from_other_image(cls, input_image, output_dir, output_subformat="streamOptimized"): """Convert the other disk image into an image of this type. Args: input_image (DiskRepresentation): Existing image representation. output_dir (str): Output directory to store the new image in. output_subformat (str): VMDK subformat string. Defaults to "streamOptimized" if unset. Returns: VMDK: representation of newly created VMDK file. .. note:: Creation of streamOptimized subformat VMDKs (ESXi's preferred subformat for OVAs, hence COT's default subformat) is more complex than it seems due to the underlying helpers required. - Prior to QEMU 2.1.0, ``qemu-img`` effectively can't write streamOptimized subformat at all (it tends to error out). - In QEMU 2.1.0 through 2.5.0, ``qemu-img`` supports output to streamOptimized subformat, but it outputs VMDK images declaring version 1 of the VMDK format, which newer versions of ESXi (and probably other VMware products) reject with the message ``"Not a supported disk format (sparse VMDK version too old)"``. - In QEMU 2.5.1 and later, ``qemu-img`` produces "version 3" VMDK images, which suffices to make ESXi happy. - ``vmdktool`` (any released version) also makes "version 3" VMDKs, but is less likely to be available on most user systems, and it can only convert from RAW format images to streamOptimized VMDK. So, when creating streamOptimized VMDKs, if we have QEMU 2.5.1+, we're golden. Else, if we have ``vmdktool``, use it, after converting the :attr:`input_image` to RAW format first if necessary. Else, fail back to QEMU 2.1.0+ but warn the user that the resulting image may not be usable with ESXi. """ file_name = os.path.basename(input_image.path) (file_prefix, _) = os.path.splitext(file_name) output_path = os.path.join(output_dir, file_prefix + ".vmdk") if output_subformat == "streamOptimized": helper = helper_select([ ('qemu-img', '2.5.1'), # best option, all needed functionality 'vmdktool', # supports VMDK v.3, but only converts from RAW ('qemu-img', '2.1.0'), # fallback - produces VMDK v.1 ]) if helper.name == 'vmdktool': if input_image.disk_format != 'raw': # vmdktool needs a raw image as input from COT.disks import RAW temp_image = None try: temp_image = RAW.from_other_image(input_image, output_dir) return cls.from_other_image(temp_image, output_dir, output_subformat) finally: if temp_image is not None: os.remove(temp_image.path) temp_image = None # Note that vmdktool takes its arguments in unusual order - # output file comes before input file helper.call(['-z9', '-v', output_path, input_image.path]) return cls(output_path) # else, fall through to default (qemu-img), with one extra: if helpers['qemu-img'].version < StrictVersion("2.5.1"): logger.warning( "QEMU version %s produces 'version 1' VMDK images, which" " newer versions of VMware ESXi will reject with the" " message '%s'.\nIn order to generate the preferred" " 'version 3' images, please upgrade to QEMU 2.5.1 or" " later, or install vmdktool.", str(helpers['qemu-img'].version), "Not a supported disk format" " (sparse VMDK version too old)") helpers['qemu-img'].call([ 'convert', '-O', 'vmdk', '-o', 'subformat={0}'.format(output_subformat), input_image.path, output_path]) return cls(output_path)