~tr3buchet/nova/lock

« back to all changes in this revision

Viewing changes to nova/virt/libvirt_conn.py

  • Committer: Vishvananda Ishaya
  • Date: 2010-12-22 20:59:53 UTC
  • mto: This revision was merged to the branch mainline in revision 482.
  • Revision ID: vishvananda@gmail.com-20101222205953-j2j5t0qjwlcd0t2s
merge trunk and upgrade to cheetah templating

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
:libvirt_type:  Libvirt domain type.  Can be kvm, qemu, uml, xen
28
28
                (default: kvm).
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
64
59
 
 
60
from Cheetah.Template import Template
 
61
 
65
62
libvirt = None
66
63
libxml2 = None
67
64
 
68
65
 
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',
96
75
                    'kvm',
97
76
                    'Libvirt domain type (valid options are: '
123
102
 
124
103
 
125
104
class LibvirtConnection(object):
 
105
 
126
106
    def __init__(self, read_only):
127
 
        (self.libvirt_uri,
128
 
         template_file,
129
 
         rescue_file) = self.get_uri_and_templates()
 
107
        self.libvirt_uri = self.get_uri()
130
108
 
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
135
112
 
139
116
    @property
140
117
    def _conn(self):
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,
144
121
                                               self.read_only)
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'))
155
132
                return False
156
133
            raise
157
134
 
158
 
    def get_uri_and_templates(self):
 
135
    def get_uri(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
167
140
        else:
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
 
142
        return uri
172
143
 
173
144
    def _connect(self, uri, read_only):
174
145
        auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT],
228
199
 
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)
272
243
        if not xml:
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)
275
246
 
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'])
290
261
                    timer.stop()
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(),
294
265
                                      instance['id'],
295
266
                                      power_state.SHUTDOWN)
299
270
        return timer.start(interval=0.5, now=True)
300
271
 
301
272
    @exception.wrap_exception
 
273
    def pause(self, instance, callback):
 
274
        raise exception.APIError("pause not supported for libvirt.")
 
275
 
 
276
    @exception.wrap_exception
 
277
    def unpause(self, instance, callback):
 
278
        raise exception.APIError("unpause not supported for libvirt.")
 
279
 
 
280
    @exception.wrap_exception
302
281
    def rescue(self, instance):
303
282
        self.destroy(instance, False)
304
283
 
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'])
320
299
                    timer.stop()
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,
324
303
                                      instance['id'],
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'])
348
327
 
349
328
        timer = utils.LoopingCall(f=None)
350
329
 
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'])
358
337
                    timer.stop()
359
338
            except:
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(),
363
342
                                      instance['id'],
372
351
        virsh_output = virsh_output[0].strip()
373
352
 
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)
378
357
            return out
380
359
            return ''
381
360
 
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+')
385
364
        fp.write(data)
386
365
        return fpath
422
401
 
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)
428
407
        f.close()
441
420
        if not os.path.exists(basepath('disk')):
442
421
            images.fetch(inst.image_id, basepath('disk-raw'), user,
443
422
                         project)
444
 
        if not os.path.exists(basepath('kernel')):
445
 
            images.fetch(inst.kernel_id, basepath('kernel'), user,
446
 
                         project)
447
 
        if not os.path.exists(basepath('ramdisk')):
448
 
            images.fetch(inst.ramdisk_id, basepath('ramdisk'), user,
449
 
                         project)
 
423
 
 
424
        if inst['kernel_id']:
 
425
            if not os.path.exists(basepath('kernel')):
 
426
                images.fetch(inst['kernel_id'], basepath('kernel'),
 
427
                             user, project)
 
428
            if inst['ramdisk_id']:
 
429
                if not os.path.exists(basepath('ramdisk')):
 
430
                    images.fetch(inst['ramdisk_id'], basepath('ramdisk'),
 
431
                                 user, project)
450
432
 
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)
455
437
 
 
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
 
440
        # partition
 
441
        target_partition = None
 
442
        if not inst['kernel_id']:
 
443
            target_partition = "1"
 
444
 
456
445
        key = str(inst['key_data'])
457
446
        net = None
458
447
        network_ref = db.network_get_by_instance(context.get_admin_context(),
468
457
                                  'dns': network_ref['dns']}
469
458
        if key or net:
470
459
            if key:
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)
473
462
            if net:
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,
477
 
                             execute=execute)
 
463
                logging.info(_('instance %s: injecting net into image %s'),
 
464
                             inst['name'], inst.image_id)
 
465
            try:
 
466
                disk.inject_data(basepath('disk-raw'), key, net,
 
467
                                 partition=target_partition,
 
468
                                 execute=execute)
 
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)
478
474
 
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'))
481
478
 
482
479
        local_bytes = (instance_types.INSTANCE_TYPES[inst.instance_type]
483
480
                                                    ['local_gb']
486
483
        resize = True
487
484
        if inst['instance_type'] == 'm1.tiny' or prefix == 'rescue-':
488
485
            resize = False
489
 
        disk.partition(basepath('disk-raw'), basepath('disk'),
490
 
                       local_bytes, resize, execute=execute)
 
486
 
 
487
        if inst['kernel_id']:
 
488
            disk.partition(basepath('disk-raw'), basepath('disk'),
 
489
                           local_bytes, resize, execute=execute)
 
490
        else:
 
491
            os.rename(basepath('disk-raw'), basepath('disk'))
 
492
            disk.extend(basepath('disk'), local_bytes, execute=execute)
491
493
 
492
494
        if FLAGS.libvirt_type == 'uml':
493
495
            utils.execute('sudo chown root %s' % basepath('disk'))
494
496
 
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'),
 
500
                        instance['name'])
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}
527
 
        if rescue:
528
 
            libvirt_xml = self.rescue_xml % xml_info
529
 
        else:
530
 
            libvirt_xml = self.libvirt_xml % xml_info
531
 
        logging.debug('instance %s: finished toXML method', instance['name'])
532
 
 
533
 
        return libvirt_xml
 
529
                    'extra_params': extra_params,
 
530
                    'rescue': rescue}
 
531
        if not rescue:
 
532
            if instance['kernel_id']:
 
533
                xml_info['kernel'] = xml_info['basepath'] + "/kernel"
 
534
 
 
535
            if instance['ramdisk_id']:
 
536
                xml_info['ramdisk'] = xml_info['basepath'] + "/ramdisk"
 
537
 
 
538
            xml_info['disk'] = xml_info['basepath'] + "/disk"
 
539
 
 
540
        xml = str(Template(self.libvirt_xml, searchList=[xml_info]))
 
541
        logging.debug(_('instance %s: finished toXML method'),
 
542
                        instance['name'])
 
543
 
 
544
        return xml
534
545
 
535
546
    def get_info(self, instance_name):
536
547
        try:
537
548
            virt_dom = self._conn.lookupByName(instance_name)
538
549
        except:
539
 
            raise exception.NotFound("Instance %s not found" % instance_name)
 
550
            raise exception.NotFound(_("Instance %s not found")
 
551
                                     % instance_name)
540
552
        (state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info()
541
553
        return {'state': state,
542
554
                'max_mem': max_mem,