def test_concurrent_copy_image(self): concurrency = 3 atomic_lock = threading.Lock() results = {"ok": 0, "existed": 0} datastore = self._find_configured_datastore_in_host_config() new_image_id = "concurrent-copy-%s" % str(uuid.uuid4()) src_image = Image("ttylinux", datastore) dst_image = Image(new_image_id, datastore) # verify destination_id is not in datastore request = Host.GetImagesRequest(datastore.id) response = self.host_client.get_images(request) assert_that(response.result, is_(GetImagesResultCode.OK)) assert_that(response.image_ids, has_item("ttylinux")) assert_that(response.image_ids, not (has_item(new_image_id))) image_number = len(response.image_ids) def _thread(): client = self.create_client() request = Host.CopyImageRequest(src_image, dst_image) response = client.copy_image(request) ok = response.result == CopyImageResultCode.OK existed = response.result == CopyImageResultCode.\ DESTINATION_ALREADY_EXIST # Verify destination_id is in datastore request = Host.GetImagesRequest(datastore.id) response = client.get_images(request) assert_that(response.result, is_(GetImagesResultCode.OK)) assert_that(response.image_ids, has_item("ttylinux")) assert_that(response.image_ids, has_item(new_image_id)) assert_that(response.image_ids, has_length(image_number + 1)) with atomic_lock: if ok: results["ok"] += 1 if existed: results["existed"] += 1 threads = [] for i in range(concurrency): thread = threading.Thread(target=_thread) threads.append(thread) thread.start() for thread in threads: thread.join() # Clean destination image self._delete_image(dst_image) # Only one copy is successful, all others return # DESTINATION_ALREADY_EXIST assert_that(results["ok"], is_(1)) assert_that(results["existed"], is_(concurrency - 1))
def clean_images(self): """ Clean up images if there are any """ datastore = self._find_configured_datastore_in_host_config() request = Host.GetImagesRequest(datastore.id) response = self.host_client.get_images(request) if response.result == GetImagesResultCode.OK: for image_id in response.image_ids: if image_id == "ttylinux": continue # To be removed when we remove ttylinux. logging.info("Cleaning up stray image %s " % image_id) self._delete_image(Image(image_id, datastore)) else: logger.warning("Failed to obtain the list of images to cleanup")
def test_finalize_image(self): """ Integration test for atomic image create """ img_id = "test-create-image" tmp_img_id = "-tmp-" + img_id tmp_image, ds = self._create_test_image(tmp_img_id) tmp_image_path = datastore_path(ds.name, "image_" + tmp_img_id) src_vmdk = vmdk_path(ds.id, tmp_img_id, IMAGE_FOLDER_NAME_PREFIX) dst_vmdk = "%s/%s.vmdk" % (tmp_image_path, img_id) try: self._manage_disk(vim.VirtualDiskManager.MoveVirtualDisk_Task, sourceName=src_vmdk, destName=dst_vmdk, force=True) except: logger.error("Error moving vmdk %s" % src_vmdk, exc_info=True) self._manage_disk(vim.VirtualDiskManager.DeleteVirtualDisk_Task, name=src_vmdk) raise dst_image = Image(img_id, ds) req = FinalizeImageRequest(image_id=img_id, datastore=ds.id, tmp_image_path=tmp_image_path) response = self.host_client.finalize_image(req) self.assertEqual(response.result, FinalizeImageResultCode.OK) request = Host.GetImagesRequest(ds.id) response = self.host_client.get_images(request) assert_that(response.result, is_(GetImagesResultCode.OK)) assert_that(response.image_ids, has_item(img_id)) # Issue another create call and it should fail as the source doesn't # exist. req = FinalizeImageRequest(image_id=img_id, datastore=ds.id, tmp_image_path=tmp_image_path) response = self.host_client.finalize_image(req) self.assertEqual(response.result, FinalizeImageResultCode.IMAGE_NOT_FOUND) # Verify that we fail if the destination already exists. tmp_image, ds = self._create_test_image(tmp_img_id) req = FinalizeImageRequest(image_id=img_id, datastore=ds.id, tmp_image_path=tmp_image_path) response = self.host_client.finalize_image(req) self.assertEqual(response.result, FinalizeImageResultCode.DESTINATION_ALREADY_EXIST) # cleanup self._delete_image(dst_image)
def _thread(): client = self.create_client() request = Host.CopyImageRequest(src_image, dst_image) response = client.copy_image(request) ok = response.result == CopyImageResultCode.OK existed = response.result == CopyImageResultCode.\ DESTINATION_ALREADY_EXIST # Verify destination_id is in datastore request = Host.GetImagesRequest(datastore.id) response = client.get_images(request) assert_that(response.result, is_(GetImagesResultCode.OK)) assert_that(response.image_ids, has_item("ttylinux")) assert_that(response.image_ids, has_item(new_image_id)) assert_that(response.image_ids, has_length(image_number + 1)) with atomic_lock: if ok: results["ok"] += 1 if existed: results["existed"] += 1
def test_get_images_datastore_not_found(self): request = Host.GetImagesRequest("datastore_not_there") response = self.host_client.get_images(request) assert_that(response.result, is_( GetImagesResultCode.DATASTORE_NOT_FOUND))
def test_copy_image_get_images(self): datastore = self._find_configured_datastore_in_host_config() assert_that(datastore, not_none()) # ttylinux is the default image that is copied to datastore1 # when agent starts src_image = Image("ttylinux", datastore) dst_image = Image("test-copy-image", datastore) # verify test-copy-image is not in datastore request = Host.GetImagesRequest(datastore.id) response = self.host_client.get_images(request) assert_that(response.result, is_(GetImagesResultCode.OK)) assert_that(response.image_ids, has_item("ttylinux")) assert_that(response.image_ids, not(has_item("test-copy-image"))) image_number = len(response.image_ids) # Copy image request = Host.CopyImageRequest(src_image, dst_image) response = self.host_client.copy_image(request) assert_that(response.result, is_(CopyImageResultCode.OK)) # Copy image the second time should return DESTINATION_ALREADY_EXIST request = Host.CopyImageRequest(src_image, dst_image) response = self.host_client.copy_image(request) assert_that(response.result, is_(CopyImageResultCode.DESTINATION_ALREADY_EXIST)) # Verify test-copy-image is in datastore request = Host.GetImagesRequest(datastore.id) response = self.host_client.get_images(request) assert_that(response.result, is_(GetImagesResultCode.OK)) assert_that(response.image_ids, has_item("ttylinux")) assert_that(response.image_ids, has_item("test-copy-image")) assert_that(response.image_ids, has_length(image_number + 1)) # Create VM image = DiskImage("test-copy-image", CloneType.COPY_ON_WRITE) disks = [ Disk(new_id(), self.DEFAULT_DISK_FLAVOR.name, False, True, image=image, capacity_gb=0, flavor_info=self.DEFAULT_DISK_FLAVOR), ] vm_wrapper = VmWrapper(self.host_client) reservation = vm_wrapper.place_and_reserve(vm_disks=disks).reservation request = vm_wrapper.create_request(res_id=reservation) response = vm_wrapper.create(request=request) assert_that(response.vm, not_none()) # Delete VM vm_wrapper.delete(request=vm_wrapper.delete_request(disk_ids=[])) # Verify test-copy-image is in datastore request = Host.GetImagesRequest(datastore.id) response = self.host_client.get_images(request) assert_that(response.result, is_(GetImagesResultCode.OK)) assert_that(response.image_ids, has_item("ttylinux")) assert_that(response.image_ids, has_item("test-copy-image")) assert_that(response.image_ids, has_length(image_number + 1)) # Copy image using datastore with name as id should succeed # This datastore object uses the datastore name as its id datastore.id = datastore.name dst_image2 = Image("test-copy-image2", datastore) request = Host.CopyImageRequest(src_image, dst_image2) response = self.host_client.copy_image(request) assert_that(response.result, is_(CopyImageResultCode.OK)) # Clean destination image self._delete_image(dst_image) self._delete_image(dst_image2)
def test_create_image_from_vm(self): """ Integration test for creating an image from a VM """ img_id = "test-new-im-from-vm-%s" % new_id() tmp_img_id = "-tmp-" + img_id tmp_image, ds = self._create_test_image(tmp_img_id) tmp_image_path = datastore_path(ds.id, "image_" + tmp_img_id) src_vmdk = vmdk_path(ds.id, tmp_img_id, IMAGE_FOLDER_NAME_PREFIX) vm_wrapper = VmWrapper(self.host_client) try: self._manage_disk(vim.VirtualDiskManager.DeleteVirtualDisk_Task, name=src_vmdk) except: logger.error("Error deleting vmdk when setting up tmp image %s" % src_vmdk, exc_info=True) raise dst_image = Image(img_id, ds) image = DiskImage("ttylinux", CloneType.COPY_ON_WRITE) disks = [ Disk(new_id(), self.DEFAULT_DISK_FLAVOR.name, False, True, image=image, capacity_gb=0, flavor_info=self.DEFAULT_DISK_FLAVOR), Disk(new_id(), self.DEFAULT_DISK_FLAVOR.name, True, True, capacity_gb=1, flavor_info=self.DEFAULT_DISK_FLAVOR), Disk(new_id(), self.DEFAULT_DISK_FLAVOR.name, True, True, capacity_gb=2, flavor_info=self.DEFAULT_DISK_FLAVOR) ] reservation = vm_wrapper.place_and_reserve(vm_disks=disks).reservation request = vm_wrapper.create_request(res_id=reservation) vm_wrapper.create(request=request) # VM in wrong state vm_wrapper.power(Host.PowerVmOp.ON, Host.PowerVmOpResultCode.OK) time.sleep(10) vm_wrapper.create_image_from_vm( image_id=img_id, datastore=ds.id, tmp_image_path=tmp_image_path, expect=Host.CreateImageFromVmResultCode.INVALID_VM_POWER_STATE) vm_wrapper.power(Host.PowerVmOp.OFF, Host.PowerVmOpResultCode.OK) time.sleep(10) # Happy case vm_wrapper.create_image_from_vm( image_id=img_id, datastore=ds.id, tmp_image_path=tmp_image_path, expect=Host.CreateImageFromVmResultCode.OK) request = Host.GetImagesRequest(ds.id) response = self.host_client.get_images(request) assert_that(response.result, is_(GetImagesResultCode.OK)) assert_that(response.image_ids, has_item(img_id)) # Issue another create call and it should fail as the source doesn't # exist. req = FinalizeImageRequest(image_id=img_id, datastore=ds.id, tmp_image_path=tmp_image_path) response = self.host_client.finalize_image(req) self.assertEqual(response.result, FinalizeImageResultCode.IMAGE_NOT_FOUND) # Verify that we fail if the destination already exists. tmp_image, ds = self._create_test_image(tmp_img_id) vm_wrapper.create_image_from_vm( image_id=tmp_img_id, datastore=ds.id, tmp_image_path=tmp_image_path, expect=Host.CreateImageFromVmResultCode.IMAGE_ALREADY_EXIST) vm_wrapper.delete() # VM to create image from is gone. vm_wrapper.create_image_from_vm( image_id=img_id, datastore=ds.id, tmp_image_path=tmp_image_path, expect=Host.CreateImageFromVmResultCode.VM_NOT_FOUND) # Create a VM using the new image created vm_wrapper2 = VmWrapper(self.host_client) image = DiskImage(img_id, CloneType.COPY_ON_WRITE) disks = [ Disk(new_id(), self.DEFAULT_DISK_FLAVOR.name, False, True, image=image, capacity_gb=0, flavor_info=self.DEFAULT_DISK_FLAVOR), ] reservation = vm_wrapper2.place_and_reserve(vm_disks=disks).reservation request = vm_wrapper2.create_request(res_id=reservation) vm_wrapper2.create(request=request) vm_wrapper2.power(Host.PowerVmOp.ON, Host.PowerVmOpResultCode.OK) vm_wrapper2.power(Host.PowerVmOp.OFF, Host.PowerVmOpResultCode.OK) vm_wrapper2.delete() # cleanup self._delete_image(dst_image)