~ubuntu-branches/ubuntu/quantal/virtinst/quantal-proposed

« back to all changes in this revision

Viewing changes to .pc/0004-Fix-path-to-qemu-dm.patch/virtinst/Guest.py

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-02-24 15:51:30 UTC
  • Revision ID: package-import@ubuntu.com-20120224155130-wqwm16u5chv3anxe
Tags: 0.600.1-1ubuntu2
debian/patches/0004-Fix-path-to-qemu-dm.patch: fix the path to the
qemu-dm binary. (LP: #936048)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Common code for all guests
 
3
#
 
4
# Copyright 2006-2009  Red Hat, Inc.
 
5
# Jeremy Katz <katzj@redhat.com>
 
6
#
 
7
# This program is free software; you can redistribute it and/or modify
 
8
# it under the terms of the GNU General Public License as published by
 
9
# the Free  Software Foundation; either version 2 of the License, or
 
10
# (at your option)  any later version.
 
11
#
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public License
 
18
# along with this program; if not, write to the Free Software
 
19
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
20
# MA 02110-1301 USA.
 
21
 
 
22
import os
 
23
import time
 
24
import logging
 
25
import signal
 
26
 
 
27
import urlgrabber.progress as progress
 
28
import libvirt
 
29
import libxml2
 
30
 
 
31
import _util
 
32
import CapabilitiesParser
 
33
import VirtualGraphics
 
34
import support
 
35
import XMLBuilderDomain
 
36
import virtinst
 
37
from XMLBuilderDomain import _xml_property
 
38
import DistroInstaller
 
39
from VirtualDevice import VirtualDevice
 
40
from VirtualDisk import VirtualDisk
 
41
from VirtualInputDevice import VirtualInputDevice
 
42
from VirtualCharDevice import VirtualCharDevice
 
43
from VirtualController import VirtualControllerUSB
 
44
from Clock import Clock
 
45
from Seclabel import Seclabel
 
46
from CPU import CPU
 
47
from DomainNumatune import DomainNumatune
 
48
from DomainFeatures import DomainFeatures
 
49
 
 
50
import osdict
 
51
from virtinst import _gettext as _
 
52
 
 
53
 
 
54
class Guest(XMLBuilderDomain.XMLBuilderDomain):
 
55
 
 
56
    # OS Dictionary static variables and methods
 
57
    _DEFAULTS = osdict.DEFAULTS
 
58
    _OS_TYPES = osdict.OS_TYPES
 
59
 
 
60
    _default_os_type = None
 
61
 
 
62
    @staticmethod
 
63
    def pretty_os_list():
 
64
        """
 
65
        Return a strip representation of OS list for printing
 
66
        """
 
67
        ret = ""
 
68
        for t in Guest.list_os_types():
 
69
            for v in Guest.list_os_variants(t):
 
70
                ret += "%-20s : %s\n" % (v, Guest.get_os_variant_label(t, v))
 
71
        return ret
 
72
 
 
73
    @staticmethod
 
74
    def list_os_types(supported=False, filtervars=None):
 
75
        """
 
76
        @param filtervars: List of only variants we want to show by default
 
77
        """
 
78
        vals = osdict.sort_helper(Guest._OS_TYPES)
 
79
        for t in vals[:]:
 
80
            if not Guest.list_os_variants(t, supported=supported,
 
81
                                          filtervars=filtervars):
 
82
                vals.remove(t)
 
83
        return vals
 
84
 
 
85
    @staticmethod
 
86
    def list_os_variants(type, sortpref=None, supported=False, filtervars=None):
 
87
        """
 
88
        Return a list of sorted os variants for the passed distro type
 
89
 
 
90
        @param sortpref: An option list of osdict 'distro' tags to
 
91
        prioritize in the returned list, e.g. passing ["fedora"] will make
 
92
        the sorted list have all fedora distros first
 
93
        @param filtervars: List of only variants we want to show by default
 
94
        """
 
95
        vals = osdict.sort_helper(Guest._OS_TYPES[type]["variants"],
 
96
                                  sortpref)
 
97
        ret = []
 
98
        for v in vals:
 
99
            if filtervars:
 
100
                if v not in filtervars:
 
101
                    continue
 
102
            elif supported:
 
103
                if not osdict.lookup_osdict_key(None, None,
 
104
                                                type, v, "supported"):
 
105
                    continue
 
106
 
 
107
            ret.append(v)
 
108
        return ret
 
109
 
 
110
    @staticmethod
 
111
    def get_os_type_label(type):
 
112
        return Guest._OS_TYPES[type]["label"]
 
113
 
 
114
    @staticmethod
 
115
    def get_os_variant_label(type, variant):
 
116
        return Guest._OS_TYPES[type]["variants"][variant]["label"]
 
117
 
 
118
    @staticmethod
 
119
    def cpuset_str_to_tuple(conn, cpuset):
 
120
        return DomainNumatune.cpuset_str_to_tuple(conn, cpuset)
 
121
 
 
122
    @staticmethod
 
123
    def generate_cpuset(conn, mem):
 
124
        """
 
125
        Generates a cpu pinning string based on host NUMA configuration.
 
126
 
 
127
        If host doesn't have a suitable NUMA configuration, a RuntimeError
 
128
        is thrown.
 
129
        """
 
130
        caps = CapabilitiesParser.parse(conn.getCapabilities())
 
131
 
 
132
        if caps.host.topology is None:
 
133
            raise RuntimeError(_("No topology section in capabilities xml."))
 
134
 
 
135
        cells = caps.host.topology.cells
 
136
        if len(cells) <= 1:
 
137
            raise RuntimeError(_("Capabilities only show <= 1 cell. "
 
138
                                 "Not NUMA capable"))
 
139
 
 
140
        # Capabilities tells us about the available memory 'cells' on the
 
141
        # system. Each 'cell' has associated 'cpu's.
 
142
        #
 
143
        # Use getCellsFreeMemory to determine which 'cell' has the smallest
 
144
        # amount of memory which fits the requested VM memory amount, then
 
145
        # pin the VM to that 'cell's associated 'cpu's
 
146
 
 
147
        cell_mem = conn.getCellsFreeMemory(0, len(cells))
 
148
        cell_id = -1
 
149
        mem = mem * 1024
 
150
        for i in range(len(cells)):
 
151
            if cell_mem[i] < mem:
 
152
                # Cell doesn't have enough mem to fit, skip it
 
153
                continue
 
154
 
 
155
            if len(cells[i].cpus) == 0:
 
156
                # No cpus to use for the cell
 
157
                continue
 
158
 
 
159
            # Find smallest cell that fits
 
160
            if cell_id < 0 or cell_mem[i] < cell_mem[cell_id]:
 
161
                cell_id = i
 
162
 
 
163
        if cell_id < 0:
 
164
            raise RuntimeError(_("Could not find any usable NUMA "
 
165
                                 "cell/cpu combinations."))
 
166
 
 
167
        # Build cpuset string
 
168
        cpustr = ""
 
169
        for cpu in cells[cell_id].cpus:
 
170
            if cpustr != "":
 
171
                cpustr += ","
 
172
            cpustr += str(cpu.id)
 
173
 
 
174
        return cpustr
 
175
 
 
176
    def __init__(self, type=None, connection=None, hypervisorURI=None,
 
177
                 installer=None, parsexml=None, caps=None, conn=None):
 
178
 
 
179
        # Set up the connection, since it is fundamental for other init
 
180
        conn = conn or connection
 
181
        if conn == None:
 
182
            logging.debug("No conn passed to Guest, opening URI '%s'" %
 
183
                          hypervisorURI)
 
184
            conn = self._open_uri(hypervisorURI)
 
185
 
 
186
        if conn == None:
 
187
            raise RuntimeError(_("Unable to connect to hypervisor, aborting "
 
188
                                 "installation!"))
 
189
 
 
190
        self._name = None
 
191
        self._uuid = None
 
192
        self._memory = None
 
193
        self._maxmemory = None
 
194
        self._hugepage = None
 
195
        self._vcpus = 1
 
196
        self._maxvcpus = 1
 
197
        self._cpuset = None
 
198
        self._autostart = False
 
199
        self._clock = None
 
200
        self._seclabel = None
 
201
        self._description = None
 
202
        self._features = None
 
203
        self._replace = None
 
204
        self._emulator = None
 
205
        self._installer = installer
 
206
 
 
207
        self._os_type = None
 
208
        self._os_variant = None
 
209
        self._os_autodetect = False
 
210
 
 
211
        # DEPRECATED: Public device lists unaltered by install process
 
212
        self.disks = []
 
213
        self.nics = []
 
214
        self.sound_devs = []
 
215
        self.hostdevs = []
 
216
 
 
217
        # General device list. Only access through API calls (even internally)
 
218
        self._devices = []
 
219
 
 
220
        # Device list to use/alter during install process. Don't access
 
221
        # directly, use internal APIs
 
222
        self._install_devices = []
 
223
 
 
224
        # The libvirt virDomain object we 'Create'
 
225
        self.domain = None
 
226
        self._consolechild = None
 
227
 
 
228
        self._default_input_device = None
 
229
        self._default_console_device = None
 
230
 
 
231
        caps = caps or (self._installer and self._installer._get_caps())
 
232
        XMLBuilderDomain.XMLBuilderDomain.__init__(self, conn, parsexml,
 
233
                                                   caps=caps)
 
234
        if self._is_parse():
 
235
            return
 
236
 
 
237
        if not self.installer:
 
238
            i = DistroInstaller.DistroInstaller(type=type,
 
239
                                                conn=conn,
 
240
                                                os_type=self._default_os_type,
 
241
                                                caps=self._get_caps())
 
242
            self.installer = i
 
243
 
 
244
        # Add default devices (if applicable)
 
245
        inp = self._get_default_input_device()
 
246
        if inp:
 
247
            self.add_device(inp)
 
248
        self._default_input_device = inp
 
249
 
 
250
        con = self._get_default_console_device()
 
251
        con.virtinst_default = True
 
252
        self.add_device(con)
 
253
        self._default_console_device = con
 
254
 
 
255
        # Need to do this after all parameter init
 
256
        self._features = DomainFeatures(self.conn)
 
257
        self._clock = Clock(self.conn)
 
258
        self._seclabel = Seclabel(self.conn)
 
259
        self._cpu = CPU(self.conn)
 
260
        self._numatune = DomainNumatune(self.conn)
 
261
 
 
262
    def _open_uri(self, uri):
 
263
        # This is here so test suite can overwrite it, to make sure
 
264
        # Guest is never opening anything
 
265
        return libvirt.open(uri)
 
266
 
 
267
    ######################
 
268
    # Property accessors #
 
269
    ######################
 
270
 
 
271
    def get_installer(self):
 
272
        return self._installer
 
273
    def set_installer(self, val):
 
274
        self._installer = val
 
275
    installer = property(get_installer, set_installer)
 
276
 
 
277
    def get_clock(self):
 
278
        return self._clock
 
279
    clock = property(get_clock)
 
280
    def get_seclabel(self):
 
281
        return self._seclabel
 
282
    seclabel = property(get_seclabel)
 
283
    def get_cpu(self):
 
284
        return self._cpu
 
285
    cpu = property(get_cpu)
 
286
    def get_numatune(self):
 
287
        return self._numatune
 
288
    numatune = property(get_numatune)
 
289
 
 
290
    def _get_features(self):
 
291
        return self._features
 
292
    features = property(_get_features)
 
293
 
 
294
    # Domain name of the guest
 
295
    def get_name(self):
 
296
        return self._name
 
297
    def set_name(self, val):
 
298
        _util.validate_name(_("Guest"), val, lencheck=True)
 
299
 
 
300
        do_fail = False
 
301
        if self.replace != True:
 
302
            try:
 
303
                self.conn.lookupByName(val)
 
304
                do_fail = True
 
305
            except:
 
306
                # Name not found
 
307
                pass
 
308
 
 
309
        if do_fail:
 
310
            raise ValueError(_("Guest name '%s' is already in use.") % val)
 
311
 
 
312
        self._name = val
 
313
    name = _xml_property(get_name, set_name,
 
314
                         xpath="./name")
 
315
 
 
316
    # Memory allocated to the guest.  Should be given in MB
 
317
    def get_memory(self):
 
318
        return self._memory
 
319
    def set_memory(self, val):
 
320
        if (type(val) is not type(1) or val <= 0):
 
321
            raise ValueError(_("Memory value must be an integer greater "
 
322
                               "than 0"))
 
323
        self._memory = val
 
324
 
 
325
        if self.maxmemory is None or self.maxmemory < val:
 
326
            self.maxmemory = val
 
327
    def _xml_memory_value(self):
 
328
        return int(self.memory) * 1024
 
329
    memory = _xml_property(get_memory, set_memory,
 
330
                           xpath="./currentMemory",
 
331
                           get_converter=lambda s, x: int(x) / 1024,
 
332
                           set_converter=lambda s, x: int(x) * 1024)
 
333
 
 
334
    # Memory allocated to the guest.  Should be given in MB
 
335
    def get_maxmemory(self):
 
336
        return self._maxmemory
 
337
    def set_maxmemory(self, val):
 
338
        if (type(val) is not type(1) or val <= 0):
 
339
            raise ValueError(_("Max Memory value must be an integer greater "
 
340
                               "than 0"))
 
341
        self._maxmemory = val
 
342
    def _xml_maxmemory_value(self):
 
343
        return int(self.maxmemory) * 1024
 
344
    maxmemory = _xml_property(get_maxmemory, set_maxmemory,
 
345
                              xpath="./memory",
 
346
                              get_converter=lambda s, x: int(x) / 1024,
 
347
                              set_converter=lambda s, x: int(x) * 1024)
 
348
    def get_hugepage(self):
 
349
        return self._hugepage
 
350
    def set_hugepage(self, val):
 
351
        if val is None:
 
352
            return val
 
353
        self._hugepage = bool(val)
 
354
    hugepage = _xml_property(get_hugepage, set_hugepage,
 
355
                             xpath="./memoryBacking/hugepages", is_bool=True)
 
356
 
 
357
    # UUID for the guest
 
358
    def get_uuid(self):
 
359
        return self._uuid
 
360
    def set_uuid(self, val):
 
361
        val = _util.validate_uuid(val)
 
362
        self._uuid = val
 
363
    uuid = _xml_property(get_uuid, set_uuid,
 
364
                         xpath="./uuid")
 
365
 
 
366
    def __validate_cpus(self, val):
 
367
        maxvcpus = _util.get_max_vcpus(self.conn, self.type)
 
368
        val = int(val)
 
369
        if val < 1:
 
370
            raise ValueError(_("Number of vcpus must be a positive integer."))
 
371
        if val > maxvcpus:
 
372
            raise ValueError(_("Number of vcpus must be no greater than %d "
 
373
                               "for this vm type.") % maxvcpus)
 
374
        return val
 
375
 
 
376
    # number of vcpus for the guest
 
377
    def get_vcpus(self):
 
378
        return self._vcpus
 
379
    def set_vcpus(self, val):
 
380
        val = self.__validate_cpus(val)
 
381
        self._vcpus = val
 
382
 
 
383
        # Don't force set maxvcpus unless already specified
 
384
        if self.maxvcpus is not None and self.maxvcpus < val:
 
385
            self.maxvcpus = val
 
386
    def _vcpus_get_converter(self, val):
 
387
        # If no current VCPUs, return maxvcpus
 
388
        if not val:
 
389
            val = self.maxvcpus
 
390
        return int(val)
 
391
    vcpus = _xml_property(get_vcpus, set_vcpus,
 
392
                          xpath="./vcpu/@current",
 
393
                          get_converter=_vcpus_get_converter)
 
394
 
 
395
    def _get_maxvcpus(self):
 
396
        return self._maxvcpus
 
397
    def _set_maxvcpus(self, val):
 
398
        val = self.__validate_cpus(val)
 
399
        self._maxvcpus = val
 
400
    maxvcpus = _xml_property(_get_maxvcpus, _set_maxvcpus,
 
401
                             xpath="./vcpu",
 
402
                             get_converter=lambda s, x: int(x))
 
403
 
 
404
    # set phy-cpus for the guest
 
405
    def get_cpuset(self):
 
406
        return self._cpuset
 
407
    def set_cpuset(self, val):
 
408
        if val is None or val == "":
 
409
            self._cpuset = None
 
410
            return
 
411
 
 
412
        DomainNumatune.validate_cpuset(self.conn, val)
 
413
        self._cpuset = val
 
414
    cpuset = _xml_property(get_cpuset, set_cpuset,
 
415
                           xpath="./vcpu/@cpuset")
 
416
 
 
417
    def get_graphics_dev(self):
 
418
        gdevs = self.get_devices(VirtualDevice.VIRTUAL_DEV_GRAPHICS)
 
419
        return (gdevs and gdevs[0] or None)
 
420
    def set_graphics_dev(self, val):
 
421
        gdev = self.graphics_dev
 
422
        if val:
 
423
            self.add_device(val)
 
424
        if gdev:
 
425
            self.remove_device(gdev)
 
426
    graphics_dev = property(get_graphics_dev, set_graphics_dev)
 
427
 
 
428
    # GAH! - installer.os_type = "hvm" or "xen" (aka xen paravirt)
 
429
    #        guest.os_type     = "Solaris", "Windows", "Linux"
 
430
    # FIXME: We should really rename this property to something else,
 
431
    #        change it throughout the codebase for readability sake, but
 
432
    #        maintain back compat.
 
433
    def get_os_type(self):
 
434
        return self._os_type
 
435
    def set_os_type(self, val):
 
436
        if type(val) is not str:
 
437
            raise ValueError(_("OS type must be a string."))
 
438
        val = val.lower()
 
439
 
 
440
        if val in self._OS_TYPES:
 
441
            if self._os_type != val:
 
442
                # Invalidate variant, since it may not apply to the new os type
 
443
                self._os_type = val
 
444
                self._os_variant = None
 
445
        else:
 
446
            raise ValueError(_("OS type '%s' does not exist in our "
 
447
                                "dictionary") % val)
 
448
 
 
449
    os_type = property(get_os_type, set_os_type)
 
450
 
 
451
    def get_os_variant(self):
 
452
        return self._os_variant
 
453
    def set_os_variant(self, val):
 
454
        if type(val) is not str:
 
455
            raise ValueError(_("OS variant must be a string."))
 
456
        val = val.lower()
 
457
 
 
458
        if self.os_type:
 
459
            if val in self._OS_TYPES[self.os_type]["variants"]:
 
460
                self._os_variant = val
 
461
            else:
 
462
                raise ValueError(_("OS variant '%(var)s' does not exist in "
 
463
                                   "our dictionary for OS type '%(ty)s'") %
 
464
                                   {'var' : val, 'ty' : self._os_type})
 
465
        else:
 
466
            found = False
 
467
            for ostype in self.list_os_types():
 
468
                if (val in self._OS_TYPES[ostype]["variants"] and
 
469
                    not self._OS_TYPES[ostype]["variants"][val].get("skip")):
 
470
                    logging.debug("Setting os type to '%s' for variant '%s'",
 
471
                                  ostype, val)
 
472
                    self.os_type = ostype
 
473
                    self._os_variant = val
 
474
                    found = True
 
475
 
 
476
            if not found:
 
477
                raise ValueError(_("Unknown OS variant '%s'" % val))
 
478
 
 
479
    os_variant = property(get_os_variant, set_os_variant)
 
480
 
 
481
    def set_os_autodetect(self, val):
 
482
        self._os_autodetect = bool(val)
 
483
    def get_os_autodetect(self):
 
484
        return self._os_autodetect
 
485
    os_autodetect = property(get_os_autodetect, set_os_autodetect)
 
486
 
 
487
    # Get the current variants 'distro' tag: 'rhel', 'fedora', etc.
 
488
    def get_os_distro(self):
 
489
        return self._lookup_osdict_key("distro")
 
490
    os_distro = property(get_os_distro)
 
491
 
 
492
    def get_autostart(self):
 
493
        return self._autostart
 
494
    def set_autostart(self, val):
 
495
        self._autostart = bool(val)
 
496
    autostart = property(get_autostart, set_autostart,
 
497
                         doc="Have domain autostart when the host boots.")
 
498
 
 
499
    def _get_description(self):
 
500
        return self._description
 
501
    def _set_description(self, val):
 
502
        self._description = val
 
503
    description = _xml_property(_get_description, _set_description,
 
504
                                xpath="./description")
 
505
 
 
506
    def _get_emulator(self):
 
507
        return self._emulator
 
508
    def _set_emulator(self, val):
 
509
        self._emulator = val
 
510
    emulator = _xml_property(_get_emulator, _set_emulator,
 
511
                             xpath="./devices/emulator")
 
512
 
 
513
    def _get_replace(self):
 
514
        return self._replace
 
515
    def _set_replace(self, val):
 
516
        self._replace = bool(val)
 
517
    replace = property(_get_replace, _set_replace,
 
518
                       doc=_("Whether we should overwrite an existing guest "
 
519
                             "with the same name."))
 
520
 
 
521
    #########################
 
522
    # DEPRECATED PROPERTIES #
 
523
    #########################
 
524
 
 
525
    # Deprecated: Should set graphics_dev.keymap directly
 
526
    def get_keymap(self):
 
527
        if self.graphics_dev is None:
 
528
            return None
 
529
        return self.graphics_dev.keymap
 
530
    def set_keymap(self, val):
 
531
        if self.graphics_dev is not None:
 
532
            self.graphics_dev.keymap = val
 
533
    keymap = property(get_keymap, set_keymap)
 
534
 
 
535
    # Deprecated: Should set guest.graphics_dev = VirtualGraphics(...)
 
536
    def get_graphics(self):
 
537
        if self.graphics_dev is None:
 
538
            return { "enabled" : False }
 
539
        return { "enabled" : True, "type" : self.graphics_dev, \
 
540
                 "keymap"  : self.graphics_dev.keymap}
 
541
    def set_graphics(self, val):
 
542
 
 
543
        # val can be:
 
544
        #   a dictionary with keys:  enabled, type, port, keymap
 
545
        #   a tuple of the form   : (enabled, type, port, keymap)
 
546
        #                            last 2 optional
 
547
        #                         : "vnc", "sdl", or false
 
548
        port = None
 
549
        gtype = None
 
550
        enabled = False
 
551
        keymap = None
 
552
        gdev = None
 
553
        if type(val) == dict:
 
554
            if "enabled" not in val:
 
555
                raise ValueError(_("Must specify whether graphics are enabled"))
 
556
 
 
557
            enabled = val["enabled"]
 
558
            if "type" in val:
 
559
                gtype = val["type"]
 
560
                if "opts" in val:
 
561
                    port = val["opts"]
 
562
 
 
563
        elif type(val) == tuple:
 
564
            if len(val) >= 1:
 
565
                enabled = val[0]
 
566
            if len(val) >= 2:
 
567
                gtype = val[1]
 
568
            if len(val) >= 3:
 
569
                port = val[2]
 
570
            if len(val) >= 4:
 
571
                keymap = val[3]
 
572
 
 
573
        else:
 
574
            if val in ("vnc", "sdl"):
 
575
                gtype = val
 
576
                enabled = True
 
577
            else:
 
578
                enabled = val
 
579
 
 
580
        if enabled not in (True, False):
 
581
            raise ValueError(_("Graphics enabled must be True or False"))
 
582
 
 
583
        if enabled:
 
584
            gdev = VirtualGraphics.VirtualGraphics(type=gtype)
 
585
            if port:
 
586
                gdev.port = port
 
587
            if keymap:
 
588
                gdev.keymap = keymap
 
589
        self.graphics_dev = gdev
 
590
 
 
591
    graphics = property(get_graphics, set_graphics)
 
592
 
 
593
    # Hypervisor name (qemu, xen, kvm, etc.)
 
594
    # Deprecated: should be pulled directly from the installer
 
595
    def get_type(self):
 
596
        return self._installer.type
 
597
    def set_type(self, val):
 
598
        self._installer.type = val
 
599
    type = property(get_type, set_type)
 
600
 
 
601
    # Deprecated: should be pulled directly from the installer
 
602
    def get_arch(self):
 
603
        return self.installer.arch
 
604
    def set_arch(self, val):
 
605
        self.installer.arch = val
 
606
    arch = property(get_arch, set_arch)
 
607
 
 
608
    # Deprecated: Should be called from the installer directly
 
609
    def get_location(self):
 
610
        return self._installer.location
 
611
    def set_location(self, val):
 
612
        self._installer.location = val
 
613
    location = property(get_location, set_location)
 
614
 
 
615
    # Deprecated: Should be called from the installer directly
 
616
    def get_scratchdir(self):
 
617
        return self._installer.scratchdir
 
618
    scratchdir = property(get_scratchdir)
 
619
 
 
620
    # Deprecated: Should be called from the installer directly
 
621
    def get_boot(self):
 
622
        return self._installer.boot
 
623
    def set_boot(self, val):
 
624
        self._installer.boot = val
 
625
    boot = property(get_boot, set_boot)
 
626
 
 
627
    # Deprecated: Should be called from the installer directly
 
628
    def get_extraargs(self):
 
629
        return self._installer.extraargs
 
630
    def set_extraargs(self, val):
 
631
        self._installer.extraargs = val
 
632
    extraargs = property(get_extraargs, set_extraargs)
 
633
 
 
634
    # Deprecated: Should set the installer values directly
 
635
    def get_cdrom(self):
 
636
        return self._installer.location
 
637
    def set_cdrom(self, val):
 
638
        self._installer.location = val
 
639
        self._installer.cdrom = True
 
640
    cdrom = property(get_cdrom, set_cdrom)
 
641
 
 
642
 
 
643
    ########################################
 
644
    # Device Add/Remove Public API methods #
 
645
    ########################################
 
646
 
 
647
    def _dev_build_list(self, devtype, devlist=None):
 
648
        if not devlist:
 
649
            devlist = self._devices
 
650
 
 
651
        newlist = []
 
652
        for i in devlist:
 
653
            if i.virtual_device_type == devtype:
 
654
                newlist.append(i)
 
655
        return newlist
 
656
 
 
657
    def add_device(self, dev):
 
658
        """
 
659
        Add the passed device to the guest's device list.
 
660
 
 
661
        @param dev: VirtualDevice instance to attach to guest
 
662
        """
 
663
        if not isinstance(dev, VirtualDevice):
 
664
            raise ValueError(_("Must pass a VirtualDevice instance."))
 
665
 
 
666
        if self._is_parse():
 
667
            xml = dev.get_xml_config()
 
668
            node = libxml2.parseDoc(xml).children
 
669
            dev.set_xml_node(node)
 
670
            self._add_child_node("./devices", node)
 
671
 
 
672
        return self._add_device(dev)
 
673
 
 
674
    def _add_device(self, dev):
 
675
        devtype = dev.virtual_device_type
 
676
 
 
677
        # If user adds a device conflicting with a default assigned device
 
678
        # remove the default
 
679
        if (dev.virtual_device_type == VirtualDevice.VIRTUAL_DEV_INPUT and
 
680
            self._default_input_device):
 
681
            if self._default_input_device in self.get_all_devices():
 
682
                self.remove_device(self._default_input_device)
 
683
            self._default_input_device = None
 
684
 
 
685
        if (dev.virtual_device_type in [VirtualDevice.VIRTUAL_DEV_CONSOLE,
 
686
                                        VirtualDevice.VIRTUAL_DEV_SERIAL] and
 
687
            self._default_console_device):
 
688
            if self._default_console_device in self.get_all_devices():
 
689
                self.remove_device(self._default_console_device)
 
690
            self._default_console_device = None
 
691
 
 
692
        # Actually add the device
 
693
        if   devtype == VirtualDevice.VIRTUAL_DEV_DISK:
 
694
            self.disks.append(dev)
 
695
        elif devtype == VirtualDevice.VIRTUAL_DEV_NET:
 
696
            self.nics.append(dev)
 
697
        elif devtype == VirtualDevice.VIRTUAL_DEV_AUDIO:
 
698
            self.sound_devs.append(dev)
 
699
        elif devtype == VirtualDevice.VIRTUAL_DEV_HOSTDEV:
 
700
            self.hostdevs.append(dev)
 
701
        else:
 
702
            self._devices.append(dev)
 
703
 
 
704
 
 
705
    def get_devices(self, devtype):
 
706
        """
 
707
        Return a list of devices of type 'devtype' that will installed on
 
708
        the guest.
 
709
 
 
710
        @param devtype: Device type to search for (one of
 
711
                        VirtualDevice.virtual_device_types)
 
712
        """
 
713
        if   devtype == VirtualDevice.VIRTUAL_DEV_DISK:
 
714
            devlist = self.disks[:]
 
715
        elif devtype == VirtualDevice.VIRTUAL_DEV_NET:
 
716
            devlist = self.nics[:]
 
717
        elif devtype == VirtualDevice.VIRTUAL_DEV_AUDIO:
 
718
            devlist = self.sound_devs[:]
 
719
        elif devtype == VirtualDevice.VIRTUAL_DEV_HOSTDEV:
 
720
            devlist = self.hostdevs[:]
 
721
        else:
 
722
            devlist = self._dev_build_list(devtype)
 
723
 
 
724
        devlist.extend(self._install_devices)
 
725
        return self._dev_build_list(devtype, devlist)
 
726
 
 
727
    def get_all_devices(self):
 
728
        """
 
729
        Return a list of all devices being installed with the guest
 
730
        """
 
731
        retlist = []
 
732
        for devtype in VirtualDevice.virtual_device_types:
 
733
            retlist.extend(self.get_devices(devtype))
 
734
        return retlist
 
735
 
 
736
    def remove_device(self, dev):
 
737
        """
 
738
        Remove the passed device from the guest's device list
 
739
 
 
740
        @param dev: VirtualDevice instance
 
741
        """
 
742
        found = False
 
743
        for devlist in [self.disks, self.nics, self.sound_devs, self.hostdevs,
 
744
                        self._devices, self._install_devices]:
 
745
            if found:
 
746
                break
 
747
 
 
748
            if dev in devlist:
 
749
                devlist.remove(dev)
 
750
                found = True
 
751
                break
 
752
 
 
753
        if not found:
 
754
            raise ValueError(_("Did not find device %s") % str(dev))
 
755
 
 
756
        if self._is_parse():
 
757
            xpath = dev.get_xml_node_path()
 
758
            if xpath:
 
759
                self._remove_child_xpath(xpath)
 
760
 
 
761
 
 
762
    ################################
 
763
    # Private xml building methods #
 
764
    ################################
 
765
 
 
766
    def _parsexml(self, xml, node):
 
767
        XMLBuilderDomain.XMLBuilderDomain._parsexml(self, xml, node)
 
768
 
 
769
        device_mappings = {
 
770
            "disk"      : virtinst.VirtualDisk,
 
771
            "interface" : virtinst.VirtualNetworkInterface,
 
772
            "sound"     : virtinst.VirtualAudio,
 
773
            "hostdev"   : virtinst.VirtualHostDevice,
 
774
            "input"     : virtinst.VirtualInputDevice,
 
775
            "serial"    : virtinst.VirtualCharDevice,
 
776
            "parallel"  : virtinst.VirtualCharDevice,
 
777
            "console"   : virtinst.VirtualCharDevice,
 
778
            "channel"   : virtinst.VirtualCharDevice,
 
779
            "graphics"  : virtinst.VirtualGraphics,
 
780
            "video"     : virtinst.VirtualVideoDevice,
 
781
            "watchdog"  : virtinst.VirtualWatchdog,
 
782
            "controller": virtinst.VirtualController,
 
783
            "filesystem": virtinst.VirtualFilesystem,
 
784
            "smartcard" : virtinst.VirtualSmartCardDevice,
 
785
            "redirdev"   : virtinst.VirtualRedirDevice,
 
786
        }
 
787
 
 
788
        # Hand off all child element parsing to relevant classes
 
789
        caps = self._get_caps()
 
790
        for node in self._xml_node.children:
 
791
            if node.name != "devices":
 
792
                continue
 
793
 
 
794
            children = filter(lambda x: (x.name in device_mappings and
 
795
                                         x.parent == node),
 
796
                              node.children)
 
797
            for devnode in children:
 
798
                objclass = device_mappings.get(devnode.name)
 
799
 
 
800
                if objclass == virtinst.VirtualCharDevice:
 
801
                    dev = objclass(self.conn, devnode.name,
 
802
                                   parsexmlnode=devnode, caps=caps)
 
803
                else:
 
804
                    dev = objclass(conn=self.conn,
 
805
                                   parsexmlnode=devnode, caps=caps)
 
806
                self._add_device(dev)
 
807
 
 
808
        self._installer = virtinst.Installer.Installer(self.conn,
 
809
                                                   parsexmlnode=self._xml_node,
 
810
                                                   caps=caps)
 
811
        self._features = DomainFeatures(self.conn,
 
812
                                        parsexmlnode=self._xml_node,
 
813
                                        caps=caps)
 
814
        self._clock = Clock(self.conn, parsexmlnode=self._xml_node, caps=caps)
 
815
        self._seclabel = Seclabel(self.conn, parsexmlnode=self._xml_node,
 
816
                                  caps=caps)
 
817
        self._cpu = CPU(self.conn, parsexmlnode=self._xml_node, caps=caps)
 
818
        self._numatune = DomainNumatune(self.conn,
 
819
                                        parsexmlnode=self._xml_node, caps=caps)
 
820
 
 
821
    def _get_default_input_device(self):
 
822
        """
 
823
        Return a VirtualInputDevice.
 
824
        """
 
825
        if self.installer and self.installer.is_container():
 
826
            return None
 
827
        dev = VirtualInputDevice(self.conn)
 
828
        return dev
 
829
 
 
830
    def _get_default_console_device(self):
 
831
        """
 
832
        Only implemented for FullVirtGuest
 
833
        """
 
834
        dev = VirtualCharDevice.get_dev_instance(self.conn,
 
835
                                                 VirtualCharDevice.DEV_CONSOLE,
 
836
                                                 VirtualCharDevice.CHAR_PTY)
 
837
        return dev
 
838
 
 
839
    def _get_device_xml(self, devs, install=True):
 
840
 
 
841
        def do_remove_media(d):
 
842
            # Keep cdrom around, but with no media attached,
 
843
            # But only if we are a distro that doesn't have a multi
 
844
            # stage install (aka not Windows)
 
845
            return (d.virtual_device_type == VirtualDevice.VIRTUAL_DEV_DISK and
 
846
                    d.device == VirtualDisk.DEVICE_CDROM
 
847
                    and d.transient
 
848
                    and not install and
 
849
                    not self.get_continue_inst())
 
850
 
 
851
        def do_skip_disk(d):
 
852
            # Skip transient labeled non-media disks
 
853
            return (d.virtual_device_type == VirtualDevice.VIRTUAL_DEV_DISK and
 
854
                    d.device == VirtualDisk.DEVICE_DISK
 
855
                    and d.transient
 
856
                    and not install)
 
857
 
 
858
        # Wrapper for building disk XML, handling transient CDROMs
 
859
        def get_dev_xml(dev):
 
860
            origpath = None
 
861
            try:
 
862
                if do_skip_disk(dev):
 
863
                    return ""
 
864
 
 
865
                if do_remove_media(dev):
 
866
                    origpath = dev.path
 
867
                    dev.path = None
 
868
 
 
869
                return dev.get_xml_config()
 
870
            finally:
 
871
                if origpath:
 
872
                    dev.path = origpath
 
873
 
 
874
        xml = self._get_emulator_xml()
 
875
        # Build XML
 
876
        for dev in devs:
 
877
            xml = _util.xml_append(xml, get_dev_xml(dev))
 
878
 
 
879
        return xml
 
880
 
 
881
    def _get_emulator_xml(self):
 
882
        emulator = self.emulator
 
883
        if self.installer.is_xenpv():
 
884
            return ""
 
885
 
 
886
        if (not self.emulator and
 
887
            self.installer.is_hvm() and
 
888
            self.type == "xen"):
 
889
            if self._get_caps().host.arch in ("x86_64"):
 
890
                emulator = "/usr/lib64/xen/bin/qemu-dm"
 
891
            else:
 
892
                emulator = "/usr/lib/xen/bin/qemu-dm"
 
893
 
 
894
        emu_xml = ""
 
895
        if emulator is not None:
 
896
            emu_xml = "    <emulator>%s</emulator>" % emulator
 
897
 
 
898
        return emu_xml
 
899
 
 
900
    def _get_features_xml(self, features):
 
901
        """
 
902
        Return features (pae, acpi, apic) xml
 
903
        """
 
904
        if self.installer and self.installer.is_container():
 
905
            return ""
 
906
        return features.get_xml_config()
 
907
 
 
908
    def _get_cpu_xml(self):
 
909
        """
 
910
        Return <cpu> XML
 
911
        """
 
912
        self.cpu.set_topology_defaults(self.vcpus)
 
913
        return self.cpu.get_xml_config()
 
914
 
 
915
    def _get_clock_xml(self):
 
916
        """
 
917
        Return <clock/> xml
 
918
        """
 
919
        return self.clock.get_xml_config()
 
920
 
 
921
    def _get_seclabel_xml(self):
 
922
        """
 
923
        Return <seclabel> XML
 
924
        """
 
925
        xml = ""
 
926
        if self.seclabel:
 
927
            xml = self.seclabel.get_xml_config()
 
928
 
 
929
        return xml
 
930
 
 
931
    def _get_osblob(self, install):
 
932
        """
 
933
        Return os, features, and clock xml (Implemented in subclass)
 
934
        """
 
935
        xml = ""
 
936
 
 
937
        osxml = self.installer.get_xml_config(self, install)
 
938
        if not osxml:
 
939
            return None
 
940
 
 
941
        xml = _util.xml_append(xml,
 
942
                               self.installer.get_xml_config(self, install))
 
943
        return xml
 
944
 
 
945
    def _get_vcpu_xml(self):
 
946
        curvcpus_supported = virtinst.support.check_conn_support(
 
947
                                    self.conn,
 
948
                                    virtinst.support.SUPPORT_CONN_MAXVCPUS_XML)
 
949
        cpuset = ""
 
950
        if self.cpuset is not None:
 
951
            cpuset = " cpuset='%s'" % self.cpuset
 
952
 
 
953
        maxv = self.maxvcpus
 
954
        curv = self.vcpus
 
955
 
 
956
        curxml = ""
 
957
        if maxv != curv and curvcpus_supported:
 
958
            curxml = " current='%s'" % curv
 
959
        else:
 
960
            maxv = curv
 
961
 
 
962
        return "  <vcpu%s%s>%s</vcpu>" % (cpuset, curxml, maxv)
 
963
 
 
964
    ############################
 
965
    # Install Helper functions #
 
966
    ############################
 
967
 
 
968
    def _prepare_install(self, meter, dry=False):
 
969
        self._install_devices = []
 
970
        ignore = dry
 
971
 
 
972
        # Fetch install media, prepare installer devices
 
973
        self._installer.prepare(guest=self,
 
974
                                meter=meter)
 
975
 
 
976
        # Initialize install device list
 
977
        for dev in self._installer.install_devices:
 
978
            self._install_devices.append(dev)
 
979
 
 
980
    def _cleanup_install(self):
 
981
        self._installer.cleanup()
 
982
 
 
983
    def _create_devices(self, progresscb):
 
984
        """
 
985
        Ensure that devices are setup
 
986
        """
 
987
        for dev in self.get_all_devices():
 
988
            dev.setup_dev(self.conn, progresscb)
 
989
 
 
990
    ##############
 
991
    # Public API #
 
992
    ##############
 
993
 
 
994
    def _get_xml_config(self, install=True, disk_boot=False):
 
995
        """
 
996
        Return the full Guest xml configuration.
 
997
 
 
998
        @param install: Whether we want the 'OS install' configuration or
 
999
                        the 'post-install' configuration. (Some Installers,
 
1000
                        like the LiveCDInstaller may not have an 'install'
 
1001
                        config.)
 
1002
        @type install: C{bool}
 
1003
        @param disk_boot: Whether we should boot off the harddisk, regardless
 
1004
                          of our position in the install process (this is
 
1005
                          used for 2 stage installs, where the second stage
 
1006
                          boots off the disk. You probably don't need to touch
 
1007
                          this.)
 
1008
        @type disk_boot: C{bool}
 
1009
        """
 
1010
        # We do a shallow copy of the device list here, and set the defaults.
 
1011
        # This way, default changes aren't persistent, and we don't need
 
1012
        # to worry about when to call set_defaults
 
1013
        origdevs = self.get_all_devices()
 
1014
        devs = []
 
1015
        for dev in origdevs:
 
1016
            devs.append(dev.copy())
 
1017
        tmpfeat = self.features.copy()
 
1018
 
 
1019
        def get_transient_devices(devtype):
 
1020
            return self._dev_build_list(devtype, devs)
 
1021
        def remove_transient_device(device):
 
1022
            devs.remove(device)
 
1023
 
 
1024
        # Set device defaults so we can validly generate XML
 
1025
        self._set_defaults(get_transient_devices,
 
1026
                           remove_transient_device,
 
1027
                           tmpfeat)
 
1028
 
 
1029
        if install:
 
1030
            action = "destroy"
 
1031
        else:
 
1032
            action = "restart"
 
1033
 
 
1034
        osblob_install = install
 
1035
        if disk_boot:
 
1036
            osblob_install = False
 
1037
 
 
1038
        osblob = self._get_osblob(osblob_install)
 
1039
        if osblob_install and not self.installer.has_install_phase():
 
1040
            return None
 
1041
 
 
1042
        desc_xml = ""
 
1043
        if self.description is not None:
 
1044
            desc = str(self.description)
 
1045
            desc_xml = ("  <description>%s</description>" %
 
1046
                        _util.xml_escape(desc))
 
1047
 
 
1048
        xml = ""
 
1049
        add = lambda x: _util.xml_append(xml, x)
 
1050
 
 
1051
        xml = add("<domain type='%s'>" % self.type)
 
1052
        xml = add("  <name>%s</name>" % self.name)
 
1053
        xml = add("  <uuid>%s</uuid>" % self.uuid)
 
1054
        xml = add(desc_xml)
 
1055
        xml = add("  <memory>%s</memory>" % (self.maxmemory * 1024))
 
1056
        xml = add("  <currentMemory>%s</currentMemory>" % (self.memory * 1024))
 
1057
 
 
1058
        # <blkiotune>
 
1059
        # <memtune>
 
1060
        if self.hugepage is True:
 
1061
            xml = add("  <memoryBacking>")
 
1062
            xml = add("    <hugepages/>")
 
1063
            xml = add("  </memoryBacking>")
 
1064
 
 
1065
        xml = add(self._get_vcpu_xml())
 
1066
        # <cputune>
 
1067
        xml = add(self.numatune.get_xml_config())
 
1068
        # <sysinfo>
 
1069
        # XXX: <bootloader> goes here, not in installer XML
 
1070
        xml = add("  %s" % osblob)
 
1071
        xml = add(self._get_features_xml(tmpfeat))
 
1072
        xml = add(self._get_cpu_xml())
 
1073
        xml = add(self._get_clock_xml())
 
1074
        xml = add("  <on_poweroff>destroy</on_poweroff>")
 
1075
        xml = add("  <on_reboot>%s</on_reboot>" % action)
 
1076
        xml = add("  <on_crash>%s</on_crash>" % action)
 
1077
        xml = add("  <devices>")
 
1078
        xml = add(self._get_device_xml(devs, install))
 
1079
        xml = add("  </devices>")
 
1080
        xml = add(self._get_seclabel_xml())
 
1081
        xml = add("</domain>\n")
 
1082
 
 
1083
        return xml
 
1084
 
 
1085
    def post_install_check(self):
 
1086
        """
 
1087
        Back compat mapping to installer post_install_check
 
1088
        """
 
1089
        return self.installer.post_install_check(self)
 
1090
 
 
1091
    def get_continue_inst(self):
 
1092
        """
 
1093
        Return True if this guest requires a call to 'continue_install',
 
1094
        which means the OS requires a 2 stage install (windows)
 
1095
        """
 
1096
        # If we are doing an 'import' or 'liveCD' install, there is
 
1097
        # no true install process, so continue install has no meaning
 
1098
        if not self.installer.has_install_phase():
 
1099
            return False
 
1100
 
 
1101
        return self._lookup_osdict_key("continue")
 
1102
 
 
1103
    def validate_parms(self):
 
1104
        """
 
1105
        Do some pre-install domain validation
 
1106
        """
 
1107
        if self.domain is not None:
 
1108
            raise RuntimeError(_("Domain has already been started!"))
 
1109
 
 
1110
        if self.name is None or self.memory is None:
 
1111
            raise RuntimeError(_("Name and memory must be specified for "
 
1112
                                 "all guests!"))
 
1113
 
 
1114
        if _util.vm_uuid_collision(self.conn, self.uuid):
 
1115
            raise RuntimeError(_("The UUID you entered is already in "
 
1116
                                 "use by another guest!"))
 
1117
 
 
1118
    def connect_console(self, consolecb, wait=True):
 
1119
        """
 
1120
        Launched the passed console callback for the already defined
 
1121
        domain. If domain isn't running, return an error.
 
1122
        """
 
1123
        (self.domain,
 
1124
         self._consolechild) = self._wait_and_connect_console(consolecb)
 
1125
 
 
1126
        # If we connected the console, wait for it to finish
 
1127
        self._waitpid_console(self._consolechild, wait)
 
1128
 
 
1129
    def terminate_console(self):
 
1130
        """
 
1131
        Kill guest console if it is open (and actually exists), otherwise
 
1132
        do nothing
 
1133
        """
 
1134
        if self._consolechild:
 
1135
            try:
 
1136
                os.kill(self._consolechild, signal.SIGKILL)
 
1137
            except:
 
1138
                pass
 
1139
 
 
1140
    def domain_is_shutdown(self):
 
1141
        """
 
1142
        Return True if the created domain object is shutdown
 
1143
        """
 
1144
        dom = self.domain
 
1145
        if not dom:
 
1146
            return False
 
1147
 
 
1148
        dominfo = dom.info()
 
1149
 
 
1150
        state    = dominfo[0]
 
1151
        cpu_time = dominfo[4]
 
1152
 
 
1153
        if state == libvirt.VIR_DOMAIN_SHUTOFF:
 
1154
            return True
 
1155
 
 
1156
        # If 'wait' was specified, the dom object we have was looked up
 
1157
        # before initially shutting down, which seems to bogus up the
 
1158
        # info data (all 0's). So, if it is bogus, assume the domain is
 
1159
        # shutdown. We will catch the error later.
 
1160
        return state == libvirt.VIR_DOMAIN_NOSTATE and cpu_time == 0
 
1161
 
 
1162
    def domain_is_crashed(self):
 
1163
        """
 
1164
        Return True if the created domain object is in a crashed state
 
1165
        """
 
1166
        if not self.domain:
 
1167
            return False
 
1168
 
 
1169
        dominfo = self.domain.info()
 
1170
        state = dominfo[0]
 
1171
 
 
1172
        return state == libvirt.VIR_DOMAIN_CRASHED
 
1173
 
 
1174
    ##########################
 
1175
    # Actual install methods #
 
1176
    ##########################
 
1177
 
 
1178
    def remove_original_vm(self, force=None):
 
1179
        """
 
1180
        Remove the existing VM with the same name if requested, or error
 
1181
        if there is a collision.
 
1182
        """
 
1183
        if force == None:
 
1184
            force = self.replace
 
1185
 
 
1186
        vm = None
 
1187
        try:
 
1188
            vm = self.conn.lookupByName(self.name)
 
1189
        except libvirt.libvirtError:
 
1190
            pass
 
1191
 
 
1192
        if vm is None:
 
1193
            return
 
1194
 
 
1195
        if not force:
 
1196
            raise RuntimeError(_("Domain named %s already exists!") %
 
1197
                               self.name)
 
1198
 
 
1199
        try:
 
1200
            logging.debug("Explicitly replacing guest '%s'", self.name)
 
1201
            if vm.ID() != -1:
 
1202
                logging.info("Destroying guest '%s'", self.name)
 
1203
                vm.destroy()
 
1204
 
 
1205
            logging.info("Undefining guest '%s'", self.name)
 
1206
            vm.undefine()
 
1207
        except libvirt.libvirtError, e:
 
1208
            raise RuntimeError(_("Could not remove old vm '%s': %s") %
 
1209
                               (self.name, str(e)))
 
1210
 
 
1211
    def start_install(self, consolecb=None, meter=None, removeOld=None,
 
1212
                      wait=True, dry=False, return_xml=False, noboot=False):
 
1213
        """
 
1214
        Begin the guest install (stage1).
 
1215
        @param return_xml: Don't create the guest, just return generated XML
 
1216
        """
 
1217
        is_initial = True
 
1218
 
 
1219
        self.validate_parms()
 
1220
        self._consolechild = None
 
1221
 
 
1222
        self._prepare_install(meter, dry)
 
1223
        try:
 
1224
            # Create devices if required (disk images, etc.)
 
1225
            if not dry:
 
1226
                self._create_devices(meter)
 
1227
 
 
1228
            start_xml, final_xml = self._build_xml(is_initial)
 
1229
            if return_xml:
 
1230
                return (start_xml, final_xml)
 
1231
            if dry:
 
1232
                return
 
1233
 
 
1234
            # Remove existing VM if requested
 
1235
            self.remove_original_vm(removeOld)
 
1236
 
 
1237
            self.domain = self._create_guest(consolecb, meter, wait,
 
1238
                                             start_xml, final_xml, is_initial,
 
1239
                                             noboot)
 
1240
 
 
1241
            # Set domain autostart flag if requested
 
1242
            self._flag_autostart()
 
1243
 
 
1244
            return self.domain
 
1245
        finally:
 
1246
            self._cleanup_install()
 
1247
 
 
1248
    def continue_install(self, consolecb=None, meter=None, wait=True,
 
1249
                         dry=False, return_xml=False):
 
1250
        """
 
1251
        Continue with stage 2 of a guest install. Only required for
 
1252
        guests which have the 'continue' flag set (accessed via
 
1253
        get_continue_inst)
 
1254
        """
 
1255
        is_initial = False
 
1256
        start_xml, final_xml = self._build_xml(is_initial)
 
1257
        if return_xml:
 
1258
            return (start_xml, final_xml)
 
1259
        if dry:
 
1260
            return
 
1261
 
 
1262
        return self._create_guest(consolecb, meter, wait,
 
1263
                                  start_xml, final_xml, is_initial, False)
 
1264
 
 
1265
    def _build_meter(self, meter, is_initial):
 
1266
        if is_initial:
 
1267
            meter_label = _("Creating domain...")
 
1268
        else:
 
1269
            meter_label = _("Starting domain...")
 
1270
 
 
1271
        if meter == None:
 
1272
            meter = progress.BaseMeter()
 
1273
        meter.start(size=None, text=meter_label)
 
1274
 
 
1275
        return meter
 
1276
 
 
1277
    def _build_xml(self, is_initial):
 
1278
        log_label = is_initial and "install" or "continue"
 
1279
        disk_boot = not is_initial
 
1280
 
 
1281
        start_xml = self.get_xml_config(install=True, disk_boot=disk_boot)
 
1282
        final_xml = self.get_xml_config(install=False)
 
1283
 
 
1284
        logging.debug("Generated %s XML: %s",
 
1285
                      log_label,
 
1286
                      (start_xml and ("\n" + start_xml) or "None required"))
 
1287
        logging.debug("Generated boot XML: \n%s", final_xml)
 
1288
 
 
1289
        return start_xml, final_xml
 
1290
 
 
1291
    def _create_guest(self, consolecb, meter, wait,
 
1292
                      start_xml, final_xml, is_initial, noboot):
 
1293
        """
 
1294
        Actually do the XML logging, guest defining/creating, console
 
1295
        launching and waiting
 
1296
 
 
1297
        @param is_initial: If running initial guest creation, else we
 
1298
                           are continuing the install
 
1299
        @param noboot: Don't boot guest if no install phase
 
1300
        """
 
1301
        meter = self._build_meter(meter, is_initial)
 
1302
        doboot = not noboot or self.installer.has_install_phase()
 
1303
        if not doboot:
 
1304
            consolecb = None
 
1305
 
 
1306
        if is_initial and doboot:
 
1307
            dom = self.conn.createLinux(start_xml or final_xml, 0)
 
1308
        else:
 
1309
            dom = self.conn.defineXML(start_xml or final_xml)
 
1310
            if doboot:
 
1311
                dom.create()
 
1312
 
 
1313
        self.domain = dom
 
1314
        meter.end(0)
 
1315
 
 
1316
        if doboot:
 
1317
            logging.debug("Started guest, connecting to console if requested")
 
1318
            (self.domain,
 
1319
             self._consolechild) = self._wait_and_connect_console(consolecb)
 
1320
 
 
1321
        self.domain = self.conn.defineXML(final_xml)
 
1322
        if is_initial:
 
1323
            try:
 
1324
                logging.debug("XML fetched from libvirt object:\n%s",
 
1325
                              dom.XMLDesc(0))
 
1326
            except Exception, e:
 
1327
                logging.debug("Error fetching XML from libvirt object: %s", e)
 
1328
 
 
1329
        # if we connected the console, wait for it to finish
 
1330
        self._waitpid_console(self._consolechild, wait)
 
1331
 
 
1332
        return self.conn.lookupByName(self.name)
 
1333
 
 
1334
 
 
1335
    def _wait_and_connect_console(self, consolecb):
 
1336
        """
 
1337
        Wait for domain to appear and be running, then connect to
 
1338
        the console if necessary
 
1339
        """
 
1340
        child = None
 
1341
        dom = _wait_for_domain(self.conn, self.name)
 
1342
 
 
1343
        if dom is None:
 
1344
            raise RuntimeError(_("Domain has not existed.  You should be "
 
1345
                                 "able to find more information in the logs"))
 
1346
        elif dom.ID() == -1:
 
1347
            raise RuntimeError(_("Domain has not run yet.  You should be "
 
1348
                                 "able to find more information in the logs"))
 
1349
 
 
1350
        if consolecb:
 
1351
            child = consolecb(dom)
 
1352
 
 
1353
        return dom, child
 
1354
 
 
1355
    def _waitpid_console(self, console_child, do_wait):
 
1356
        """
 
1357
        Wait for console to close if it was launched
 
1358
        """
 
1359
        if not console_child or not do_wait:
 
1360
            return
 
1361
 
 
1362
        try:
 
1363
            os.waitpid(console_child, 0)
 
1364
        except OSError, (err_no, msg):
 
1365
            logging.debug("waitpid: %s: %s", err_no, msg)
 
1366
 
 
1367
        # ensure there's time for the domain to finish destroying if the
 
1368
        # install has finished or the guest crashed
 
1369
        time.sleep(1)
 
1370
 
 
1371
    def _flag_autostart(self):
 
1372
        """
 
1373
        Set the autostart flag for self.domain if the user requested it
 
1374
        """
 
1375
        if not self.autostart:
 
1376
            return
 
1377
 
 
1378
        try:
 
1379
            self.domain.setAutostart(True)
 
1380
        except libvirt.libvirtError, e:
 
1381
            if support.is_error_nosupport(e):
 
1382
                logging.warn("Could not set autostart flag: libvirt "
 
1383
                             "connection does not support autostart.")
 
1384
            else:
 
1385
                raise e
 
1386
 
 
1387
 
 
1388
    ###################
 
1389
    # Device defaults #
 
1390
    ###################
 
1391
 
 
1392
    def set_defaults(self):
 
1393
        """
 
1394
        Public function to set guest defaults. Things like preferred
 
1395
        disk bus (unless one is specified). These changes are persistent.
 
1396
        The install process will call a non-persistent version, so calling
 
1397
        this manually isn't required.
 
1398
        """
 
1399
        self._set_defaults(self.get_devices, self.remove_device,
 
1400
                           self.features)
 
1401
 
 
1402
    def _set_hvm_defaults(self, devlist_func, features):
 
1403
        disktype = VirtualDevice.VIRTUAL_DEV_DISK
 
1404
        nettype = VirtualDevice.VIRTUAL_DEV_NET
 
1405
        disk_bus  = self._lookup_device_param(disktype, "bus")
 
1406
        net_model = self._lookup_device_param(nettype, "model")
 
1407
 
 
1408
        # Only overwrite params if they weren't already specified
 
1409
        for net in devlist_func(nettype):
 
1410
            if net_model and not net.model:
 
1411
                net.model = net_model
 
1412
 
 
1413
        for disk in devlist_func(disktype):
 
1414
            if (disk_bus and not disk.bus and
 
1415
                disk.device == VirtualDisk.DEVICE_DISK):
 
1416
                disk.bus = disk_bus
 
1417
 
 
1418
        if self.clock.offset == None:
 
1419
            self.clock.offset = self._lookup_osdict_key("clock")
 
1420
 
 
1421
        if features["acpi"] is None:
 
1422
            features["acpi"] = self._lookup_osdict_key("acpi")
 
1423
        if features["apic"] is None:
 
1424
            features["apic"] = self._lookup_osdict_key("apic")
 
1425
        if features["pae"] is None and self._get_caps():
 
1426
            features["pae"] = self._get_caps().support_pae()
 
1427
 
 
1428
 
 
1429
    def _set_pv_defaults(self, devlist_func, remove_func):
 
1430
        # Default file backed PV guests to tap driver
 
1431
        for d in devlist_func(VirtualDevice.VIRTUAL_DEV_DISK):
 
1432
            if (d.type == VirtualDisk.TYPE_FILE
 
1433
                and _util.is_blktap_capable()
 
1434
                and d.driver_name == None):
 
1435
                d.driver_name = VirtualDisk.DRIVER_TAP
 
1436
 
 
1437
        for d in devlist_func(VirtualDevice.VIRTUAL_DEV_INPUT):
 
1438
            if d.type == d.INPUT_TYPE_DEFAULT:
 
1439
                d.type = d.INPUT_TYPE_MOUSE
 
1440
            if d.bus == d.INPUT_BUS_DEFAULT:
 
1441
                d.bus = d.INPUT_BUS_XEN
 
1442
 
 
1443
        for d in devlist_func(VirtualDevice.VIRTUAL_DEV_CONSOLE):
 
1444
            if hasattr(d, "virtinst_default"):
 
1445
                remove_func(d)
 
1446
 
 
1447
    def add_usb_ich9_controllers(self):
 
1448
        ctrl = VirtualControllerUSB(self.conn,
 
1449
                                    model="ich9-ehci1")
 
1450
        self.add_device(ctrl)
 
1451
 
 
1452
        ctrl = VirtualControllerUSB(self.conn,
 
1453
                                    model="ich9-uhci1")
 
1454
        ctrl.get_master().startport = 0
 
1455
        self.add_device(ctrl)
 
1456
 
 
1457
        ctrl = VirtualControllerUSB(self.conn,
 
1458
                                    model="ich9-uhci2")
 
1459
        ctrl.get_master().startport = 2
 
1460
        self.add_device(ctrl)
 
1461
 
 
1462
        ctrl = VirtualControllerUSB(self.conn,
 
1463
                                    model="ich9-uhci3")
 
1464
        ctrl.get_master().startport = 4
 
1465
        self.add_device(ctrl)
 
1466
 
 
1467
    def _set_defaults(self, devlist_func, remove_func, features):
 
1468
        if self.installer.is_hvm():
 
1469
            self._set_hvm_defaults(devlist_func, features)
 
1470
        if self.installer.is_xenpv():
 
1471
            self._set_pv_defaults(devlist_func, remove_func)
 
1472
 
 
1473
        soundtype = VirtualDevice.VIRTUAL_DEV_AUDIO
 
1474
        videotype = VirtualDevice.VIRTUAL_DEV_VIDEO
 
1475
        inputtype = VirtualDevice.VIRTUAL_DEV_INPUT
 
1476
        gfxtype = VirtualDevice.VIRTUAL_DEV_GRAPHICS
 
1477
        channeltype = VirtualDevice.VIRTUAL_DEV_CHANNEL
 
1478
 
 
1479
        # Set default input values
 
1480
        input_type = self._lookup_device_param(inputtype, "type")
 
1481
        input_bus = self._lookup_device_param(inputtype, "bus")
 
1482
        for inp in devlist_func(inputtype):
 
1483
            if (inp.type == inp.INPUT_TYPE_DEFAULT and
 
1484
                inp.bus  == inp.INPUT_BUS_DEFAULT):
 
1485
                inp.type = input_type
 
1486
                inp.bus  = input_bus
 
1487
 
 
1488
        # Generate disk targets, and set preferred disk bus
 
1489
        used_targets = []
 
1490
        for disk in devlist_func(VirtualDevice.VIRTUAL_DEV_DISK):
 
1491
            if not disk.bus:
 
1492
                if disk.device == disk.DEVICE_FLOPPY:
 
1493
                    disk.bus = "fdc"
 
1494
                else:
 
1495
                    if self.installer.is_hvm():
 
1496
                        disk.bus = "ide"
 
1497
                    elif self.installer.is_xenpv():
 
1498
                        disk.bus = "xen"
 
1499
            used_targets.append(disk.generate_target(used_targets))
 
1500
 
 
1501
        # Set sound device model
 
1502
        sound_model  = self._lookup_device_param(soundtype, "model")
 
1503
        for sound in devlist_func(soundtype):
 
1504
            if sound.model == sound.MODEL_DEFAULT:
 
1505
                sound.model = sound_model
 
1506
 
 
1507
        # Set video device model
 
1508
        # QXL device (only if we use spice) - safe even if guest is VGA only
 
1509
        def has_spice():
 
1510
            for gfx in devlist_func(gfxtype):
 
1511
                if gfx.type == gfx.TYPE_SPICE:
 
1512
                    return True
 
1513
        if has_spice():
 
1514
            video_model  = "qxl"
 
1515
        else:
 
1516
            video_model  = self._lookup_device_param(videotype, "model_type")
 
1517
 
 
1518
        for video in devlist_func(videotype):
 
1519
            if video.model_type == video.MODEL_DEFAULT:
 
1520
                video.model_type = video_model
 
1521
 
 
1522
        # Spice agent channel (only if we use spice)
 
1523
        def has_spice_agent():
 
1524
            for chn in devlist_func(channeltype):
 
1525
                if chn.char_type == chn.CHAR_SPICEVMC:
 
1526
                    return True
 
1527
 
 
1528
        if (has_spice() and
 
1529
            not has_spice_agent() and
 
1530
            support.check_conn_support(self.conn,
 
1531
                                       support.SUPPORT_CONN_HV_CHAR_SPICEVMC)):
 
1532
            agentdev = VirtualCharDevice.get_dev_instance(self.conn,
 
1533
                                            VirtualCharDevice.DEV_CHANNEL,
 
1534
                                            VirtualCharDevice.CHAR_SPICEVMC)
 
1535
            self.add_device(agentdev)
 
1536
 
 
1537
        # Generate UUID
 
1538
        if self.uuid is None:
 
1539
            found = False
 
1540
            for ignore in range(256):
 
1541
                self.uuid = _util.uuidToString(_util.randomUUID())
 
1542
                if _util.vm_uuid_collision(self.conn, self.uuid):
 
1543
                    continue
 
1544
                found = True
 
1545
                break
 
1546
 
 
1547
            if not found:
 
1548
                logging.debug("Failed to generate non-conflicting UUID")
 
1549
 
 
1550
 
 
1551
    ###################################
 
1552
    # Guest Dictionary Helper methods #
 
1553
    ###################################
 
1554
 
 
1555
    def _is_rhel6(self):
 
1556
        emulator = self.emulator or ""
 
1557
 
 
1558
        return (self.type in ["qemu", "kvm"] and
 
1559
                emulator.startswith("/usr/libexec/qemu"))
 
1560
 
 
1561
    def _lookup_osdict_key(self, key):
 
1562
        """
 
1563
        Using self.os_type and self.os_variant to find key in OSTYPES
 
1564
        @returns: dict value, or None if os_type/variant wasn't set
 
1565
        """
 
1566
        return osdict.lookup_osdict_key(self.conn, self.type,
 
1567
                                        self.os_type, self.os_variant,
 
1568
                                        key)
 
1569
 
 
1570
    def _lookup_device_param(self, device_key, param):
 
1571
        """
 
1572
        Check the OS dictionary for the prefered device setting for passed
 
1573
        device type and param (bus, model, etc.)
 
1574
        """
 
1575
        try:
 
1576
            support._set_rhel6(self._is_rhel6())
 
1577
            return osdict.lookup_device_param(self.conn, self.type,
 
1578
                                              self.os_type, self.os_variant,
 
1579
                                              device_key, param)
 
1580
        finally:
 
1581
            support._set_rhel6(False)
 
1582
 
 
1583
 
 
1584
def _wait_for_domain(conn, name):
 
1585
    # sleep in .25 second increments until either a) we get running
 
1586
    # domain ID or b) it's been 5 seconds.  this is so that
 
1587
    # we can try to gracefully handle domain restarting failures
 
1588
    dom = None
 
1589
    for ignore in range(1, int(5 / .25)): # 5 seconds, .25 second sleeps
 
1590
        try:
 
1591
            dom = conn.lookupByName(name)
 
1592
            if dom and dom.ID() != -1:
 
1593
                break
 
1594
        except libvirt.libvirtError, e:
 
1595
            logging.debug("No guest running yet: " + str(e))
 
1596
            dom = None
 
1597
        time.sleep(0.25)
 
1598
 
 
1599
    return dom
 
1600
 
 
1601
# Back compat class to avoid ABI break
 
1602
XenGuest = Guest
 
1603
Guest.get_config_xml = Guest.get_xml_config