[libvirt] [PATCH] libxenlight driver
by Jim Fehlig
Here's the latest version of a libxenlight driver for libvirt.
I've added a per-domain libxl_ctx in addition to the driver wide
context. The former is stored in virDomainObject privateData and used
for operations on the domain. The latter is stored in driver private
data and is used for non-domain related libxl calls, e.g. getVersion,
getNodeInfo, etc. This approach was suggested by Ian Jackson and
Stefano Stabellini and appears to be working much better than a single,
driver wide libxl_ctx. I no longer have the restart issues described in
the first patch posting [1].
Your review and comments are much appreciated!
Thanks,
Jim
[1] https://www.redhat.com/archives/libvir-list/2011-February/msg00409.html
13 years, 8 months
[libvirt] [RFC] virt-disk : a command line tool for modify domain XML's disk of inactive domains.
by KAMEZAWA Hiroyuki
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 ?
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(a)jp.fujitsu.com>
#
# 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'
13 years, 8 months
[libvirt] [PATCH] Fix off-by-1 in virFileAbsPath.
by Daniel P. Berrange
The virFileAbsPath was not taking into account the '/' directory
separator when allocating memory for combining cwd + path. Convert
to use virAsprintf to avoid this type of bug completely.
* src/util/util.c: Convert virFileAbsPath to use virAsprintf
---
src/util/util.c | 19 ++++++-------------
1 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c
index 965e96d..452f592 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1990,30 +1990,23 @@ cleanup:
int virFileAbsPath(const char *path, char **abspath)
{
char *buf;
- int cwdlen;
if (path[0] == '/') {
- buf = strdup(path);
- if (buf == NULL)
- return(-1);
+ if (!(*abspath = strdup(path)))
+ return -1;
} else {
buf = getcwd(NULL, 0);
if (buf == NULL)
- return(-1);
+ return -1;
- cwdlen = strlen(buf);
- /* cwdlen includes the null terminator */
- if (VIR_REALLOC_N(buf, cwdlen + strlen(path) + 1) < 0) {
+ if (virAsprintf(abspath, "%s/%s", buf, path) < 0) {
VIR_FREE(buf);
errno = ENOMEM;
- return(-1);
+ return -1;
}
-
- buf[cwdlen] = '/';
- strcpy(&buf[cwdlen + 1], path);
+ VIR_FREE(buf);
}
- *abspath = buf;
return 0;
}
--
1.7.4
13 years, 8 months
[libvirt] [PATCH] Fix off-by-1 in virFileAbsPath.
by Daniel P. Berrange
The virFileAbsPath was not taking into account the '/' directory
separator when allocating memory for combining cwd + path. Convert
to use virAsprintf to avoid this type of bug completely.
* src/util/util.c: Convert virFileAbsPath to use virAsprintf
---
src/util/util.c | 19 ++++++-------------
1 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c
index 965e96d..452f592 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1990,30 +1990,23 @@ cleanup:
int virFileAbsPath(const char *path, char **abspath)
{
char *buf;
- int cwdlen;
if (path[0] == '/') {
- buf = strdup(path);
- if (buf == NULL)
- return(-1);
+ if (!(*abspath = strdup(path)))
+ return -1;
} else {
buf = getcwd(NULL, 0);
if (buf == NULL)
- return(-1);
+ return -1;
- cwdlen = strlen(buf);
- /* cwdlen includes the null terminator */
- if (VIR_REALLOC_N(buf, cwdlen + strlen(path) + 1) < 0) {
+ if (virAsprintf(abspath, "%s/%s", buf, path) < 0) {
VIR_FREE(buf);
errno = ENOMEM;
- return(-1);
+ return -1;
}
-
- buf[cwdlen] = '/';
- strcpy(&buf[cwdlen + 1], path);
+ VIR_FREE(buf);
}
- *abspath = buf;
return 0;
}
--
1.7.4
13 years, 8 months
[libvirt] [PATCH] Fix discard of expected errors
by Daniel P. Berrange
In a couple of commands virsh catches & ignores errors, but fails
to reset last_error. Thus the error is ignored, but still reported
to the user.
* tools/virsh.c: Reset last_error if ignoring an error
---
tools/virsh.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 2837e0f..62fca17 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2122,6 +2122,9 @@ cmdDominfo(vshControl *ctl, const vshCmd *cmd)
if (last_error->code != VIR_ERR_NO_SUPPORT) {
virDomainFree(dom);
return FALSE;
+ } else {
+ virFreeError(last_error);
+ last_error = NULL;
}
} else {
/* Only print something if a security model is active */
@@ -2498,6 +2501,8 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
if (!tmp || virStrToLong_i(tmp + 1, &tmp, 10, &count) < 0)
count = -1;
}
+ virFreeError(last_error);
+ last_error = NULL;
VIR_FREE(xml);
}
--
1.7.4
13 years, 8 months
[libvirt] [PATCH] Make LXC container startup/shutdown/I/O more robust
by Daniel P. Berrange
The current LXC I/O controller looks for HUP to detect
when a guest has quit. This isn't reliable as during
initial bootup it is possible that 'init' will close
the console and let mingetty re-open it. The shutdown
of containers was also flakey because it only killed
the libvirt I/O controller and expected container
processes to gracefully follow.
Change the I/O controller such that when it see HUP
or an I/O error, it uses kill($PID, 0) to see if the
process has really quit.
Change the container shutdown sequence to use the
virCgroupKillPainfully function to ensure every
really goes away
* docs/drvlxc.html.in: Document that certain cgroups
controllers are now mandatory
* src/lxc/lxc_controller.c: Check if PID is still
alive before quitting on I/O error/HUP
* src/lxc/lxc_driver.c: Use virCgroupKillPainfully
---
docs/drvlxc.html.in | 18 ++++++
src/lxc/lxc_controller.c | 42 ++++++++++----
src/lxc/lxc_driver.c | 142 ++++++++++++++++------------------------------
3 files changed, 98 insertions(+), 104 deletions(-)
diff --git a/docs/drvlxc.html.in b/docs/drvlxc.html.in
index 35058c4..3e715b1 100644
--- a/docs/drvlxc.html.in
+++ b/docs/drvlxc.html.in
@@ -9,6 +9,24 @@ light-weight "application container" which does not have it's own root image. Y
start it using
</p>
+<h2>Cgroups Requirements</h2>
+
+<p>
+The libvirt LXC driver requires that certain cgroups controllers are
+mounted on the host OS. The minimum required controllers are 'cpuacct',
+'memory' and 'devices', while recommended extra controllers are
+'cpu', 'freezer' and 'blkio'. The /etc/cgconfig.conf & cgconfig
+init service used to mount cgroups at host boot time. To manually
+mount them use. NB, the blkio controller in some kernels will not
+allow creation of nested sub-directories which will prevent correct
+operation of the libvirt LXC driver. On such kernels the blkio controller
+must not be mounted.
+</p>
+
+<pre>
+ # mount -t cgroup cgroup /dev/cgroup -o cpuacct,memory,devices,cpu,freezer,blkio
+</pre>
+
<h3>Example config version 1</h3>
<p></p>
<pre>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index b742a33..0cd7dc4 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -31,6 +31,7 @@
#include <sys/un.h>
#include <unistd.h>
#include <paths.h>
+#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <getopt.h>
@@ -119,12 +120,10 @@ static int lxcSetContainerResources(virDomainDefPtr def)
virReportSystemError(-rc,
_("Unable to set memory limit for domain %s"),
def->name);
- /* Don't fail if we can't set memory due to lack of kernel support */
- if (rc != -ENOENT)
- goto cleanup;
+ goto cleanup;
}
- if(def->mem.hard_limit) {
+ if (def->mem.hard_limit) {
rc = virCgroupSetMemoryHardLimit(cgroup, def->mem.hard_limit);
if (rc != 0) {
virReportSystemError(-rc,
@@ -134,7 +133,7 @@ static int lxcSetContainerResources(virDomainDefPtr def)
}
}
- if(def->mem.soft_limit) {
+ if (def->mem.soft_limit) {
rc = virCgroupSetMemorySoftLimit(cgroup, def->mem.soft_limit);
if (rc != 0) {
virReportSystemError(-rc,
@@ -144,7 +143,7 @@ static int lxcSetContainerResources(virDomainDefPtr def)
}
}
- if(def->mem.swap_hard_limit) {
+ if (def->mem.swap_hard_limit) {
rc = virCgroupSetSwapHardLimit(cgroup, def->mem.swap_hard_limit);
if (rc != 0) {
virReportSystemError(-rc,
@@ -323,6 +322,18 @@ ignorable_epoll_accept_errno(int errnum)
|| errnum == EWOULDBLOCK);
}
+static bool
+lxcPidGone(pid_t container)
+{
+ waitpid(container, NULL, WNOHANG);
+
+ if (kill(container, 0) < 0 &&
+ errno == ESRCH)
+ return true;
+
+ return false;
+}
+
/**
* lxcControllerMain
* @monitor: server socket fd to accept client requests
@@ -340,7 +351,8 @@ ignorable_epoll_accept_errno(int errnum)
static int lxcControllerMain(int monitor,
int client,
int appPty,
- int contPty)
+ int contPty,
+ pid_t container)
{
int rc = -1;
int epollFd;
@@ -446,7 +458,13 @@ static int lxcControllerMain(int monitor,
++numActive;
}
} else if (epollEvent.events & EPOLLHUP) {
- VIR_DEBUG("EPOLLHUP from fd %d", epollEvent.data.fd);
+ if (lxcPidGone(container))
+ goto cleanup;
+ curFdOff = epollEvent.data.fd == appPty ? 0 : 1;
+ if (fdArray[curFdOff].active) {
+ fdArray[curFdOff].active = 0;
+ --numActive;
+ }
continue;
} else {
lxcError(VIR_ERR_INTERNAL_ERROR,
@@ -485,7 +503,9 @@ static int lxcControllerMain(int monitor,
--numActive;
fdArray[curFdOff].active = 0;
} else if (-1 == rc) {
- goto cleanup;
+ if (lxcPidGone(container))
+ goto cleanup;
+ continue;
}
}
@@ -564,7 +584,7 @@ lxcControllerRun(virDomainDefPtr def,
int rc = -1;
int control[2] = { -1, -1};
int containerPty = -1;
- char *containerPtyPath;
+ char *containerPtyPath = NULL;
pid_t container = -1;
virDomainFSDefPtr root;
char *devpts = NULL;
@@ -683,7 +703,7 @@ lxcControllerRun(virDomainDefPtr def,
if (lxcControllerClearCapabilities() < 0)
goto cleanup;
- rc = lxcControllerMain(monitor, client, appPty, containerPty);
+ rc = lxcControllerMain(monitor, client, appPty, containerPty, container);
cleanup:
VIR_FREE(devptmx);
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 625777a..e47c201 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -953,36 +953,16 @@ cleanup:
* @driver: pointer to driver structure
* @vm: pointer to VM to clean up
*
- * waitpid() on the container process. kill and wait the tty process
- * This is called by both lxcDomainDestroy and lxcSigHandler when a
- * container exits.
- *
- * Returns 0 on success or -1 in case of error
+ * Cleanout resources associated with the now dead VM
+ *
*/
-static int lxcVmCleanup(lxc_driver_t *driver,
+static void lxcVmCleanup(lxc_driver_t *driver,
virDomainObjPtr vm)
{
- int rc = 0;
- int waitRc;
- int childStatus = -1;
virCgroupPtr cgroup;
int i;
lxcDomainObjPrivatePtr priv = vm->privateData;
- while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) &&
- errno == EINTR)
- ; /* empty */
-
- if ((waitRc != vm->pid) && (errno != ECHILD)) {
- virReportSystemError(errno,
- _("waitpid failed to wait for container %d: %d"),
- vm->pid, waitRc);
- rc = -1;
- } else if (WIFEXITED(childStatus)) {
- VIR_DEBUG("container exited with rc: %d", WEXITSTATUS(childStatus));
- rc = -1;
- }
-
/* now that we know it's stopped call the hook if present */
if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
char *xml = virDomainDefFormat(vm->def, 0);
@@ -1022,8 +1002,6 @@ static int lxcVmCleanup(lxc_driver_t *driver,
vm->def->id = -1;
vm->newDef = NULL;
}
-
- return rc;
}
/**
@@ -1182,11 +1160,10 @@ error:
static int lxcVmTerminate(lxc_driver_t *driver,
- virDomainObjPtr vm,
- int signum)
+ virDomainObjPtr vm)
{
- if (signum == 0)
- signum = SIGINT;
+ virCgroupPtr group = NULL;
+ int rc;
if (vm->pid <= 0) {
lxcError(VIR_ERR_INTERNAL_ERROR,
@@ -1194,18 +1171,30 @@ static int lxcVmTerminate(lxc_driver_t *driver,
return -1;
}
- if (kill(vm->pid, signum) < 0) {
- if (errno != ESRCH) {
- virReportSystemError(errno,
- _("Failed to kill pid %d"),
- vm->pid);
- return -1;
- }
- }
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
+ return -1;
+ rc = virCgroupKillPainfully(group);
+ if (rc < 0) {
+ virReportSystemError(-rc, "%s",
+ _("Failed to kill container PIDs"));
+ rc = -1;
+ goto cleanup;
+ }
+ if (rc == 1) {
+ lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Some container PIDs refused to die"));
+ rc = -1;
+ goto cleanup;
+ }
+ lxcVmCleanup(driver, vm);
vm->state = VIR_DOMAIN_SHUTDOWN;
- return lxcVmCleanup(driver, vm);
+ rc = 0;
+
+cleanup:
+ virCgroupFree(&group);
+ return rc;
}
static void lxcMonitorEvent(int watch,
@@ -1229,7 +1218,7 @@ static void lxcMonitorEvent(int watch,
goto cleanup;
}
- if (lxcVmTerminate(driver, vm, SIGINT) < 0) {
+ if (lxcVmTerminate(driver, vm) < 0) {
virEventRemoveHandle(watch);
} else {
event = virDomainEventNewFromObj(vm,
@@ -1544,7 +1533,7 @@ static int lxcVmStart(virConnectPtr conn,
VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
lxcMonitorEvent,
vm, NULL)) < 0) {
- lxcVmTerminate(driver, vm, 0);
+ lxcVmTerminate(driver, vm);
goto cleanup;
}
@@ -1712,55 +1701,6 @@ cleanup:
return dom;
}
-/**
- * lxcDomainShutdown:
- * @dom: pointer to domain to shutdown
- *
- * Sends SIGINT to container root process to request it to shutdown
- *
- * Returns 0 on success or -1 in case of error
- */
-static int lxcDomainShutdown(virDomainPtr dom)
-{
- lxc_driver_t *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- virDomainEventPtr event = NULL;
- int ret = -1;
-
- lxcDriverLock(driver);
- vm = virDomainFindByUUID(&driver->domains, dom->uuid);
- if (!vm) {
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- virUUIDFormat(dom->uuid, uuidstr);
- lxcError(VIR_ERR_NO_DOMAIN,
- _("No domain with matching uuid '%s'"), uuidstr);
- goto cleanup;
- }
-
- if (!virDomainObjIsActive(vm)) {
- lxcError(VIR_ERR_OPERATION_INVALID,
- "%s", _("Domain is not running"));
- goto cleanup;
- }
-
- ret = lxcVmTerminate(driver, vm, 0);
- event = virDomainEventNewFromObj(vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
- if (!vm->persistent) {
- virDomainRemoveInactive(&driver->domains, vm);
- vm = NULL;
- }
-
-cleanup:
- if (vm)
- virDomainObjUnlock(vm);
- if (event)
- lxcDomainEventQueue(driver, event);
- lxcDriverUnlock(driver);
- return ret;
-}
-
static int
lxcDomainEventRegister(virConnectPtr conn,
@@ -1928,7 +1868,7 @@ static int lxcDomainDestroy(virDomainPtr dom)
goto cleanup;
}
- ret = lxcVmTerminate(driver, vm, SIGKILL);
+ ret = lxcVmTerminate(driver, vm);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
@@ -2057,7 +1997,7 @@ lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
lxcMonitorEvent,
vm, NULL)) < 0) {
- lxcVmTerminate(driver, vm, 0);
+ lxcVmTerminate(driver, vm);
goto cleanup;
}
} else {
@@ -2124,8 +2064,24 @@ static int lxcStartup(int privileged)
rc = virCgroupForDriver("lxc", &lxc_driver->cgroup, privileged, 1);
if (rc < 0) {
char buf[1024];
- VIR_WARN("Unable to create cgroup for driver: %s",
+ VIR_WARN("Unable to create cgroup, disabling LXC driver: %s",
virStrerror(-rc, buf, sizeof(buf)));
+ goto cleanup;
+ }
+ if (!virCgroupMounted(lxc_driver->cgroup,
+ VIR_CGROUP_CONTROLLER_CPUACCT)) {
+ VIR_WARN0("Unable to find 'cpuacct' cgroups controller mount");
+ goto cleanup;
+ }
+ if (!virCgroupMounted(lxc_driver->cgroup,
+ VIR_CGROUP_CONTROLLER_DEVICES)) {
+ VIR_WARN0("Unable to find 'devices' cgroups controller mount");
+ goto cleanup;
+ }
+ if (!virCgroupMounted(lxc_driver->cgroup,
+ VIR_CGROUP_CONTROLLER_MEMORY)) {
+ VIR_WARN0("Unable to find 'memory' cgroups controller mount");
+ goto cleanup;
}
/* Call function to load lxc driver configuration information */
@@ -2845,7 +2801,7 @@ static virDriver lxcDriver = {
lxcDomainLookupByName, /* domainLookupByName */
lxcDomainSuspend, /* domainSuspend */
lxcDomainResume, /* domainResume */
- lxcDomainShutdown, /* domainShutdown */
+ NULL, /* domainShutdown */
NULL, /* domainReboot */
lxcDomainDestroy, /* domainDestroy */
lxcGetOSType, /* domainGetOSType */
--
1.7.4
13 years, 8 months
[libvirt] [PATCH] security: avoid memory leak
by Eric Blake
Leak introduced in commit d6623003.
* src/qemu/qemu_driver.c (qemuSecurityInit): Avoid leak on failure.
* src/security/security_stack.c (virSecurityStackClose): Avoid
leaking component drivers.
---
src/qemu/qemu_driver.c | 5 ++++-
src/security/security_stack.c | 7 ++++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0f25a2a..8b15a3e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -204,8 +204,11 @@ qemuSecurityInit(struct qemud_driver *driver)
goto error;
if (!(driver->securityManager = virSecurityManagerNewStack(mgr,
- dac)))
+ dac))) {
+
+ virSecurityManagerFree(dac);
goto error;
+ }
} else {
driver->securityManager = mgr;
}
diff --git a/src/security/security_stack.c b/src/security/security_stack.c
index 79b3e1f..64f745a 100644
--- a/src/security/security_stack.c
+++ b/src/security/security_stack.c
@@ -61,8 +61,13 @@ virSecurityStackOpen(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
}
static int
-virSecurityStackClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
+virSecurityStackClose(virSecurityManagerPtr mgr)
{
+ virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+
+ virSecurityManagerFree(priv->primary);
+ virSecurityManagerFree(priv->secondary);
+
return 0;
}
--
1.7.4
13 years, 8 months
[libvirt] [PATCH] RFC: experimental libvirtd upstart job
by apevec@gmail.com
From: Alan Pevec <apevec(a)redhat.com>
To install it, disable libvirtd sysv initscript:
chkconfig libvirtd off
service libvirtd stop
and enable libvirtd upstart job:
cp /usr/share/doc/libvirt-*/libvirtd.upstart \
/etc/init/libvirtd.conf
initctl reload-configuration
initctl start libvirtd
Test:
initctl status libvirtd
libvirtd start/running, process 3929
killall -9 libvirtd
initctl status libvirtd
libvirtd start/running, process 4047
---
daemon/Makefile.am | 1 +
daemon/libvirtd.upstart | 47 +++++++++++++++++++++++++++++++++++++++++++++++
libvirt.spec.in | 1 +
3 files changed, 49 insertions(+), 0 deletions(-)
create mode 100644 daemon/libvirtd.upstart
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index cdf0f75..a4ebcf8 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -27,6 +27,7 @@ EXTRA_DIST = \
remote_generate_stubs.pl \
libvirtd.conf \
libvirtd.init.in \
+ libvirtd.upstart \
libvirtd.policy-0 \
libvirtd.policy-1 \
libvirtd.sasl \
diff --git a/daemon/libvirtd.upstart b/daemon/libvirtd.upstart
new file mode 100644
index 0000000..40d5fa3
--- /dev/null
+++ b/daemon/libvirtd.upstart
@@ -0,0 +1,47 @@
+# libvirtd upstart job
+#
+# XXX wait for rc to get all dependent initscripts started
+# from sysv libvirtd initscript: Required-Start: $network messagebus
+start on stopped rc RUNLEVEL=[345]
+stop on runlevel [016]
+respawn
+# default rate limit is 10x/5s
+#respawn limit 10 5
+
+# DAEMON_COREFILE_LIMIT in /etc/sysconfig/libvirtd doesn't have effect
+# must set resource limits here
+#limit core unlimited unlimited
+
+# documented http://upstart.ubuntu.com/wiki/Stanzas#pid
+# but not accepted by upstart-0.6.5
+#pid file /var/run/libvirtd.pid
+
+env PIDFILE=/var/run/libvirtd.pid
+
+script
+ LIBVIRTD_CONFIG=
+ LIBVIRTD_ARGS=
+ KRB5_KTNAME=/etc/libvirt/krb5.tab
+
+ test -f /etc/sysconfig/libvirtd && . /etc/sysconfig/libvirtd
+
+ export QEMU_AUDIO_DRV
+ export SDL_AUDIODRIVER
+
+ LIBVIRTD_CONFIG_ARGS=
+ if [ -n "$LIBVIRTD_CONFIG" ]
+ then
+ LIBVIRTD_CONFIG_ARGS="--config $LIBVIRTD_CONFIG"
+ else
+ true
+ fi
+
+ mkdir -p /var/cache/libvirt
+ rm -rf /var/cache/libvirt/*
+ KRB5_KTNAME=$KRB5_KTNAME /usr/sbin/libvirtd $LIBVIRTD_CONFIG_ARGS $LIBVIRTD_ARGS
+end script
+
+post-stop script
+ rm -f $PIDFILE
+ rm -rf /var/cache/libvirt/*
+end script
diff --git a/libvirt.spec.in b/libvirt.spec.in
index a29693a..365000c 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -854,6 +854,7 @@ fi
%{_sysconfdir}/libvirt/nwfilter/*.xml
%{_sysconfdir}/rc.d/init.d/libvirtd
+%doc daemon/libvirtd.upstart
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
%if %{with_dtrace}
--
1.7.3.4
13 years, 8 months
[libvirt] [PATCH] Expose name + UUID to LXC containers via env variables
by Daniel P. Berrange
When spawning 'init' in the container, set
LIBVIRT_LXC_UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
LIBVIRT_LXC_NAME=YYYYYYYYYYYY
to allow guest software to detect & identify that they
are in a container
* src/lxc/lxc_container.c: Set LIBVIRT_LXC_UUID and
LIBVIRT_LXC_NAME env vars
---
src/lxc/lxc_container.c | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index d973984..269dc97 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -52,6 +52,7 @@
#include "util.h"
#include "memory.h"
#include "veth.h"
+#include "uuid.h"
#include "files.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -102,6 +103,20 @@ struct __lxc_child_argv {
*/
static int lxcContainerExecInit(virDomainDefPtr vmDef)
{
+ char *uuidenv, *nameenv;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ virUUIDFormat(vmDef->uuid, uuidstr);
+
+ if (virAsprintf(&uuidenv, "LIBVIRT_LXC_UUID=%s", uuidstr) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ if (virAsprintf(&nameenv, "LIBVIRT_LXC_NAME=%s", vmDef->name) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
const char *const argv[] = {
vmDef->os.init,
NULL,
@@ -109,6 +124,8 @@ static int lxcContainerExecInit(virDomainDefPtr vmDef)
const char *const envp[] = {
"PATH=/bin:/sbin",
"TERM=linux",
+ uuidenv,
+ nameenv,
NULL,
};
--
1.7.4
13 years, 8 months
[libvirt] [PATCH] Fix group/mode for /dev/pts inside LXC container
by Daniel P. Berrange
Normal practice for /dev/pts is to have it mode=620,gid=5
but LXC was leaving mode=000,gid=0 preventing unprivilegd
users in the guest use of PTYs
* src/lxc/lxc_controller.c: Fix /dev/pts setup
---
src/lxc/lxc_controller.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index b742a33..d047f60 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -629,7 +629,7 @@ lxcControllerRun(virDomainDefPtr def,
}
VIR_DEBUG("Mouting 'devpts' on %s", devpts);
- if (mount("devpts", devpts, "devpts", 0, "newinstance,ptmxmode=0666") < 0) {
+ if (mount("devpts", devpts, "devpts", 0, "newinstance,ptmxmode=0666,mode=0620,gid=5") < 0) {
virReportSystemError(errno,
_("Failed to mount devpts on %s"),
devpts);
--
1.7.4
13 years, 8 months