@@ -58,6 +58,9 @@ def __init__(self, connection):
5858 self ._original_devices_type = []
5959 self ._original_xml = None
6060
61+ # Deliberately private: user doesn't need to know this
62+ self ._original_devices_idx = []
63+
6164 # clone guest
6265 self ._clone_name = None
6366 self ._clone_devices = []
@@ -211,11 +214,13 @@ def setup_original(self):
211214 # Pull clonable storage info from the original xml
212215 self ._original_devices , \
213216 self ._original_devices_size ,\
214- self ._original_devices_type = self ._get_original_devices_info (self ._original_xml )
217+ self ._original_devices_type ,\
218+ self ._original_devices_idx = self ._get_original_devices_info (self ._original_xml )
215219
216220 logging .debug ("Original paths: %s" % (self ._original_devices ))
217221 logging .debug ("Original sizes: %s" % (self ._original_devices_size ))
218222 logging .debug ("Original types: %s" % (self ._original_devices_type ))
223+ logging .debug ("Original idxs: %s" % (self ._original_devices_idx ))
219224
220225 # Check original domain is SHUTOFF
221226 # XXX: Shouldn't pause also be fine, and guests with no storage/
@@ -278,16 +283,14 @@ def setup_clone(self):
278283
279284 # Changing storage paths
280285 clone_devices = iter (self ._clone_devices )
281- count = ctx .xpathEval ("count(/domain/devices/disk)" )
282- for i in range (1 , int (count + 1 )):
283- node = self ._get_available_cloning_device (ctx , i , self ._force_target )
284- if node == None :
285- continue
286+ for i in self ._original_devices_idx :
287+ node = ctx .xpathEval ("/domain/devices/disk[%d]/source" % i )
286288 node = node [0 ].get_properties ()
287289 try :
288290 node .setContent (clone_devices .next ())
289291 except Exception :
290- raise ValueError , _ ("Missing new file to use disk image for %s" ) % node .getContent ()
292+ raise ValueError , _ ("Missing new file to use disk image "
293+ "for %s" ) % node .getContent ()
291294
292295 # changing uuid
293296 node = ctx .xpathEval ("/domain/uuid" )
@@ -320,7 +323,9 @@ def setup_clone(self):
320323 # Change xml disk type values if original and clone disk types
321324 # (block/file) don't match
322325 self ._change_disk_type (self ._original_devices_type ,
323- self ._clone_devices_type , ctx )
326+ self ._clone_devices_type ,
327+ self ._original_devices_idx ,
328+ ctx )
324329
325330 # Save altered clone xml
326331 self ._clone_xml = str (doc )
@@ -357,12 +362,13 @@ def _check_mac(self, mac):
357362 # Parse disk paths that need to be cloned from the original guest's xml
358363 # Return a tuple of lists:
359364 # ([list of paths to clone], [size of those paths],
360- # [file/block type of those paths])
365+ # [file/block type of those paths], [indices of disks to be cloned] )
361366 def _get_original_devices_info (self , xml ):
362367
363368 lst = []
364369 size = []
365370 typ = []
371+ idx_lst = []
366372
367373 doc = libxml2 .parseDoc (xml )
368374 ctx = doc .xpathNewContext ()
@@ -373,6 +379,7 @@ def _get_original_devices_info(self, xml):
373379 node = self ._get_available_cloning_device (ctx , i , self ._force_target )
374380 if node == None :
375381 continue
382+ idx_lst .append (i )
376383 lst .append (node [0 ].get_properties ().getContent ())
377384 finally :
378385 if ctx is not None :
@@ -386,7 +393,7 @@ def _get_original_devices_info(self, xml):
386393 typ .append (t )
387394 size .append (sz )
388395
389- return (lst , size , typ )
396+ return (lst , size , typ , idx_lst )
390397
391398 # Pull disk #i from the original guest xml, return it's xml
392399 # if it should be cloned (skips readonly, empty, or sharable disks
@@ -436,18 +443,21 @@ def _local_paths_info(self, paths_lst):
436443
437444 # Check if original disk type (file/block) is different from
438445 # requested clones disk type, and alter xml if needed
439- def _change_disk_type (self , org_type , cln_type , ctx ):
440-
441- for i in range (len (org_type )):
442- disk_type = ctx .xpathEval ("/domain/devices/disk[%d]/@type" % (i + 1 ))
443- driv_name = ctx .xpathEval ("/domain/devices/disk[%d]/driver/@name" % (i + 1 ))
444- src = ctx .xpathEval ("/domain/devices/disk[%d]/source" % (i + 1 ))
446+ def _change_disk_type (self , org_type , cln_type , idxs , ctx ):
447+
448+ type_idx = 0
449+ for dev_idx in idxs :
450+ disk_type = ctx .xpathEval ("/domain/devices/disk[%d]/@type" %
451+ dev_idx )
452+ driv_name = ctx .xpathEval ("/domain/devices/disk[%d]/driver/@name" %
453+ dev_idx )
454+ src = ctx .xpathEval ("/domain/devices/disk[%d]/source" % dev_idx )
445455 src_chid_txt = src [0 ].get_properties ().getContent ()
446456
447457 # different type
448- if org_type [i ] != cln_type [i ]:
458+ if org_type [type_idx ] != cln_type [type_idx ]:
449459 # changing from file to disk
450- if org_type [i ] == True :
460+ if org_type [type_idx ] == True :
451461 disk_type [0 ].setContent ("block" )
452462 driv_name [0 ].setContent ("phy" )
453463 src [0 ].get_properties ().unlinkNode ()
@@ -459,6 +469,8 @@ def _change_disk_type(self, org_type, cln_type, ctx):
459469 src [0 ].get_properties ().unlinkNode ()
460470 src [0 ].newProp ("file" , src_chid_txt )
461471
472+ type_idx += 1
473+
462474#
463475# start duplicate
464476# this function clones the virtual machine according to the ClonDesign object
0 commit comments