summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authorJosh Kearney <josh@jk0.org>2011-09-19 10:25:00 -0500
committerJosh Kearney <josh@jk0.org>2011-09-19 10:25:00 -0500
commit91664a2c07e4a5627558dbcaa2dd4a6719315561 (patch)
treed18ac2781af9ebfa296bb9ae14d660207d94a94b /nova/virt
parent90f01055a92153709a90115688a8fce3d3029976 (diff)
parent0561c0e01822d81fc90fed00f41b8d469c6c7808 (diff)
Merged trunk.
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/libvirt/connection.py136
-rw-r--r--nova/virt/libvirt/firewall.py4
-rw-r--r--nova/virt/xenapi/vmops.py64
3 files changed, 105 insertions, 99 deletions
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index 2ae1359bf..b3c8ebf6e 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -29,9 +29,9 @@ Supports KVM, LXC, QEMU, UML, and XEN.
(default: kvm).
:libvirt_uri: Override for the default libvirt URI (depends on libvirt_type).
:libvirt_xml_template: Libvirt XML Template.
-:rescue_image_id: Rescue ami image (default: ami-rescue).
-:rescue_kernel_id: Rescue aki image (default: aki-rescue).
-:rescue_ramdisk_id: Rescue ari image (default: ari-rescue).
+:rescue_image_id: Rescue ami image (None = original image).
+:rescue_kernel_id: Rescue aki image (None = original image).
+:rescue_ramdisk_id: Rescue ari image (None = original image).
:injected_network_template: Template file for injected network
:allow_same_net_traffic: Whether to allow in project network traffic
@@ -84,9 +84,9 @@ LOG = logging.getLogger('nova.virt.libvirt_conn')
FLAGS = flags.FLAGS
flags.DECLARE('live_migration_retry_count', 'nova.compute.manager')
# TODO(vish): These flags should probably go into a shared location
-flags.DEFINE_string('rescue_image_id', 'ami-rescue', 'Rescue ami image')
-flags.DEFINE_string('rescue_kernel_id', 'aki-rescue', 'Rescue aki image')
-flags.DEFINE_string('rescue_ramdisk_id', 'ari-rescue', 'Rescue ari image')
+flags.DEFINE_string('rescue_image_id', None, 'Rescue ami image')
+flags.DEFINE_string('rescue_kernel_id', None, 'Rescue aki image')
+flags.DEFINE_string('rescue_ramdisk_id', None, 'Rescue ari image')
flags.DEFINE_string('libvirt_xml_template',
utils.abspath('virt/libvirt.xml.template'),
'Libvirt XML Template')
@@ -125,8 +125,10 @@ flags.DEFINE_string('block_migration_flag',
'Define block migration behavior.')
flags.DEFINE_integer('live_migration_bandwidth', 0,
'Define live migration behavior')
-flags.DEFINE_string('qemu_img', 'qemu-img',
- 'binary to use for qemu-img commands')
+flags.DEFINE_string('snapshot_image_format', None,
+ 'Snapshot image format (valid options are : '
+ 'raw, qcow2, vmdk, vdi).'
+ 'Defaults to same as source image')
flags.DEFINE_string('libvirt_vif_type', 'bridge',
'Type of VIF to create.')
flags.DEFINE_string('libvirt_vif_driver',
@@ -391,10 +393,7 @@ class LibvirtConnection(driver.ComputeDriver):
def snapshot(self, context, instance, image_href):
"""Create snapshot from a running VM instance.
- This command only works with qemu 0.14+, the qemu_img flag is
- provided so that a locally compiled binary of qemu-img can be used
- to support this command.
-
+ This command only works with qemu 0.14+
"""
virt_dom = self._lookup_by_name(instance['name'])
@@ -420,8 +419,11 @@ class LibvirtConnection(driver.ComputeDriver):
arch = base['properties']['architecture']
metadata['properties']['architecture'] = arch
- if 'disk_format' in base:
- metadata['disk_format'] = base['disk_format']
+ source_format = base.get('disk_format') or 'raw'
+ image_format = FLAGS.snapshot_image_format or source_format
+ if FLAGS.use_cow_images:
+ source_format = 'qcow2'
+ metadata['disk_format'] = image_format
if 'container_format' in base:
metadata['container_format'] = base['container_format']
@@ -444,12 +446,12 @@ class LibvirtConnection(driver.ComputeDriver):
# Export the snapshot to a raw image
temp_dir = tempfile.mkdtemp()
out_path = os.path.join(temp_dir, snapshot_name)
- qemu_img_cmd = (FLAGS.qemu_img,
+ qemu_img_cmd = ('qemu-img',
'convert',
'-f',
- 'qcow2',
+ source_format,
'-O',
- 'raw',
+ image_format,
'-s',
snapshot_name,
disk_path,
@@ -468,7 +470,7 @@ class LibvirtConnection(driver.ComputeDriver):
snapshot_ptr.delete(0)
@exception.wrap_exception()
- def reboot(self, instance, network_info, reboot_type):
+ def reboot(self, instance, network_info, reboot_type=None, xml=None):
"""Reboot a virtual machine, given an instance reference.
This method actually destroys and re-creates the domain to ensure the
@@ -479,7 +481,9 @@ class LibvirtConnection(driver.ComputeDriver):
# NOTE(itoumsn): Use XML delived from the running instance
# instead of using to_xml(instance, network_info). This is almost
# the ultimate stupid workaround.
- xml = virt_dom.XMLDesc(0)
+ if not xml:
+ xml = virt_dom.XMLDesc(0)
+
# NOTE(itoumsn): self.shutdown() and wait instead of self.destroy() is
# better because we cannot ensure flushing dirty buffers
# in the guest OS. But, in case of KVM, shutdown() does not work...
@@ -543,43 +547,42 @@ class LibvirtConnection(driver.ComputeDriver):
data recovery.
"""
- self.destroy(instance, network_info, cleanup=False)
-
- xml = self.to_xml(instance, network_info, rescue=True)
- rescue_images = {'image_id': FLAGS.rescue_image_id,
- 'kernel_id': FLAGS.rescue_kernel_id,
- 'ramdisk_id': FLAGS.rescue_ramdisk_id}
- self._create_image(context, instance, xml, '.rescue', rescue_images)
- self._create_new_domain(xml)
-
- def _wait_for_rescue():
- """Called at an interval until the VM is running again."""
- instance_name = instance['name']
- try:
- state = self.get_info(instance_name)['state']
- except exception.NotFound:
- msg = _("During reboot, %s disappeared.") % instance_name
- LOG.error(msg)
- raise utils.LoopingCallDone
-
- if state == power_state.RUNNING:
- msg = _("Instance %s rescued successfully.") % instance_name
- LOG.info(msg)
- raise utils.LoopingCallDone
+ virt_dom = self._conn.lookupByName(instance['name'])
+ unrescue_xml = virt_dom.XMLDesc(0)
+ unrescue_xml_path = os.path.join(FLAGS.instances_path,
+ instance['name'],
+ 'unrescue.xml')
+ f = open(unrescue_xml_path, 'w')
+ f.write(unrescue_xml)
+ f.close()
- timer = utils.LoopingCall(_wait_for_rescue)
- return timer.start(interval=0.5, now=True)
+ xml = self.to_xml(instance, network_info, rescue=True)
+ rescue_images = {
+ 'image_id': FLAGS.rescue_image_id or instance['image_ref'],
+ 'kernel_id': FLAGS.rescue_kernel_id or instance['kernel_id'],
+ 'ramdisk_id': FLAGS.rescue_ramdisk_id or instance['ramdisk_id'],
+ }
+ self._create_image(context, instance, xml, '.rescue', rescue_images,
+ network_info=network_info)
+ self.reboot(instance, network_info, xml=xml)
@exception.wrap_exception()
- def unrescue(self, instance, network_info):
+ def unrescue(self, instance, callback, network_info):
"""Reboot the VM which is being rescued back into primary images.
Because reboot destroys and re-creates instances, unresue should
simply call reboot.
"""
- self.reboot(instance, network_info)
+ unrescue_xml_path = os.path.join(FLAGS.instances_path,
+ instance['name'],
+ 'unrescue.xml')
+ f = open(unrescue_xml_path)
+ unrescue_xml = f.read()
+ f.close()
+ os.remove(unrescue_xml_path)
+ self.reboot(instance, network_info, xml=unrescue_xml)
@exception.wrap_exception()
def poll_rescued_instances(self, timeout):
@@ -774,13 +777,13 @@ class LibvirtConnection(driver.ComputeDriver):
if size:
disk.extend(target, size)
- def _create_local(self, target, local_size, prefix='G', fs_format=None):
+ def _create_local(self, target, local_size, unit='G', fs_format=None):
"""Create a blank image of specified size"""
if not fs_format:
fs_format = FLAGS.default_local_format
- utils.execute('truncate', target, '-s', "%d%c" % (local_size, prefix))
+ utils.execute('truncate', target, '-s', "%d%c" % (local_size, unit))
if fs_format:
utils.execute('mkfs', '-t', fs_format, target)
@@ -788,9 +791,9 @@ class LibvirtConnection(driver.ComputeDriver):
self._create_local(target, local_size)
disk.mkfs(os_type, fs_label, target)
- def _create_swap(self, target, swap_gb):
+ def _create_swap(self, target, swap_mb):
"""Create a swap file of specified size"""
- self._create_local(target, swap_gb)
+ self._create_local(target, swap_mb, unit='M')
utils.execute('mkswap', target)
def _create_image(self, context, inst, libvirt_xml, suffix='',
@@ -818,8 +821,10 @@ class LibvirtConnection(driver.ComputeDriver):
utils.execute('mkdir', '-p', container_dir)
# NOTE(vish): No need add the suffix to console.log
- os.close(os.open(basepath('console.log', ''),
- os.O_CREAT | os.O_WRONLY, 0660))
+ console_log = basepath('console.log', '')
+ if os.path.exists(console_log):
+ utils.execute('chown', os.getuid(), console_log, run_as_root=True)
+ os.close(os.open(console_log, os.O_CREAT | os.O_WRONLY, 0660))
if not disk_images:
disk_images = {'image_id': inst['image_ref'],
@@ -886,22 +891,22 @@ class LibvirtConnection(driver.ComputeDriver):
cow=FLAGS.use_cow_images,
local_size=eph['size'])
- swap_gb = 0
+ swap_mb = 0
swap = driver.block_device_info_get_swap(block_device_info)
if driver.swap_is_usable(swap):
- swap_gb = swap['swap_size']
+ swap_mb = swap['swap_size']
elif (inst_type['swap'] > 0 and
not self._volume_in_mapping(self.default_swap_device,
block_device_info)):
- swap_gb = inst_type['swap']
+ swap_mb = inst_type['swap']
- if swap_gb > 0:
+ if swap_mb > 0:
self._cache_image(fn=self._create_swap,
target=basepath('disk.swap'),
- fname="swap_%s" % swap_gb,
+ fname="swap_%s" % swap_mb,
cow=FLAGS.use_cow_images,
- swap_gb=swap_gb)
+ swap_mb=swap_mb)
# For now, we assume that if we're not using a kernel, we're using a
# partitioned disk image where the target partition is the first
@@ -922,10 +927,10 @@ class LibvirtConnection(driver.ComputeDriver):
target=basepath('disk.config'),
fname=fname,
image_id=config_drive_id,
- user=user,
- project=project)
+ user_id=inst['user_id'],
+ project_id=inst['project_id'],)
elif config_drive:
- self._create_local(basepath('disk.config'), 64, prefix="M",
+ self._create_local(basepath('disk.config'), 64, unit='M',
fs_format='msdos') # 64MB
if inst['key_data']:
@@ -995,15 +1000,16 @@ class LibvirtConnection(driver.ComputeDriver):
nbd=FLAGS.use_cow_images,
tune2fs=tune2fs)
- if FLAGS.libvirt_type == 'lxc':
- disk.setup_container(basepath('disk'),
- container_dir=container_dir,
- nbd=FLAGS.use_cow_images)
except Exception as e:
# This could be a windows image, or a vmdk format disk
LOG.warn(_('instance %(inst_name)s: ignoring error injecting'
' data into image %(img_id)s (%(e)s)') % locals())
+ if FLAGS.libvirt_type == 'lxc':
+ disk.setup_container(basepath('disk'),
+ container_dir=container_dir,
+ nbd=FLAGS.use_cow_images)
+
if FLAGS.libvirt_type == 'uml':
utils.execute('chown', 'root', basepath('disk'), run_as_root=True)
diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py
index 0db10c7ce..c6253511e 100644
--- a/nova/virt/libvirt/firewall.py
+++ b/nova/virt/libvirt/firewall.py
@@ -663,7 +663,9 @@ class IptablesFirewallDriver(FirewallDriver):
if version == 6 and rule.protocol == 'icmp':
protocol = 'icmpv6'
- args = ['-j ACCEPT', '-p', protocol]
+ args = ['-j ACCEPT']
+ if protocol:
+ args += ['-p', protocol]
if protocol in ['udp', 'tcp']:
if rule.from_port == rule.to_port:
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 55a6a4a78..210b8fe65 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -49,9 +49,9 @@ XenAPI = None
LOG = logging.getLogger("nova.virt.xenapi.vmops")
FLAGS = flags.FLAGS
-flags.DEFINE_integer('windows_version_timeout', 300,
- 'number of seconds to wait for windows agent to be '
- 'fully operational')
+flags.DEFINE_integer('agent_version_timeout', 300,
+ 'number of seconds to wait for agent to be fully '
+ 'operational')
flags.DEFINE_string('xenapi_vif_driver',
'nova.virt.xenapi.vif.XenAPIBridgeDriver',
'The XenAPI VIF driver using XenServer Network APIs.')
@@ -324,15 +324,8 @@ class VMOps(object):
def _check_agent_version():
LOG.debug(_("Querying agent version"))
- if instance.os_type == 'windows':
- # Windows will generally perform a setup process on first boot
- # that can take a couple of minutes and then reboot. So we
- # need to be more patient than normal as well as watch for
- # domid changes
- version = self.get_agent_version(instance,
- timeout=FLAGS.windows_version_timeout)
- else:
- version = self.get_agent_version(instance)
+
+ version = self.get_agent_version(instance)
if not version:
return
@@ -639,9 +632,15 @@ class VMOps(object):
self._session.wait_for_task(task, instance.id)
- def get_agent_version(self, instance, timeout=None):
+ def get_agent_version(self, instance):
"""Get the version of the agent running on the VM instance."""
+ # The agent can be slow to start for a variety of reasons. On Windows,
+ # it will generally perform a setup process on first boot that can
+ # take a couple of minutes and then reboot. On Linux, the system can
+ # also take a while to boot. So we need to be more patient than
+ # normal as well as watch for domid changes
+
def _call():
# Send the encrypted password
transaction_id = str(uuid.uuid4())
@@ -655,27 +654,26 @@ class VMOps(object):
# (ie CRLF escaped) for some reason. Strip that off.
return resp['message'].replace('\\r\\n', '')
- if timeout:
- vm_ref = self._get_vm_opaque_ref(instance)
- vm_rec = self._session.get_xenapi().VM.get_record(vm_ref)
+ vm_ref = self._get_vm_opaque_ref(instance)
+ vm_rec = self._session.get_xenapi().VM.get_record(vm_ref)
- domid = vm_rec['domid']
-
- expiration = time.time() + timeout
- while time.time() < expiration:
- ret = _call()
- if ret:
- return ret
-
- vm_rec = self._session.get_xenapi().VM.get_record(vm_ref)
- if vm_rec['domid'] != domid:
- LOG.info(_('domid changed from %(olddomid)s to '
- '%(newdomid)s') % {
- 'olddomid': domid,
- 'newdomid': vm_rec['domid']})
- domid = vm_rec['domid']
- else:
- return _call()
+ domid = vm_rec['domid']
+
+ expiration = time.time() + FLAGS.agent_version_timeout
+ while time.time() < expiration:
+ ret = _call()
+ if ret:
+ return ret
+
+ vm_rec = self._session.get_xenapi().VM.get_record(vm_ref)
+ if vm_rec['domid'] != domid:
+ LOG.info(_('domid changed from %(olddomid)s to '
+ '%(newdomid)s') % {
+ 'olddomid': domid,
+ 'newdomid': vm_rec['domid']})
+ domid = vm_rec['domid']
+
+ return None
def agent_update(self, instance, url, md5sum):
"""Update agent on the VM instance."""