On 02/21/2011 03:23 AM, KAMEZAWA Hiroyuki wrote: > Hi, now, with qemu, virsh attach-disk doesn't work with inactive disks and > we need to edit XML with virsh edit. > IIUC, libvirt and virsh is designed as it is. > > But I want to modify domain XML via commandline tools > - for middleware, which modify domains by scripting. > - for concsoles, where curses can't work correctly. > - for me, I can't remember XML definition detaisl ;) > > So, I write one. > > Following script is a script for modify domain XML and allows > - add disks > - delete disks > - show list of disks > > I think most of elements defined in http://libvirt.org/formatdomain.html#elementsDisks > is supported. But I'm an only qemu user and didn't test with Xen and other VMs. > > What I wanted to hear opinions as 'RFC' is > - Can this be shipped with libvirt as one of a tool ? (with more documents) > (If so, we'll write other scripts for cpu,network,memory,etc...) > > - If not, what is the best way other than making this as my house script ? > I'm grad if this is shipped with libvirt is because catching new definition > of XML is easy. > > - Doesn't this one work with your environment ? > > Thanks for taking a stab at this, I've been meaning to start a similar tool for some time. However, you should be able to leverage virtinst to accomplish nearly all the XML parsing, and reuse existing virt-install command line options and documentation. Additionally the tool could build or edit any arbitrary domain XML and wouldn't be specific to disks. Take a look at tests/xmlparse.py in the virtinst repo to see how the parsing works and what it's capable of. Thanks, Cole > > Example) > [root@bluextal pydom]# ./virt-disk.py --domain Guest02 --virtio --source /dev/iscsi_lvm/disk02 > Name : vdb > Device Type : block > Media Type : disk > Bus Type : virtio > Driver Name : qemu > Driver Type : raw > Driver Cache : default > ReadWrite : ReadWrite > Source : /dev/iscsi_lvm/disk02 > Address: : AutoFill > Add this device Y/N ? y > > [root@bluextal pydom]# virsh dumpxml Guest02 > <domain type='kvm'> > ..... > <disk type='block' device='disk'> > <driver name='qemu' type='raw'/> > <source dev='/dev/iscsi_lvm/disk02'/> > <target dev='vdb' bus='virtio'/> > <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> > </disk> > == > > Thanks, > -Kame > > == > #!/usr/bin/python > # > # > # 'virt-disk' is a command for maintaining disk entities in XML description > # of libvirt's VM definition. Default vm assumes 'qemu' > # > # Copyright (C) 2011 Fujitsu LTD. > # > # KAMEZAWA Hiroyuki <kamezawa.hiroyu@xxxxxxxxxxxxxx> > # > # Usage: > # > # Brief help is > # %virt-disk --help > # > # When you want to see list of disks of domain > # %virt-disk --domain <domain name> --list > # > # When you want to remove 'vdb' > # %virt-disk --domain <domain name> --delete vdb > # > # When you want to add block device as virtio block device. > # %virt-disk --domain <domain name> --virtio --source /dev/to/mydisk > # > # When you want to add an IDE cdrom > # %virt-disk --domain <domain name> --ide --media cdrom > # --source /path/to/ISO.img > # > # When you want to add a network image as virtio disk. > # %virt-disk --domain <domain name> --type network --protocol sheepdog > # --host address:port --source resource_name --virtio > # > # This commad does > # > # - parse options. > # - connect libvirt and get domain xml > # - add all devices to disks[] List. > # - add all pci address to PCIS[] List > # - create new BlockDevice object with regard to options. > # - create a XML entry of device > # - insert and save it. > # > > import xml.dom > import xml.dom.minidom > import os > import stat > import sys > import libvirt > import re,string > from xml.dom import Node > from optparse import OptionParser,OptionGroup > > PCIS = [] > disks = [] > > class Address : > pci = [] > drive = [] > def __init__(self, type) : > self.type = type > self.domain = None > self.bus = None > self.slot = None > self.function = None > self.controller = None > self.function = None > if type == 'pci' : > PCIS.append(self) > > class BlockDevice : > def __init__(self) : > self.type = None > self.media = None > self.driver_cache = None > self.driver_name = None > self.driver_type = None > self.driver_error_policy = None > self.driver_io = None > self.source = None > self.protocol = None > self.protocol_addr = None > self.protocol_port = None > self.target_dev = None > self.target_bus = None > self.readonly = False > self.address_type = None > self.address_bus = '' > self.address_domain = '' > self.address_function = '' > self.address_slot = '' > self.address_controller= '' > self.address_unit='' > self.boot_order = None > self.shareable = False > self.serial = None > self.encrypt_format = None > self.encrypt_type = None > self.encrypt_uuid = None > > def get_attr(self, name, attr) : > x = name.getAttribute(attr) > if x == '' : > return None > return x > > def find_element(self, ent, name) : > for member in ent.childNodes : > if member.nodeName == name : > return member > return None > > def parse_info(self, name) : > # parsing <disk ..... > self.type = self.get_attr(name, 'type') > self.media = self.get_attr(name, 'device') > # parsing <driver .... > driver = self.find_element(name, 'driver') > if driver != None : > self.driver_name = self.get_attr(driver, 'name') > if self.driver_name == 'qemu' : > self.driver_type = self.get_attr(driver, 'type') > self.driver_cache = self.get_attr(driver, 'cache') > self.driver_error_policy =\ > self.get_attr(driver, 'error_policy') > self.driver_io = self.get_attr(driver, 'io') > # parsing <source > source = self.find_element(name, 'source') > if source != None : > self.source = self.get_attr(source, 'dev') > if self.source == None : > self.source = self.get_attr(source, 'file') > if self.source == None : > self.protocol = self.get_attr(source, 'protocol') > self.source = self.get_attr(source, 'name') > else : > self.source = None > # > # check protocol and host, port > # > if self.protocol != None : > source = self.find_element(name, 'source') > host = self.find_element(source, 'host') > if host != None : > self.protocol_host = self.get_attr(host, 'host') > self.protocol_port = self.get_attr(host, 'port') > # parsing <target > target = self.find_element(name, 'target') > if target != None : > self.target_dev = self.get_attr(target, 'dev') > self.target_bus = self.get_attr(target, 'bus') > # check readonly > if self.find_element(name, 'readonly') != None : > self.readonly = True > # check shareable > if self.find_element(name, 'shareable') != None: > self.shareable = True > # check boot order > boot = self.find_element(name, 'boot') > if boot != None : > self.boot_order = self.get_attr(boot, 'order') > # check shareable > if self.find_element(name, 'shareable') != None : > self.shareable = True > # check address > address = self.find_element(name, 'address') > if address != None : > self.address_type = self.get_attr(address, 'type') > if self.address_type == 'pci' : > self.address_bus = self.get_attr(address, 'bus') > self.address_slot = self.get_attr(address, 'slot') > self.address_function = self.get_attr(address, 'function') > self.address_domain = self.get_attr(address, 'domain') > elif self.address_type == 'drive' : > self.address_bus = self.get_attr(address, 'bus') > self.address_controller = self.get_attr(address, 'controller') > self.address_unit = self.get_attr(address, 'unit') > # check serial ID > serial = self.find_element(name, 'serial') > if serial != None : > for member in serial.childNodes : > if member.nodeType == Node.TEXT_NODE : > self.serial = member.data > # check encryption > encrypt = self.find_element(name, 'encryption') > if encrypt != None : > self.encrypt_format = self.get_attr(encrypt, 'format') > sec = self.find_element(encrypt, 'secret') > if sec != None : > self.encrypt_type = self.get_attr(sec, 'type') > self.encrypt_uuid = self.get_attr(sec, 'uuid') > > return True > > def show_ent(self, name, value) : > if value != None : > print '%-16s:\t%s' %(name, value) > > def show(self) : > self.show_ent('Name', self.target_dev) > self.show_ent('Device Type', self.type) > self.show_ent('Media Type', self.media) > self.show_ent('Bus Type', self.target_bus) > self.show_ent('Driver Name', self.driver_name) > self.show_ent('Driver Type', self.driver_type) > self.show_ent('Driver Cache', self.driver_cache) > self.show_ent('Driver I/O', self.driver_io) > self.show_ent('Error Policy', self.driver_error_policy) > if self.readonly : > self.show_ent('ReadWrite', 'ReadOnly') > else : > self.show_ent('ReadWrite', 'ReadWrite') > if self.shareable : > self.show_ent('Shareable', 'Yes') > self.show_ent('Device Boot Order',self.boot_order) > self.show_ent('Protocol', self.protocol) > self.show_ent('Hostname', self.protocol_addr) > self.show_ent('Port', self.protocol_port) > self.show_ent('Source', self.source) > > if self.address_type == None : > self.show_ent('Address:', 'AutoFill') > elif self.address_type == 'pci' : > x = '%s/%s/%s' %\ > (self.address_bus, self.address_slot, self.address_function) > self.show_ent('PCI Address', x) > elif self.address_type == 'drive' : > x = '%s/%s/%s'\ > %(self.address_controller, self.address_bus, self.address_unit) > self.show_ent('Drive Index', x) > > if self.serial != None : > self.show_ent('Serial', self.serial) > > if self.encrypt_format != None : > self.show_ent('Encryption', self.encrypt_format) > self.show_ent(' Type', self.encrypt_type) > self.show_ent(' UUID', self.encrypt_uuid) > > def is_block_device(node) : > if node.nodeName == 'disk' : > return True > return False > > def parse_address(addr) : > type = addr.getAttribute('type') > ent = Address(type) > if ent.type == 'pci' : > ent.bus = addr.getAttribute('bus') > ent.slot = addr.getAttribute('slot') > ent.function = addr.getAttribute('function') > ent.domain = addr.getAttribute('domain') > elif ent.type == 'drive' : > ent.controller = addr.getAttribute('controller') > ent.bus = addr.getAttribute('bus') > ent.unit = addr.getAttribute('unit') > # Nothing happens > return True > > def check_pci_conflict(bus, slot, function) : > sloti = int(slot, 16) > for addr in PCIS : > if int(addr.slot, 16) == sloti : > return True > return False > > def get_free_pci_slot(devname) : > for i in range(3, 31) : #qemu allows only 32 slots > x = str(i) > if not check_pci_conflict('0x00', x, '0x00') : > slot = '0x%02x'%(i) > return ['0x00', slot, '0x00'] > return [] > > def check_get_free_scsi_slot(index) : > addr = scsi_index_to_addr(index) > conflict = False > for disk in disks : > if disk.target_device != scsi: > continue > if disk.target_controller == addr[0] and\ > disk.target_bus == addr[1] and\ > disk.target_units == addr[2] : > conflict = True > break > if conflict == False: > return addr > return [] > > def check_drive_conflict(type, controller, bus, unit) : > for addr in drives : > conflict = False > for disk in disks : > if disk.target_bus != 'type' : > continue > if disk.address_controller == controller and\ > disk.address_bus == bus and\ > disk.address_unit == unit : > conflict = True > break > return conflict > return True > > > def check_device_conflict(devices, name) : > for dev in devices : > if dev.target_dev == name : > return True > return False > > def gen_scsi_name_from_index(index) : > name = 'sd' > if index < 26 : > name = name + chr(ord('a') + index) > elif index < (26 + (26 * 26)) : > x = index / 26 - 1 > y = index % 26 > name = name + chr(ord('a') + x) > name = name + chr(ord('a') + y) > else : > x = (index / 26 - 1) / 26 - 1 > y = (index / 26 - 1) % 26 > x = index % 26 > name = name + chr(ord('a') + x) > name = name + chr(ord('a') + y) > name = name + chr(ord('a') + z) > return name > > def gen_device_name(devices, head) : > if head == 'hd' : > for x in 'abcd' : > name = 'hd' + x > if not check_device_conflict(devices, name) : > return name > if head == 'vd' : > for x in range(0, 26) : > name = head + chr(ord('a') + x) > if not check_device_conflict(devices, name) : > return name > if head == 'sd' : > for index in range(0, 18278) : > name = gen_scsi_name_from_index(index) > if not check_device_conflict(devices, name) : > return name > return None > > # > # Commandline Parser > # Using optparse package. Deafault value is below. > # > usage='usage:%prog --domain Domain <options>....' > parser = OptionParser(usage) > > def help_choice(help, list, default) : > help = help + " " > help = help + ",".join(list) > if (default == True) : > help = help + " default: %default" > return help > > parser.add_option('-c', '--connect', action='store', > type='string', dest='connect_uri', help='libvirtd connect URI') > > parser.add_option('-d', '--domain', action='store', > type='string',dest="domain", > help='domain name.') > > parser.add_option('-l', '--list', action='store_true', dest='show_list', > help='see device list') > > parser.add_option('--delete', action='store', dest='delete', type='string' > , help='remove device') > > # > # 'block' or 'file' can be detected by --source option. > # > typeChoices=('block','file','network','dir') > parser.add_option('--type', choices=typeChoices, dest='type', type='choice', > help=help_choice('device type:', typeChoices, False)) > > mediaChoices=('disk','cdrom') > parser.add_option('--media', choices=mediaChoices, > type='choice',dest="media", > help=help_choice('media type:', mediaChoices, True)) > > parser.add_option('--source', action='store', type='string', dest='source', > help='select source file/device to be shown as disk') > > protocolChoices=('nbd','rbd', 'sheepdog') > parser.add_option('--protocol', choices=protocolChoices, > type='choice', dest='protocol', > help=help_choice('netdisk protocol:', protocolChoices, False)) > > parser.add_option('--host', action='store', type='string', dest='host', > help='<host:port> for rbd and sheepdog, network devices') > > parser.add_option('--devname', action='store', type='string', dest='devname', > help='device name to be shown to guest(auto at default)') > > qemu_group = OptionGroup(parser, "Qemu Options") > qemuFormatChoices=('raw','bochs','qcow2','qed') > qemu_group.add_option('--qemu_disk_format', choices=qemuFormatChoices, > type='choice', dest='qemu_format', > help=help_choice('disk format(qemu):',qemuFormatChoices, True)) > > ioChoices=('threads','native') > qemu_group.add_option('--io',choices=ioChoices, type='choice', dest='io', > help=help_choice('io option(qemu):', ioChoices, False)) > > cacheChoices=('none','writeback','writethrough','default') > qemu_group.add_option('--cache', choices=cacheChoices, type='choice', > dest='cache', help=help_choice('cache policy:(qemu)', cacheChoices, True)) > > errorChoices=('stop','ignore','enospace') > parser.add_option('--error_policy', choices=errorChoices, type='choice', > dest='error_policy', > help=help_choice('error policy:', errorChoices, False)) > > xen_group = OptionGroup(parser, "Xen Options") > xenDriverChoices=('tap','tap2','phy','file') > xen_group.add_option('--driver', choices=xenDriverChoices, > type='choice', dest='driver_name', > help=help_choice('Xen driver type:', xenDriverChoices, False)) > > xen_group.add_option('--aio', action='store_true', > dest='xen_aio', help='using Xen aio driver') > > parser.add_option('--virtio', action='store_true', > dest='virtio', help='create a virtio device') > > parser.add_option('--readonly', action='store_true', > dest='readonly', help='attach device as read only') > > parser.add_option('--scsi', action='store_true', > dest='scsi', help='create a scsi device') > > parser.add_option('--ide', action='store_true', > dest='ide', help='create a ide device') > > parser.add_option('--pci', action='store', dest='pci', type='string', > help='customize pci resource by hand as bus:slot:function') > > parser.add_option('--drive_id', action='store', dest='drive_id', type='string', > help='customize ide/scsi resource ID as controller:bus:unit') > > parser.add_option('--yes', action='store_true', dest='yes', > help='don\'t ask before save') > > parser.add_option('--nosave', action='store_true', dest='nosave', > help='show created device XML instead of saving.') > > parser.add_option('--boot_order', action='store', dest='boot_order', > type='int', help='boot order of the device', metavar='Num') > > parser.add_option('--shareable', action='store_true', dest='shareable', > help='the device can be shareable between device') > > parser.add_option('--serial', action='store', dest='serial', > type='string', help='optional serial ID of the device') > > EncChoices = ['qcow'] > qemu_group.add_option('--encryption_format', choices=EncChoices, > type='choice', dest='encryption_format', > metavar='qcow', help='Only \"qcow\" is supported') > > EncTypeChoices =['passphrase'] > qemu_group.add_option('--encryption_type', choices=EncTypeChoices, > type='choice', dest='encryption_type', > help=help_choice('encription_type', EncTypeChoices, True)) > > qemu_group.add_option('--encryption_uuid', action='store', > metavar='UUID', dest='encryption_uuid', > help='UUID for encrypted deivce') > > > parser.add_option_group(qemu_group) > parser.add_option_group(xen_group) > parser.set_defaults(list=False, media='disk') > parser.set_defaults(qemu_format='raw', cache='default', media='disk') > parser.set_defaults(virtio=False, readonly=False, scsi=False, ide=False) > parser.set_defaults(xen_aio=False,) > parser.set_defaults(yes=False) > > > (options, args) = parser.parse_args(sys.argv) > > # > # Confirm domain XML is not updated since we opened it. > # > def check_domain_unchanged(origin, domain): > if origin != domain.XMLDesc(0) : > print 'Domain file may be updated while we open' > print 'please retry' > exit(1) > # > # Connect libvirt and get domain information. > # > if options.domain == None : > print 'please specify domain to be modified' > exit(1) > > try : > conn = libvirt.open(options.connect_uri) > except: > print 'Can\'t connect libvirt with URI %s'%(options.connect_uri) > exit(1) > > conn_uri = conn.getURI() > info = re.split(':/', conn_uri) > > # From the name of connection URI, we detect vmname. > vmname = info[0] > > # domain look up. > domain = conn.lookupByName(options.domain) > if domain == None: > print 'Can\'t find domain %s' %(options.domain) > exit(1) > > > # read XML description. > origin = domain.XMLDesc(0) > dom = xml.dom.minidom.parseString(domain.XMLDesc(0)) > > # At 1st, we need to find <device> block. > names = dom.getElementsByTagName('devices') > if (names == None) : > print '<device> element not found in %s\n' % filename > exit(1) > > for devices in names : > if devices.hasChildNodes() : > for name in devices.childNodes : > if (is_block_device(name)) : > disk = BlockDevice() > disk.parse_info(name) > disks.append(disk) > if name.hasChildNodes() : > for elem in name.childNodes : > if elem.nodeName == 'address' : > addr = parse_address(elem) > > # > # Show List. > # > if options.show_list == True : > for disk in disks : > disk.show() > print '' > exit(0) > > # delete is easy. > if options.delete != None : > disk = None > for name in devices.childNodes : > if (not is_block_device(name)) : > continue > disk = BlockDevice() > disk.parse_info(name) > if disk.target_dev == options.delete : > devices.removeChild(name) > break > disk = None > if disk == None : > print 'no such device %s'%(options.delete) > exit(1) > if not options.yes : > print 'You\'ll delete this device!' > disk.show() > x = raw_input('Really delete Y/N ? ') > if x != 'Y' and x != 'y' : > exit(0) > str = dom.toxml() > check_domain_unchanged(origin, domain) > conn.defineXML(str) > exit(1) > > # > # Build a newdisk information from command line options > # and default values. > # > newdisk = BlockDevice() > if options.type != None : > newdisk.type = options.type > > newdisk.media = options.media > > # > # qemu only has a drive name as 'qemu'. 'type' and 'cache' are selectable. > # > if vmname == 'qemu' : > newdisk.driver_name = 'qemu' > newdisk.driver_type = options.qemu_format > if options.cache == None : > newdisk.driver_cache = 'default' > else : > newdisk.driver_cache = options.cache > else : # Xen can select drive name. > newdisk.driver_name = options.driver_name > if options.xen_aio == True : > newdisk.driver_type = 'aio' > > if options.error_policy != None : > newdisk.driver_error_policy = options.error_policy > > if options.io != None : > newdisk.io = options.io > > # Make readonly if crdom is specified. > if options.media == 'cdrom' or options.readonly == True: > newdisk.readonly = True; > > # Check Device Name and detect device bus from device name. > if options.devname != None : > if re.match('vd[a-z]', options.devname) : > newdisk.target_dev = options.devname > newdisk.target_bus = 'virtio' > elif re.match('hd[a-d]', options.devname) : > newdisk.target_dev = options.devname > newdisk.target_bus = 'ide' > elif re.match('sd[a-z]', options.devname) : > newdisk.target_dev = options.devname > newdisk.target_bus = 'scsi' > else : > newdisk.target_dev = options.devname > # > # Define device name automatically with regard to the bus. > # > if options.virtio == True : > newdisk.target_bus = 'virtio' > if options.devname == None: > newdisk.target_dev = gen_device_name(disks, 'vd') > if newdisk.target_dev == None: > print 'failed to define virtio drive name as vd*' > print 'please define by hand with --devname' > exit(1) > elif options.ide == True : > newdisk.target_bus = 'ide' > if options.devname == None: > newdisk.target_dev = gen_device_name(disks, 'hd') > if newdisk.target_dev == None : > print 'failed to define ide drive name as hd*' > print 'please define by hand with --devname' > exit(1) > > elif options.scsi == True : > newdisk.target_bus = 'scsi' > if options.devname == None: > newdisk.target_dev = gen_device_name(disks, 'sd') > if newdisk.target_dev == None : > print 'failed to define scsi drive name as sd*' > print 'please define by hand with --devname' > exit(1) > # > # If we can't detelct target bus, retrun error. > # > if newdisk.target_bus == None : > print 'need to specify device name or target bus for drive' > exit(1) > > # > # If there is a device with the same name, error. > # > if check_device_conflict(disks, newdisk.target_dev) : > print 'device name conflicts %s' %(newdisk.target_dev) > print 'please specify an other name with --devname' > > # > # Handle 'source' type. > # > if options.source != None and options.protocol == None: > # No network case. check local FS. > # Only absolute path is allowed. > if options.source[0] != '/' : > print 'please use absolute path for source %s:' %(options.source) > exit(1) > try: > mode = os.stat(options.source)[stat.ST_MODE] > except: > print 'can\'t handle file %s' %(options.source) > exit(1) > # > # check 'file' and 'block' > # > newdisk.source = options.source > if stat.S_ISREG(mode) != 0: > if newdisk.type == None : > newdisk.type = 'file' > if newdisk.type != 'file' : > print '%s specified in --source is file' %(options.source) > exit(1) > if stat.S_ISBLK(mode) != 0 : > if newdisk.type == None : > newdisk.type = 'block' > if newdisk.type != 'block' : > print '%s specified in --source is blkdev' %(options.source) > exit(1) > if newdisk.type == None : > print 'can\'t detect source type %s'%(options.source) > > elif options.type == 'network' : > if options.protocol == None : > print 'need to select protocol for network drive.' > exit(1) > newdisk.protocol = options.protocol > if options.source == None : > print 'source name for network should be privded --soruce' > exit(1) > newdisk.source = options.source > if not re.match('[0-9a-zA-z\._-]+:[0-9]+', options.host) : > print 'host should be specified in address:port manner' > exit(1) > (addr, port) = re.split(':', options.host) > newdisk.protocol_addr = addr > newdisk.protocol_port = port > > if options.media != 'cdrom' and options.source == None : > print 'you need to specify source if not cdrom' > exit(1) > > # > # Define PCI/IDE/SCSI drive address. > # (Usually, all this will be defined automatically.) > # > > # format check > if options.pci != None : > if options.drive_id != None : > print 'pci address and drive-id cannot be set at the same time' > exit(1) > if not re.match("0x[0-9a-f]+:0x[0-9a-f]+:0x[0-9-a-f]", options.pci) : > print 'bad pci address ',options.pci > print '0xXX:0xXX:0xXX is expected',options.pci > exit(1) > > if options.drive_id != None : > if not re.match("[0-9]+:[0-9]+:[0-9]+", options.drive_id) : > print 'bad drive_id address', options.drive_id > exit(1) > > # define BUS ID. > # > # In this case, device name should meet bus ID(especially IDE), > # which the user specified. The user should specify device > # name by himself. > # > if options.pci != None or options.drive_id != None : > if options.devname == None : > print 'We recommend that --drive_id should be used with --devname', > print 'device name <-> drive ID relationship is at random, now' > > if options.pci != None : > pci = re.split(':', options.pci) > if '0x00' != pci[0] : > print 'only bus 0x00 can be used in pci' > exit(1) > if check_pci_conflict(pci[0], pci[1], pci[2]) : > print 'bus %s conflicts' % (options.pci) > newdisk.address_type = 'pci' > newdisk.address_bus = pci[0] > newdisk.address_slot = pci[1] > newdisk.address_function = pci[2] > > elif options.drive_id != None : > drive = re.split(':', options.drive_id) > > if options.ide == True : > if check_drive_conflict('ide', drive[0],drive[1],drive[2]) : > print 'drive %s conflicts' % (options.drive_id) > else : > if check_drive_conflict('scsi',drive[0], drive[1], drive[2]) : > print 'drive %s conflicts' % (options.drive_id) > > newdisk.address_type = 'drive' > newdisk.address_controller = drive[0] > newdisk.address_bus = drive[1] > newdisk.address_unit = drive[2] > > if options.boot_order != None : > newdisk.boot_order = str(options.boot_order) > > if options.shareable == True: > newdisk.shareab;e = True > > if options.serial != None : > newdisk.serial = options.serial > # > # Handle encryption > # > > if options.encryption_format != None : > if options.encryption_type == None or\ > options.encryption_uuid == None : > print 'encryption passphrase or UUID is not specified' > exit(1) > newdisk.encrypt_format = options.encryption_format > newdisk.encrypt_type = options.encryption_type > newdisk.encrypt_uuid = options.encryption_uuid > > # > # Okay, we got all required information. Show the newdisk. > # > if options.yes != True : > newdisk.show() > # > # Build XML from 'newdisk' > # > def append_attribute(doc, elem, attr, value) : > x = doc.createAttribute(attr) > elem.setAttributeNode(x) > elem.setAttribute(attr, value) > > def append_text(doc, elem, text) : > x = doc.createTextNode(text) > elem.appendChild(x) > > def append_element(doc, parent, name, level) : > append_text(doc, parent, '\n') > while level > 0 : > append_text(doc, parent, ' ') > level = level - 1 > element = doc.createElement(name) > parent.appendChild(element) > return element > > # <disk .... > element = dom.createElement('disk') > append_attribute(dom, element, 'device', newdisk.media) > append_attribute(dom, element, 'type', newdisk.type) > > # > # <driver ... > # > child = append_element(dom, element, 'driver', 3) > append_attribute(dom, child, 'name', newdisk.driver_name) > append_attribute(dom, child, 'type', newdisk.driver_type) > if newdisk.driver_cache != None : > append_attribute(dom, child, 'cache', newdisk.driver_cache) > if newdisk.driver_error_policy != None : > append_attribute(dom, child, 'error_policy', newdisk.driver_error_policy) > if newdisk.driver_io != None : > append_attribute(dom, child, 'io', newdisk.driver_io) > > # > # <source.... > # > if newdisk.type == 'file' and newdisk.source != None: > child = append_element(dom, element, 'source', 3) > append_attribute(dom, child, 'file', options.source) > elif newdisk.type == 'block' and newdisk.source != None: > child = append_element(dom, element, 'source', 3) > append_attribute(dom, child, 'dev', options.source) > elif newdisk.type == 'network' and newdisk.protocol != None: > child = append_element(dom, element, 'source', 3) > append_attribute(dom, child, 'protocol', options.protocol) > append_attribute(dom, child, 'name', options.source) > host = append_element(dom, child, 'host', 4) > address = re.split(':',options.host) > append_attribute(dom, host, 'name', address[0]) > append_attribute(dom, host, 'port', address[1]) > # > # <target.... > # > child = append_element(dom, element, 'target', 3) > append_attribute(dom, child, 'dev', newdisk.target_dev) > append_attribute(dom, child, 'bus', newdisk.target_bus) > > > # > # <address..... > # libvirt will do auto-fill in typical case. > # > if newdisk.address_type != None : > child = append_element(dom, element, 'address', 3) > append_attribute(dom, child, 'type', newdisk.address_type) > > if newdisk.address_type == 'pci' : > append_attribute(dom, child, 'bus', newdisk.address_bus) > append_attribute(dom, child, 'slot', newdisk.address_slot) > append_attribute(dom, child, 'function', newdisk.address_function) > append_attribute(dom, child, 'domain', '0x0000') > > elif newdisk.address_type == 'drive' : > append_attribute(dom, child, 'controller', newdisk.address_controller) > append_attribute(dom, child, 'unit', newdisk.address_unit) > append_attribute(dom, child, 'bus', newdisk.address_bus) > append_attribute(dom, child, 'domain', '0x0000') > # > # <readonly > # > if newdisk.readonly == True: > append_element(dom, element, 'readonly', 3) > > # > # <shareable > # > if newdisk.shareable == True: > append_element(dom, element, 'readonly', 3) > # > # <boot > # > if newdisk.boot_order != None: > child = append_element(dom, element, 'boot', 3) > append_attribute(dom, child, 'order', newdisk.boot_order) > > # > # <serial > # > if newdisk.serial != None: > child = append_element(dom, element, 'serial', 3) > append_text(dom, child, newdisk.serial) > > # > # <encryption > # > > if newdisk.encrypt_format != None : > child = append_element(dom, element, 'encryption', 3) > append_attribute(dom, child, 'format', newdisk.encrypt_format) > secret = append_element(dom, child, 'secret', 4) > append_attribute(dom, secret, 'type', newdisk.encrypt_type) > append_attribute(dom, secret, 'uuid', newdisk.encrypt_uuid) > append_text(dom, child, '\n') > > # indent for </disk> > append_text(dom, element, '\n') > append_text(dom, element, ' ') > > if options.nosave == True : > print '' > print element.toxml('utf-8') > exit(0) > > # > # Insert newdisk to the tail of disks. > # > for devices in names : > if not devices.hasChildNodes() : > continue > for name in devices.childNodes : > if name.nodeName == 'controller' : > break > if name == None : > append_text(dom, devices, ' ') > x = dom.createTextNode('\n') > devices.appendChild(element) > devices.insertBefore(x, name) > else: > devices.insertBefore(element, name) > x = dom.createTextNode('\n ') > devices.insertBefore(x, name) > > if not options.yes : > x = raw_input('Add this device Y/N ? ') > if x != 'y' and x != 'Y' : > exit(1) > > str = dom.toxml('utf-8') > > check_domain_unchanged(origin, domain) > > try: > conn.defineXML(str) > except: > print 'Failed' > > _______________________________________________ > virt-tools-list mailing list > virt-tools-list@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/virt-tools-list -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list