27
27
:libvirt_type: Libvirt domain type. Can be kvm, qemu, uml, xen
29
29
:libvirt_uri: Override for the default libvirt URI (depends on libvirt_type).
30
:libvirt_xml_template: Libvirt XML Template (QEmu/KVM).
31
:libvirt_xen_xml_template: Libvirt XML Template (Xen).
32
:libvirt_uml_xml_template: Libvirt XML Template (User Mode Linux).
33
:libvirt_rescue_xml_template: XML template for rescue mode (KVM & QEMU).
34
:libvirt_rescue_xen_xml_template: XML templage for rescue mode (XEN).
35
:libvirt_rescue_uml_xml_template: XML template for rescue mode (UML).
30
:libvirt_xml_template: Libvirt XML Template.
36
31
:rescue_image_id: Rescue ami image (default: ami-rescue).
37
32
:rescue_kernel_id: Rescue aki image (default: aki-rescue).
38
33
:rescue_ramdisk_id: Rescue ari image (default: ari-rescue).
62
57
from nova.compute import power_state
63
58
from nova.virt import images
60
from Cheetah.Template import Template
69
66
FLAGS = flags.FLAGS
70
flags.DEFINE_string('libvirt_rescue_xml_template',
71
utils.abspath('virt/libvirt.rescue.qemu.xml.template'),
72
'Libvirt RESCUE XML Template for QEmu/KVM')
73
flags.DEFINE_string('libvirt_rescue_xen_xml_template',
74
utils.abspath('virt/libvirt.rescue.xen.xml.template'),
75
'Libvirt RESCUE XML Template for xen')
76
flags.DEFINE_string('libvirt_rescue_uml_xml_template',
77
utils.abspath('virt/libvirt.rescue.uml.xml.template'),
78
'Libvirt RESCUE XML Template for user-mode-linux')
79
67
# TODO(vish): These flags should probably go into a shared location
80
68
flags.DEFINE_string('rescue_image_id', 'ami-rescue', 'Rescue ami image')
81
69
flags.DEFINE_string('rescue_kernel_id', 'aki-rescue', 'Rescue aki image')
82
70
flags.DEFINE_string('rescue_ramdisk_id', 'ari-rescue', 'Rescue ari image')
83
71
flags.DEFINE_string('libvirt_xml_template',
84
utils.abspath('virt/libvirt.qemu.xml.template'),
85
'Libvirt XML Template for QEmu/KVM')
86
flags.DEFINE_string('libvirt_xen_xml_template',
87
utils.abspath('virt/libvirt.xen.xml.template'),
88
'Libvirt XML Template for Xen')
89
flags.DEFINE_string('libvirt_uml_xml_template',
90
utils.abspath('virt/libvirt.uml.xml.template'),
91
'Libvirt XML Template for user-mode-linux')
92
flags.DEFINE_string('injected_network_template',
93
utils.abspath('virt/interfaces.template'),
94
'Template file for injected network')
72
utils.abspath('virt/libvirt.xml.template'),
73
'Libvirt XML Template')
95
74
flags.DEFINE_string('libvirt_type',
97
76
'Libvirt domain type (valid options are: '
125
104
class LibvirtConnection(object):
126
106
def __init__(self, read_only):
129
rescue_file) = self.get_uri_and_templates()
107
self.libvirt_uri = self.get_uri()
131
self.libvirt_xml = open(template_file).read()
132
self.rescue_xml = open(rescue_file).read()
109
self.libvirt_xml = open(FLAGS.libvirt_xml_template).read()
133
110
self._wrapped_conn = None
134
111
self.read_only = read_only
141
118
if not self._wrapped_conn or not self._test_connection():
142
logging.debug('Connecting to libvirt: %s' % self.libvirt_uri)
119
logging.debug(_('Connecting to libvirt: %s') % self.libvirt_uri)
143
120
self._wrapped_conn = self._connect(self.libvirt_uri,
145
122
return self._wrapped_conn
151
128
except libvirt.libvirtError as e:
152
129
if e.get_error_code() == libvirt.VIR_ERR_SYSTEM_ERROR and \
153
130
e.get_error_domain() == libvirt.VIR_FROM_REMOTE:
154
logging.debug('Connection to libvirt broke')
131
logging.debug(_('Connection to libvirt broke'))
158
def get_uri_and_templates(self):
159
136
if FLAGS.libvirt_type == 'uml':
160
137
uri = FLAGS.libvirt_uri or 'uml:///system'
161
template_file = FLAGS.libvirt_uml_xml_template
162
rescue_file = FLAGS.libvirt_rescue_uml_xml_template
163
138
elif FLAGS.libvirt_type == 'xen':
164
139
uri = FLAGS.libvirt_uri or 'xen:///'
165
template_file = FLAGS.libvirt_xen_xml_template
166
rescue_file = FLAGS.libvirt_rescue_xen_xml_template
168
141
uri = FLAGS.libvirt_uri or 'qemu:///system'
169
template_file = FLAGS.libvirt_xml_template
170
rescue_file = FLAGS.libvirt_rescue_xml_template
171
return uri, template_file, rescue_file
173
144
def _connect(self, uri, read_only):
174
145
auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT],
229
200
def _cleanup(self, instance):
230
201
target = os.path.join(FLAGS.instances_path, instance['name'])
231
logging.info('instance %s: deleting instance files %s',
202
logging.info(_('instance %s: deleting instance files %s'),
232
203
instance['name'], target)
233
204
if os.path.exists(target):
234
205
shutil.rmtree(target)
270
241
mount_device = mountpoint.rpartition("/")[2]
271
242
xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device)
273
raise exception.NotFound("No disk at %s" % mount_device)
244
raise exception.NotFound(_("No disk at %s") % mount_device)
274
245
virt_dom.detachDevice(xml)
276
247
@exception.wrap_exception
286
257
db.instance_set_state(context.get_admin_context(),
287
258
instance['id'], state)
288
259
if state == power_state.RUNNING:
289
logging.debug('instance %s: rebooted', instance['name'])
260
logging.debug(_('instance %s: rebooted'), instance['name'])
291
262
except Exception, exn:
292
logging.error('_wait_for_reboot failed: %s', exn)
263
logging.error(_('_wait_for_reboot failed: %s'), exn)
293
264
db.instance_set_state(context.get_admin_context(),
295
266
power_state.SHUTDOWN)
299
270
return timer.start(interval=0.5, now=True)
301
272
@exception.wrap_exception
273
def pause(self, instance, callback):
274
raise exception.APIError("pause not supported for libvirt.")
276
@exception.wrap_exception
277
def unpause(self, instance, callback):
278
raise exception.APIError("unpause not supported for libvirt.")
280
@exception.wrap_exception
302
281
def rescue(self, instance):
303
282
self.destroy(instance, False)
316
295
state = self.get_info(instance['name'])['state']
317
296
db.instance_set_state(None, instance['id'], state)
318
297
if state == power_state.RUNNING:
319
logging.debug('instance %s: rescued', instance['name'])
298
logging.debug(_('instance %s: rescued'), instance['name'])
321
300
except Exception, exn:
322
logging.error('_wait_for_rescue failed: %s', exn)
301
logging.error(_('_wait_for_rescue failed: %s'), exn)
323
302
db.instance_set_state(None,
325
304
power_state.SHUTDOWN)
344
323
NWFilterFirewall(self._conn).setup_nwfilters_for_instance(instance)
345
324
self._create_image(instance, xml)
346
325
self._conn.createXML(xml, 0)
347
logging.debug("instance %s: is running", instance['name'])
326
logging.debug(_("instance %s: is running"), instance['name'])
349
328
timer = utils.LoopingCall(f=None)
354
333
db.instance_set_state(context.get_admin_context(),
355
334
instance['id'], state)
356
335
if state == power_state.RUNNING:
357
logging.debug('instance %s: booted', instance['name'])
336
logging.debug(_('instance %s: booted'), instance['name'])
360
logging.exception('instance %s: failed to boot',
339
logging.exception(_('instance %s: failed to boot'),
361
340
instance['name'])
362
341
db.instance_set_state(context.get_admin_context(),
372
351
virsh_output = virsh_output[0].strip()
374
353
if virsh_output.startswith('/dev/'):
375
logging.info('cool, it\'s a device')
354
logging.info(_('cool, it\'s a device'))
376
355
out, err = utils.execute("sudo dd if=%s iflag=nonblock" %
377
356
virsh_output, check_exit_code=False)
382
361
def _append_to_file(self, data, fpath):
383
logging.info('data: %r, fpath: %r' % (data, fpath))
362
logging.info(_('data: %r, fpath: %r') % (data, fpath))
384
363
fp = open(fpath, 'a+')
423
402
# TODO(termie): these are blocking calls, it would be great
424
403
# if they weren't.
425
logging.info('instance %s: Creating image', inst['name'])
404
logging.info(_('instance %s: Creating image'), inst['name'])
426
405
f = open(basepath('libvirt.xml'), 'w')
427
406
f.write(libvirt_xml)
441
420
if not os.path.exists(basepath('disk')):
442
421
images.fetch(inst.image_id, basepath('disk-raw'), user,
444
if not os.path.exists(basepath('kernel')):
445
images.fetch(inst.kernel_id, basepath('kernel'), user,
447
if not os.path.exists(basepath('ramdisk')):
448
images.fetch(inst.ramdisk_id, basepath('ramdisk'), user,
424
if inst['kernel_id']:
425
if not os.path.exists(basepath('kernel')):
426
images.fetch(inst['kernel_id'], basepath('kernel'),
428
if inst['ramdisk_id']:
429
if not os.path.exists(basepath('ramdisk')):
430
images.fetch(inst['ramdisk_id'], basepath('ramdisk'),
451
433
def execute(cmd, process_input=None, check_exit_code=True):
452
434
return utils.execute(cmd=cmd,
453
435
process_input=process_input,
454
436
check_exit_code=check_exit_code)
438
# For now, we assume that if we're not using a kernel, we're using a
439
# partitioned disk image where the target partition is the first
441
target_partition = None
442
if not inst['kernel_id']:
443
target_partition = "1"
456
445
key = str(inst['key_data'])
458
447
network_ref = db.network_get_by_instance(context.get_admin_context(),
468
457
'dns': network_ref['dns']}
471
logging.info('instance %s: injecting key into image %s',
460
logging.info(_('instance %s: injecting key into image %s'),
472
461
inst['name'], inst.image_id)
474
logging.info('instance %s: injecting net into image %s',
475
inst['name'], inst.image_id)
476
disk.inject_data(basepath('disk-raw'), key, net,
463
logging.info(_('instance %s: injecting net into image %s'),
464
inst['name'], inst.image_id)
466
disk.inject_data(basepath('disk-raw'), key, net,
467
partition=target_partition,
469
except Exception as e:
470
# This could be a windows image, or a vmdk format disk
471
logging.warn(_('instance %s: ignoring error injecting data'
472
' into image %s (%s)'),
473
inst['name'], inst.image_id, e)
479
if os.path.exists(basepath('disk')):
480
utils.execute('rm -f %s' % basepath('disk'))
475
if inst['kernel_id']:
476
if os.path.exists(basepath('disk')):
477
utils.execute('rm -f %s' % basepath('disk'))
482
479
local_bytes = (instance_types.INSTANCE_TYPES[inst.instance_type]
487
484
if inst['instance_type'] == 'm1.tiny' or prefix == 'rescue-':
489
disk.partition(basepath('disk-raw'), basepath('disk'),
490
local_bytes, resize, execute=execute)
487
if inst['kernel_id']:
488
disk.partition(basepath('disk-raw'), basepath('disk'),
489
local_bytes, resize, execute=execute)
491
os.rename(basepath('disk-raw'), basepath('disk'))
492
disk.extend(basepath('disk'), local_bytes, execute=execute)
492
494
if FLAGS.libvirt_type == 'uml':
493
495
utils.execute('sudo chown root %s' % basepath('disk'))
495
497
def to_xml(self, instance, rescue=False):
496
498
# TODO(termie): cache?
497
logging.debug('instance %s: starting toXML method', instance['name'])
499
logging.debug(_('instance %s: starting toXML method'),
498
501
network = db.project_get_network(context.get_admin_context(),
499
502
instance['project_id'])
500
503
# FIXME(vish): stick this in db
523
526
'mac_address': instance['mac_address'],
524
527
'ip_address': ip_address,
525
528
'dhcp_server': dhcp_server,
526
'extra_params': extra_params}
528
libvirt_xml = self.rescue_xml % xml_info
530
libvirt_xml = self.libvirt_xml % xml_info
531
logging.debug('instance %s: finished toXML method', instance['name'])
529
'extra_params': extra_params,
532
if instance['kernel_id']:
533
xml_info['kernel'] = xml_info['basepath'] + "/kernel"
535
if instance['ramdisk_id']:
536
xml_info['ramdisk'] = xml_info['basepath'] + "/ramdisk"
538
xml_info['disk'] = xml_info['basepath'] + "/disk"
540
xml = str(Template(self.libvirt_xml, searchList=[xml_info]))
541
logging.debug(_('instance %s: finished toXML method'),
535
546
def get_info(self, instance_name):
537
548
virt_dom = self._conn.lookupByName(instance_name)
539
raise exception.NotFound("Instance %s not found" % instance_name)
550
raise exception.NotFound(_("Instance %s not found")
540
552
(state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info()
541
553
return {'state': state,
542
554
'max_mem': max_mem,