Skip to content

Commit

Permalink
storage: extract single volume clone into clone_volume
Browse files Browse the repository at this point in the history
This will be useful for admin.vm.volume.Clone implementation.

QubesOS/qubes-issues#2256
  • Loading branch information
marmarek committed Jun 19, 2017
1 parent 93ccb8b commit f48b1be
Showing 1 changed file with 32 additions and 34 deletions.
66 changes: 32 additions & 34 deletions qubes/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,46 +431,44 @@ def create(self):
os.umask(old_umask)

@asyncio.coroutine
def clone(self, src_vm):
''' Clone volumes from the specified vm '''
def clone_volume(self, src_vm, name):
''' Clone single volume from the specified vm
:param QubesVM src_vm: source VM
:param str name: name of volume to clone ('root', 'private' etc)
:return cloned volume object
'''
config = self.vm.volume_config[name]
dst_pool = self.vm.app.get_pool(config['pool'])
dst = dst_pool.init_volume(self.vm, config)
src_volume = src_vm.volumes[name]
src_pool = src_volume.pool
if dst_pool == src_pool:
msg = "Cloning volume {!s} from vm {!s}"
self.vm.log.info(msg.format(src_volume.name, src_vm.name))
clone_op_ret = dst_pool.clone(src_volume, dst)
else:
msg = "Importing volume {!s} from vm {!s}"
self.vm.log.info(msg.format(src_volume.name, src_vm.name))
clone_op_ret = dst_pool.import_volume(
dst_pool, dst, src_pool, src_volume)

# clone/import functions may be either synchronous or asynchronous
# in the later case, we need to wait for them to finish
clone_op = {}
if asyncio.iscoroutine(clone_op_ret):
self.vm.volumes[name] = yield from clone_op_ret
else:
self.vm.volumes[name] = clone_op_ret
return self.vm.volumes[name]

@asyncio.coroutine
def clone(self, src_vm):
''' Clone volumes from the specified vm '''

self.vm.volumes = {}
with VmCreationManager(self.vm):
for name, config in self.vm.volume_config.items():
dst_pool = self.vm.app.get_pool(config['pool'])
dst = dst_pool.init_volume(self.vm, config)
src_volume = src_vm.volumes[name]
src_pool = src_volume.pool
if dst_pool == src_pool:
msg = "Cloning volume {!s} from vm {!s}"
self.vm.log.info(msg.format(src_volume.name, src_vm.name))
clone_op_ret = dst_pool.clone(src_volume, dst)
else:
msg = "Importing volume {!s} from vm {!s}"
self.vm.log.info(msg.format(src_volume.name, src_vm.name))
clone_op_ret = dst_pool.import_volume(
dst_pool, dst, src_pool, src_volume)
if asyncio.iscoroutine(clone_op_ret):
clone_op[name] = asyncio.ensure_future(clone_op_ret)

yield from asyncio.wait(x for x in clone_op.values()
if inspect.isawaitable(x))

for name, clone_op_ret in clone_op.items():
if inspect.isawaitable(clone_op_ret):
volume = clone_op_ret.result
else:
volume = clone_op_ret

assert volume, "%s.clone() returned '%s'" % (
self.vm.app.get_pool(self.vm.volume_config[name]['pool']).
__class__.__name__, volume)

self.vm.volumes[name] = volume
yield from asyncio.wait(self.clone_volume(src_vm, vol_name)
for vol_name in self.vm.volume_config.keys())

@property
def outdated_volumes(self):
Expand Down

0 comments on commit f48b1be

Please sign in to comment.