def test_inject_config_iso(self): """Inject config file on an ISO.""" self.command.package = self.input_ovf self.command.config_file = self.config_file self.command.run() self.assertLogged(**self.OVERWRITING_DISK_ITEM) self.command.finished() config_iso = os.path.join(self.temp_dir, 'config.iso') self.check_diff(""" <ovf:File ovf:href="sample_cfg.txt" ovf:id="textfile" \ ovf:size="{cfg_size}" /> + <ovf:File ovf:href="config.iso" ovf:id="config.iso" \ ovf:size="{config_size}" /> </ovf:References> ... <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> + <rasd:Description>Configuration disk</rasd:Description> <rasd:ElementName>CD-ROM 2</rasd:ElementName> + <rasd:HostResource>ovf:/file/config.iso</rasd:HostResource> <rasd:InstanceID>8</rasd:InstanceID>""".format( cfg_size=self.FILE_SIZE['sample_cfg.txt'], config_size=os.path.getsize(config_iso))) if helpers['isoinfo']: # The sample_cfg.text should be renamed to the platform-specific # file name for bootstrap config - in this case, config.txt self.assertEqual( DiskRepresentation.from_file(config_iso).files, ["config.txt"]) else: logger.info("isoinfo not available, not checking disk contents")
def test_disk_representation_from_file_qcow2(self): """Test if DiskRepresentation.from_file() works for qcow2 images.""" temp_disk = os.path.join(self.temp_dir, 'foo.qcow2') helpers['qemu-img'].call(['create', '-f', 'qcow2', temp_disk, "16M"]) diskrep = DiskRepresentation.from_file(temp_disk) self.assertEqual(diskrep.disk_format, "qcow2") self.assertEqual(diskrep.disk_subformat, None)
def test_convert_from_vmdk(self): """Test conversion of a RAW image from a VMDK.""" old = DiskRepresentation.from_file(self.blank_vmdk) raw = RAW.from_other_image(old, self.temp_dir) self.assertEqual(raw.disk_format, 'raw') self.assertEqual(raw.disk_subformat, None)
def test_inject_config_iso(self): """Inject config file on an ISO.""" self.command.package = self.input_ovf self.command.config_file = self.config_file self.command.run() self.assertLogged(**self.OVERWRITING_DISK_ITEM) self.command.finished() config_iso = os.path.join(self.temp_dir, 'config.iso') self.check_diff(""" <ovf:File ovf:href="sample_cfg.txt" ovf:id="textfile" \ ovf:size="{cfg_size}" /> + <ovf:File ovf:href="config.iso" ovf:id="config.iso" \ ovf:size="{config_size}" /> </ovf:References> ... <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> + <rasd:Description>Configuration disk</rasd:Description> <rasd:ElementName>CD-ROM 2</rasd:ElementName> + <rasd:HostResource>ovf:/file/config.iso</rasd:HostResource> <rasd:InstanceID>8</rasd:InstanceID>""" .format(cfg_size=self.FILE_SIZE['sample_cfg.txt'], config_size=os.path.getsize(config_iso))) if helpers['isoinfo']: # The sample_cfg.text should be renamed to the platform-specific # file name for bootstrap config - in this case, config.txt self.assertEqual(DiskRepresentation.from_file(config_iso).files, ["config.txt"]) else: logger.info("isoinfo not available, not checking disk contents")
def test_inject_extra_directory(self): """Test injection of extras from an entire directory.""" self.command.package = self.input_ovf extra_dir = os.path.join(self.temp_dir, "configs") os.makedirs(extra_dir) shutil.copy(self.input_ovf, extra_dir) shutil.copy(self.minimal_ovf, extra_dir) subdir = os.path.join(extra_dir, "subdirectory") os.makedirs(subdir) shutil.copy(self.invalid_ovf, subdir) self.command.extra_files = [extra_dir] self.command.run() self.assertLogged(**self.OVERWRITING_DISK_ITEM) self.command.finished() config_iso = os.path.join(self.temp_dir, 'config.iso') if helpers['isoinfo']: self.assertEqual( DiskRepresentation.from_file(config_iso).files, [ 'input.ovf', 'minimal.ovf', 'subdirectory', 'subdirectory/invalid.ovf', ]) else: logger.info("isoinfo not present, not checking disk contents")
def test_inject_extra_directory(self): """Test injection of extras from an entire directory.""" self.command.package = self.input_ovf extra_dir = os.path.join(self.temp_dir, "configs") os.makedirs(extra_dir) shutil.copy(self.input_ovf, extra_dir) shutil.copy(self.minimal_ovf, extra_dir) subdir = os.path.join(extra_dir, "subdirectory") os.makedirs(subdir) shutil.copy(self.invalid_ovf, subdir) self.command.extra_files = [extra_dir] self.command.run() self.assertLogged(**self.OVERWRITING_DISK_ITEM) self.command.finished() config_iso = os.path.join(self.temp_dir, 'config.iso') if helpers['isoinfo']: self.assertEqual( DiskRepresentation.from_file(config_iso).files, [ 'input.ovf', 'minimal.ovf', 'subdirectory', 'subdirectory/invalid.ovf', ] ) else: logger.info("isoinfo not present, not checking disk contents")
def test_disk_representation_from_file_iso(self): """Test if DiskRepresentation.from_file() works for iso images.""" diskrep = DiskRepresentation.from_file(self.input_iso) self.assertEqual(diskrep.disk_format, "iso") # In Travis CI we can't currently install isoinfo (via genisoimage). # https://github.com/travis-ci/apt-package-whitelist/issues/588 if helpers['isoinfo']: self.assertEqual(diskrep.disk_subformat, "")
def test_disk_representation_from_file_raw_noext(self): """DiskRepresentation.from_file() falls back to RAW if unsure.""" temp_disk = os.path.join(self.temp_dir, 'foo.bar') with open(temp_disk, 'a') as fakedisk: fakedisk.write("Hello world") diskrep = DiskRepresentation.from_file(temp_disk) self.assertEqual(diskrep.disk_format, "raw") self.assertEqual(diskrep.disk_subformat, None) # Less confidence in this case self.assertLogged(levelname='WARNING', msg='COT has low confidence', args=(temp_disk, 'raw', '10'))
def setUp(self): """Pre-test setup.""" super(TestVMDKConversion, self).setUp() self.input_image_paths = {} self.input_disks = {} input_dir = os.path.join(self.temp_dir, "disks") os.makedirs(input_dir) for disk_format in ["raw", "qcow2", "vmdk"]: temp_disk = os.path.join(input_dir, "foo.{0}".format(disk_format)) helpers['qemu-img'].call( ['create', '-f', disk_format, temp_disk, "16M"]) self.input_disks[disk_format] = DiskRepresentation.from_file( temp_disk)
def setUp(self): """Pre-test setup.""" super(TestVMDKConversion, self).setUp() self.input_image_paths = {} self.input_disks = {} input_dir = os.path.join(self.temp_dir, "disks") os.makedirs(input_dir) for disk_format in ["raw", "qcow2", "vmdk"]: temp_disk = os.path.join(input_dir, "foo.{0}".format(disk_format)) helpers['qemu-img'].call(['create', '-f', disk_format, temp_disk, "16M"]) self.input_disks[disk_format] = DiskRepresentation.from_file( temp_disk)
def test_inject_config_primary_secondary_extra(self): """Test injection of primary and secondary files and extras.""" self.command.package = self.input_ovf # IOSXRv supports secondary config self.set_vm_platform(IOSXRv) self.command.config_file = self.config_file self.command.secondary_config_file = self.config_file self.command.extra_files = [self.minimal_ovf, self.vmware_ovf] self.command.run() self.assertLogged(**self.OVERWRITING_DISK_ITEM) self.command.finished() self.assertLogged(**self.invalid_hardware_warning( '4CPU-4GB-3NIC', 'VMXNET3', 'NIC type')) self.assertLogged(**self.invalid_hardware_warning( '1CPU-1GB-1NIC', 'VMXNET3', 'NIC type')) self.assertLogged(**self.invalid_hardware_warning( '1CPU-1GB-1NIC', '1024', 'MiB of RAM')) self.assertLogged(**self.invalid_hardware_warning( '2CPU-2GB-1NIC', 'VMXNET3', 'NIC type')) self.assertLogged(**self.invalid_hardware_warning( '2CPU-2GB-1NIC', '2048', 'MiB of RAM')) config_iso = os.path.join(self.temp_dir, 'config.iso') self.check_diff(""" <ovf:File ovf:href="sample_cfg.txt" ovf:id="textfile" \ ovf:size="{cfg_size}" /> + <ovf:File ovf:href="config.iso" ovf:id="config.iso" \ ovf:size="{config_size}" /> </ovf:References> ... <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> + <rasd:Description>Configuration disk</rasd:Description> <rasd:ElementName>CD-ROM 2</rasd:ElementName> + <rasd:HostResource>ovf:/file/config.iso</rasd:HostResource> <rasd:InstanceID>8</rasd:InstanceID>""" .format(cfg_size=self.FILE_SIZE['sample_cfg.txt'], config_size=os.path.getsize(config_iso))) if helpers['isoinfo']: self.assertEqual( DiskRepresentation.from_file(config_iso).files, [ "iosxr_config.txt", "iosxr_config_admin.txt", "minimal.ovf", "vmware.ovf", ] ) else: logger.info("isoinfo not available, not checking disk contents")
def test_inject_config_iso_multiple_drives(self): """Inject config file on an ISO when multiple empty drives exist.""" temp_ovf = os.path.join(self.temp_dir, "intermediate.ovf") # Remove the existing ISO from our input_ovf: remover = COTRemoveFile(UI()) remover.package = self.input_ovf remover.output = temp_ovf remover.file_path = "input.iso" remover.run() remover.finished() remover.destroy() # Now we have two empty drives. self.command.package = temp_ovf self.command.config_file = self.config_file self.command.run() self.assertLogged(**self.OVERWRITING_DISK_ITEM) self.command.finished() config_iso = os.path.join(self.temp_dir, 'config.iso') self.check_diff(""" <ovf:File ovf:href="input.vmdk" ovf:id="file1" ovf:size="{vmdk_size}" /> - <ovf:File ovf:href="input.iso" ovf:id="file2" ovf:size="{iso_size}" /> <ovf:File ovf:href="sample_cfg.txt" ovf:id="textfile" \ ovf:size="{cfg_size}" /> + <ovf:File ovf:href="config.iso" ovf:id="config.iso" \ ovf:size="{config_size}" /> </ovf:References> ... <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> + <rasd:Description>Configuration disk</rasd:Description> <rasd:ElementName>CD-ROM 1</rasd:ElementName> - <rasd:HostResource>ovf:/file/file2</rasd:HostResource> + <rasd:HostResource>ovf:/file/config.iso</rasd:HostResource> <rasd:InstanceID>7</rasd:InstanceID>""" .format(vmdk_size=self.FILE_SIZE['input.vmdk'], iso_size=self.FILE_SIZE['input.iso'], cfg_size=self.FILE_SIZE['sample_cfg.txt'], config_size=os.path.getsize(config_iso))) if helpers['isoinfo']: # The sample_cfg.text should be renamed to the platform-specific # file name for bootstrap config - in this case, config.txt self.assertEqual(DiskRepresentation.from_file(config_iso).files, ["config.txt"]) else: logger.info("isoinfo not available, not checking disk contents")
def test_inject_config_iso_multiple_drives(self): """Inject config file on an ISO when multiple empty drives exist.""" temp_ovf = os.path.join(self.temp_dir, "intermediate.ovf") # Remove the existing ISO from our input_ovf: remover = COTRemoveFile(UI()) remover.package = self.input_ovf remover.output = temp_ovf remover.file_path = "input.iso" remover.run() remover.finished() remover.destroy() # Now we have two empty drives. self.command.package = temp_ovf self.command.config_file = self.config_file self.command.run() self.assertLogged(**self.OVERWRITING_DISK_ITEM) self.command.finished() config_iso = os.path.join(self.temp_dir, 'config.iso') self.check_diff(""" <ovf:File ovf:href="input.vmdk" ovf:id="file1" ovf:size="{vmdk_size}" /> - <ovf:File ovf:href="input.iso" ovf:id="file2" ovf:size="{iso_size}" /> <ovf:File ovf:href="sample_cfg.txt" ovf:id="textfile" \ ovf:size="{cfg_size}" /> + <ovf:File ovf:href="config.iso" ovf:id="config.iso" \ ovf:size="{config_size}" /> </ovf:References> ... <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> + <rasd:Description>Configuration disk</rasd:Description> <rasd:ElementName>CD-ROM 1</rasd:ElementName> - <rasd:HostResource>ovf:/file/file2</rasd:HostResource> + <rasd:HostResource>ovf:/file/config.iso</rasd:HostResource> <rasd:InstanceID>7</rasd:InstanceID>""".format( vmdk_size=self.FILE_SIZE['input.vmdk'], iso_size=self.FILE_SIZE['input.iso'], cfg_size=self.FILE_SIZE['sample_cfg.txt'], config_size=os.path.getsize(config_iso))) if helpers['isoinfo']: # The sample_cfg.text should be renamed to the platform-specific # file name for bootstrap config - in this case, config.txt self.assertEqual( DiskRepresentation.from_file(config_iso).files, ["config.txt"]) else: logger.info("isoinfo not available, not checking disk contents")
def test_inject_config_primary_secondary_extra(self): """Test injection of primary and secondary files and extras.""" self.command.package = self.input_ovf # IOSXRv supports secondary config self.set_vm_platform(IOSXRv) self.command.config_file = self.config_file self.command.secondary_config_file = self.config_file self.command.extra_files = [self.minimal_ovf, self.vmware_ovf] self.command.run() self.assertLogged(**self.OVERWRITING_DISK_ITEM) self.command.finished() self.assertLogged(**self.invalid_hardware_warning( '4CPU-4GB-3NIC', 'VMXNET3', 'NIC type')) self.assertLogged(**self.invalid_hardware_warning( '1CPU-1GB-1NIC', 'VMXNET3', 'NIC type')) self.assertLogged(**self.invalid_hardware_warning( '1CPU-1GB-1NIC', '1024', 'MiB of RAM')) self.assertLogged(**self.invalid_hardware_warning( '2CPU-2GB-1NIC', 'VMXNET3', 'NIC type')) self.assertLogged(**self.invalid_hardware_warning( '2CPU-2GB-1NIC', '2048', 'MiB of RAM')) config_iso = os.path.join(self.temp_dir, 'config.iso') self.check_diff(""" <ovf:File ovf:href="sample_cfg.txt" ovf:id="textfile" \ ovf:size="{cfg_size}" /> + <ovf:File ovf:href="config.iso" ovf:id="config.iso" \ ovf:size="{config_size}" /> </ovf:References> ... <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> + <rasd:Description>Configuration disk</rasd:Description> <rasd:ElementName>CD-ROM 2</rasd:ElementName> + <rasd:HostResource>ovf:/file/config.iso</rasd:HostResource> <rasd:InstanceID>8</rasd:InstanceID>""".format( cfg_size=self.FILE_SIZE['sample_cfg.txt'], config_size=os.path.getsize(config_iso))) if helpers['isoinfo']: self.assertEqual( DiskRepresentation.from_file(config_iso).files, [ "iosxr_config.txt", "iosxr_config_admin.txt", "minimal.ovf", "vmware.ovf", ]) else: logger.info("isoinfo not available, not checking disk contents")
def test_disk_conversion(self): """Make sure hard disk is converted to stream-optimized VMDK format.""" # Create a qcow2 image and add it as a new disk new_qcow2 = os.path.join(self.temp_dir, "new.qcow2") # Make it a small file to keep the test fast QCOW2.create_file(path=new_qcow2, capacity="16M") self.command.package = self.input_ovf self.command.disk_image = new_qcow2 self.command.controller = 'scsi' self.command.run() self.assertLogged(**self.DRIVE_TYPE_GUESSED_HARDDISK) self.command.finished() # Make sure the disk was converted and added to the OVF self.check_diff(""" <ovf:File ovf:href="sample_cfg.txt" ovf:id="textfile" \ ovf:size="{cfg_size}" /> + <ovf:File ovf:href="new.vmdk" ovf:id="new.vmdk" ovf:size="{new_size}" /> </ovf:References> ... <ovf:Disk ovf:capacity="1" ovf:capacityAllocationUnits="byte * 2^30" \ ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format=\ "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" /> + <ovf:Disk ovf:capacity="16" ovf:capacityAllocationUnits="byte * 2^20" \ ovf:diskId="new.vmdk" ovf:fileRef="new.vmdk" ovf:format=\ "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" /> </ovf:DiskSection> ... </ovf:Item> + <ovf:Item> + <rasd:AddressOnParent>1</rasd:AddressOnParent> + <rasd:ElementName>Hard Disk Drive</rasd:ElementName> + <rasd:HostResource>ovf:/disk/new.vmdk</rasd:HostResource> + <rasd:InstanceID>14</rasd:InstanceID> + <rasd:Parent>3</rasd:Parent> + <rasd:ResourceType>17</rasd:ResourceType> + </ovf:Item> </ovf:VirtualHardwareSection> """.format(cfg_size=self.FILE_SIZE['sample_cfg.txt'], new_size=os.path.getsize(os.path.join(self.temp_dir, "new.vmdk")))) # Make sure the disk was actually converted to the right format diskrep = DiskRepresentation.from_file(os.path.join(self.temp_dir, "new.vmdk")) self.assertEqual(diskrep.disk_format, 'vmdk') self.assertEqual(diskrep.disk_subformat, "streamOptimized")
def disk_image(self, value): self._disk_image = DiskRepresentation.from_file(value)
def test_predicted_drive_type(self): """Default prediction is 'harddisk'.""" self.assertEqual( 'harddisk', DiskRepresentation(path=self.blank_vmdk).predicted_drive_type)
def test_convert_to_errors(self): """Invalid inputs to convert_to().""" self.assertRaises( NotImplementedError, DiskRepresentation.from_file(self.blank_vmdk).convert_to, "frobozz", self.temp_dir)
def test_disk_representation_from_file_vmdk(self): """Test if DiskRepresentation.from_file() works for vmdk images.""" diskrep = DiskRepresentation.from_file(self.blank_vmdk) self.assertEqual(diskrep.disk_format, "vmdk") self.assertEqual(diskrep.disk_subformat, "streamOptimized")
def test_capacity_qemu_error(self, mock_check_output): """Test error handline if qemu-img reports an error.""" mock_check_output.return_value = "qemu-img info: unsupported command" with self.assertRaises(RuntimeError): assert DiskRepresentation(path=self.blank_vmdk).capacity
def test_files(self): """No default files getter logic.""" with self.assertRaises(NotImplementedError): assert DiskRepresentation(path=self.blank_vmdk).files
def run(self): """Do the actual work of this command. Raises: InvalidInputError: if :func:`ready_to_run` reports ``False`` ValueUnsupportedError: if the :const:`~COT.platforms.Platform.BOOTSTRAP_DISK_TYPE` of the associated VM's :attr:`~COT.vm_description.VMDescription.platform` is not 'cdrom' or 'harddisk' LookupError: if unable to find a disk drive device to inject the configuration into. """ super(COTInjectConfig, self).run() vm = self.vm platform = vm.platform # Find the disk drive where the config should be injected # First, look for any previously-injected config disk to overwrite: if platform.BOOTSTRAP_DISK_TYPE == 'cdrom': (fileelem, _, _, drive_device) = vm.search_from_filename( 'config.iso') elif platform.BOOTSTRAP_DISK_TYPE == 'harddisk': (fileelem, _, _, drive_device) = vm.search_from_filename( 'config.vmdk') else: raise ValueUnsupportedError("bootstrap disk drive type", platform.BOOTSTRAP_DISK_TYPE, "'cdrom' or 'harddisk'") if fileelem is not None: file_id = vm.get_id_from_file(fileelem) self.ui.confirm_or_die( "Existing configuration disk '{0}' found.\n" "Continue and overwrite it?".format(file_id)) logger.notice("Overwriting existing config disk '%s'", file_id) else: file_id = None # Find the empty slot where we should inject the config drive_device = vm.find_empty_drive(platform.BOOTSTRAP_DISK_TYPE) if drive_device is None: raise LookupError("Could not find an empty {0} drive to " "inject the config into" .format(platform.BOOTSTRAP_DISK_TYPE)) (cont_type, drive_address) = vm.find_device_location(drive_device) # Copy config file(s) to per-platform name in working directory config_files = [] if self.config_file: dest = os.path.join(vm.working_dir, platform.CONFIG_TEXT_FILE) shutil.copy(self.config_file, dest) config_files.append(dest) if self.secondary_config_file: dest = os.path.join(vm.working_dir, platform.SECONDARY_CONFIG_TEXT_FILE) shutil.copy(self.secondary_config_file, dest) config_files.append(dest) # Extra files are packaged as-is config_files += self.extra_files # Package the config files into a disk image # pylint:disable=redefined-variable-type if platform.BOOTSTRAP_DISK_TYPE == 'cdrom': bootstrap_file = os.path.join(vm.working_dir, 'config.iso') disk_format = 'iso' elif platform.BOOTSTRAP_DISK_TYPE == 'harddisk': bootstrap_file = os.path.join(vm.working_dir, 'config.img') disk_format = 'raw' else: raise ValueUnsupportedError("bootstrap disk drive type", platform.BOOTSTRAP_DISK_TYPE, "'cdrom' or 'harddisk'") disk_image = DiskRepresentation.for_new_file(bootstrap_file, disk_format, files=config_files) # Inject the disk image into the OVA, using "add-disk" functionality add_disk_worker( ui=self.ui, vm=vm, disk_image=disk_image, drive_type=platform.BOOTSTRAP_DISK_TYPE, file_id=file_id, controller=cont_type, address=drive_address, subtype=None, description='Configuration disk', diskname=None, )