storage: allow import_data and import_data_end be coroutines
On some storage pools this operation can also be time consuming - for example require creating temporary volume, and volume.create() already can be a coroutine. This is also requirement for making common code used by start()/create() etc be a coroutine, otherwise neither of them can be and will block other operations. Related to QubesOS/qubes-issues#4283
This commit is contained in:
parent
295705a708
commit
6170edb291
@ -479,7 +479,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
if not self.dest.is_halted():
|
if not self.dest.is_halted():
|
||||||
raise qubes.exc.QubesVMNotHaltedError(self.dest)
|
raise qubes.exc.QubesVMNotHaltedError(self.dest)
|
||||||
|
|
||||||
path = self.dest.storage.import_data(self.arg)
|
path = yield from self.dest.storage.import_data(self.arg)
|
||||||
assert ' ' not in path
|
assert ' ' not in path
|
||||||
size = self.dest.volumes[self.arg].size
|
size = self.dest.volumes[self.arg].size
|
||||||
|
|
||||||
|
@ -68,7 +68,8 @@ class QubesInternalAPI(qubes.api.AbstractQubesAPI):
|
|||||||
success = untrusted_payload == b'ok'
|
success = untrusted_payload == b'ok'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.dest.storage.import_data_end(self.arg, success=success)
|
yield from self.dest.storage.import_data_end(self.arg,
|
||||||
|
success=success)
|
||||||
except:
|
except:
|
||||||
self.dest.fire_event('domain-volume-import-end', volume=self.arg,
|
self.dest.fire_event('domain-volume-import-end', volume=self.arg,
|
||||||
success=False)
|
success=False)
|
||||||
|
@ -198,6 +198,8 @@ class Volume:
|
|||||||
volume data require something more than just writing to a file (
|
volume data require something more than just writing to a file (
|
||||||
for example connecting to some other domain, or converting data
|
for example connecting to some other domain, or converting data
|
||||||
on the fly), the returned path may be a pipe.
|
on the fly), the returned path may be a pipe.
|
||||||
|
|
||||||
|
This can be implemented as a coroutine.
|
||||||
'''
|
'''
|
||||||
raise self._not_implemented("import")
|
raise self._not_implemented("import")
|
||||||
|
|
||||||
@ -207,6 +209,8 @@ class Volume:
|
|||||||
|
|
||||||
This method is called regardless the operation was successful or not.
|
This method is called regardless the operation was successful or not.
|
||||||
|
|
||||||
|
This can be implemented as a coroutine.
|
||||||
|
|
||||||
:param success: True if data import was successful, otherwise False
|
:param success: True if data import was successful, otherwise False
|
||||||
'''
|
'''
|
||||||
# by default do nothing
|
# by default do nothing
|
||||||
@ -654,24 +658,34 @@ class Storage:
|
|||||||
|
|
||||||
return self.vm.volumes[volume].export()
|
return self.vm.volumes[volume].export()
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
def import_data(self, volume):
|
def import_data(self, volume):
|
||||||
''' Helper function to import volume data (pool.import_data(volume))'''
|
''' Helper function to import volume data (pool.import_data(volume))'''
|
||||||
assert isinstance(volume, (Volume, str)), \
|
assert isinstance(volume, (Volume, str)), \
|
||||||
"You need to pass a Volume or pool name as str"
|
"You need to pass a Volume or pool name as str"
|
||||||
if isinstance(volume, Volume):
|
if isinstance(volume, Volume):
|
||||||
return volume.import_data()
|
ret = volume.import_data()
|
||||||
|
else:
|
||||||
|
ret = self.vm.volumes[volume].import_data()
|
||||||
|
|
||||||
return self.vm.volumes[volume].import_data()
|
if asyncio.iscoroutine(ret):
|
||||||
|
ret = yield from ret
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
def import_data_end(self, volume, success):
|
def import_data_end(self, volume, success):
|
||||||
''' Helper function to finish/cleanup data import
|
''' Helper function to finish/cleanup data import
|
||||||
(pool.import_data_end( volume))'''
|
(pool.import_data_end( volume))'''
|
||||||
assert isinstance(volume, (Volume, str)), \
|
assert isinstance(volume, (Volume, str)), \
|
||||||
"You need to pass a Volume or pool name as str"
|
"You need to pass a Volume or pool name as str"
|
||||||
if isinstance(volume, Volume):
|
if isinstance(volume, Volume):
|
||||||
return volume.import_data_end(success=success)
|
ret = volume.import_data_end(success=success)
|
||||||
|
else:
|
||||||
|
ret = self.vm.volumes[volume].import_data_end(success=success)
|
||||||
|
|
||||||
return self.vm.volumes[volume].import_data_end(success=success)
|
if asyncio.iscoroutine(ret):
|
||||||
|
ret = yield from ret
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class VolumesCollection:
|
class VolumesCollection:
|
||||||
|
Loading…
Reference in New Issue
Block a user