Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 6b405598

History | View | Annotate | Download (29.3 kB)

1 eb58f9b1 Guido Trotter
#
2 eb58f9b1 Guido Trotter
#
3 eb58f9b1 Guido Trotter
4 eb58f9b1 Guido Trotter
# Copyright (C) 2008 Google Inc.
5 eb58f9b1 Guido Trotter
#
6 eb58f9b1 Guido Trotter
# This program is free software; you can redistribute it and/or modify
7 eb58f9b1 Guido Trotter
# it under the terms of the GNU General Public License as published by
8 eb58f9b1 Guido Trotter
# the Free Software Foundation; either version 2 of the License, or
9 eb58f9b1 Guido Trotter
# (at your option) any later version.
10 eb58f9b1 Guido Trotter
#
11 eb58f9b1 Guido Trotter
# This program is distributed in the hope that it will be useful, but
12 eb58f9b1 Guido Trotter
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 eb58f9b1 Guido Trotter
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 eb58f9b1 Guido Trotter
# General Public License for more details.
15 eb58f9b1 Guido Trotter
#
16 eb58f9b1 Guido Trotter
# You should have received a copy of the GNU General Public License
17 eb58f9b1 Guido Trotter
# along with this program; if not, write to the Free Software
18 eb58f9b1 Guido Trotter
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 eb58f9b1 Guido Trotter
# 02110-1301, USA.
20 eb58f9b1 Guido Trotter
21 eb58f9b1 Guido Trotter
22 eb58f9b1 Guido Trotter
"""KVM hypervisor
23 eb58f9b1 Guido Trotter

24 eb58f9b1 Guido Trotter
"""
25 eb58f9b1 Guido Trotter
26 eb58f9b1 Guido Trotter
import os
27 eb58f9b1 Guido Trotter
import os.path
28 eb58f9b1 Guido Trotter
import re
29 eb58f9b1 Guido Trotter
import tempfile
30 6567aff3 Guido Trotter
import time
31 30e42c4e Guido Trotter
import logging
32 eb58f9b1 Guido Trotter
from cStringIO import StringIO
33 eb58f9b1 Guido Trotter
34 eb58f9b1 Guido Trotter
from ganeti import utils
35 eb58f9b1 Guido Trotter
from ganeti import constants
36 eb58f9b1 Guido Trotter
from ganeti import errors
37 38e250ba Guido Trotter
from ganeti import serializer
38 38e250ba Guido Trotter
from ganeti import objects
39 eb58f9b1 Guido Trotter
from ganeti.hypervisor import hv_base
40 eb58f9b1 Guido Trotter
41 eb58f9b1 Guido Trotter
42 eb58f9b1 Guido Trotter
class KVMHypervisor(hv_base.BaseHypervisor):
43 c4469f75 Guido Trotter
  """KVM hypervisor interface"""
44 eb58f9b1 Guido Trotter
45 eb58f9b1 Guido Trotter
  _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
46 a1d79fc6 Guido Trotter
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
47 a1d79fc6 Guido Trotter
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
48 a1d79fc6 Guido Trotter
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
49 a1d79fc6 Guido Trotter
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _CTRL_DIR, _CONF_DIR]
50 eb58f9b1 Guido Trotter
51 6b5605e8 Iustin Pop
  PARAMETERS = [
52 6b5605e8 Iustin Pop
    constants.HV_KERNEL_PATH,
53 6b5605e8 Iustin Pop
    constants.HV_INITRD_PATH,
54 074ca009 Guido Trotter
    constants.HV_ROOT_PATH,
55 07813a9e Iustin Pop
    constants.HV_KERNEL_ARGS,
56 6b5605e8 Iustin Pop
    constants.HV_ACPI,
57 a2faf9ee Guido Trotter
    constants.HV_SERIAL_CONSOLE,
58 56fee73b Guido Trotter
    constants.HV_VNC_BIND_ADDRESS,
59 8b2d1013 Guido Trotter
    constants.HV_VNC_TLS,
60 8b2d1013 Guido Trotter
    constants.HV_VNC_X509,
61 8b2d1013 Guido Trotter
    constants.HV_VNC_X509_VERIFY,
62 66d5dbef Guido Trotter
    constants.HV_CDROM_IMAGE_PATH,
63 66d5dbef Guido Trotter
    constants.HV_BOOT_ORDER,
64 43440815 Guido Trotter
    constants.HV_NIC_TYPE,
65 43440815 Guido Trotter
    constants.HV_DISK_TYPE,
66 11344a50 Guido Trotter
    constants.HV_USB_MOUSE,
67 6b5605e8 Iustin Pop
    ]
68 6b5605e8 Iustin Pop
69 30e42c4e Guido Trotter
  _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
70 30e42c4e Guido Trotter
                                    re.M | re.I)
71 30e42c4e Guido Trotter
72 eb58f9b1 Guido Trotter
  def __init__(self):
73 eb58f9b1 Guido Trotter
    hv_base.BaseHypervisor.__init__(self)
74 eb58f9b1 Guido Trotter
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
75 eb58f9b1 Guido Trotter
    # in a tmpfs filesystem or has been otherwise wiped out.
76 9afb67fe Guido Trotter
    dirs = [(dir, constants.RUN_DIRS_MODE) for dir in self._DIRS]
77 9afb67fe Guido Trotter
    utils.EnsureDirs(dirs)
78 eb58f9b1 Guido Trotter
79 1f8b3a27 Guido Trotter
  def _InstancePidAlive(self, instance_name):
80 1f8b3a27 Guido Trotter
    """Returns the instance pid and pidfile
81 1f8b3a27 Guido Trotter

82 1f8b3a27 Guido Trotter
    """
83 1f8b3a27 Guido Trotter
    pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
84 1f8b3a27 Guido Trotter
    pid = utils.ReadPidFile(pidfile)
85 1f8b3a27 Guido Trotter
    alive = utils.IsProcessAlive(pid)
86 1f8b3a27 Guido Trotter
87 1f8b3a27 Guido Trotter
    return (pidfile, pid, alive)
88 1f8b3a27 Guido Trotter
89 0df4d98a Guido Trotter
  @classmethod
90 0df4d98a Guido Trotter
  def _InstanceMonitor(cls, instance_name):
91 c4fbefc8 Guido Trotter
    """Returns the instance monitor socket name
92 c4fbefc8 Guido Trotter

93 c4fbefc8 Guido Trotter
    """
94 0df4d98a Guido Trotter
    return '%s/%s.monitor' % (cls._CTRL_DIR, instance_name)
95 c4fbefc8 Guido Trotter
96 0df4d98a Guido Trotter
  @classmethod
97 0df4d98a Guido Trotter
  def _InstanceSerial(cls, instance_name):
98 c4fbefc8 Guido Trotter
    """Returns the instance serial socket name
99 c4fbefc8 Guido Trotter

100 c4fbefc8 Guido Trotter
    """
101 0df4d98a Guido Trotter
    return '%s/%s.serial' % (cls._CTRL_DIR, instance_name)
102 c4fbefc8 Guido Trotter
103 0df4d98a Guido Trotter
  @classmethod
104 0df4d98a Guido Trotter
  def _InstanceKVMRuntime(cls, instance_name):
105 38e250ba Guido Trotter
    """Returns the instance KVM runtime filename
106 38e250ba Guido Trotter

107 38e250ba Guido Trotter
    """
108 0df4d98a Guido Trotter
    return '%s/%s.runtime' % (cls._CONF_DIR, instance_name)
109 38e250ba Guido Trotter
110 eb58f9b1 Guido Trotter
  def _WriteNetScript(self, instance, seq, nic):
111 eb58f9b1 Guido Trotter
    """Write a script to connect a net interface to the proper bridge.
112 eb58f9b1 Guido Trotter

113 eb58f9b1 Guido Trotter
    This can be used by any qemu-type hypervisor.
114 eb58f9b1 Guido Trotter

115 eb58f9b1 Guido Trotter
    @param instance: instance we're acting on
116 eb58f9b1 Guido Trotter
    @type instance: instance object
117 eb58f9b1 Guido Trotter
    @param seq: nic sequence number
118 eb58f9b1 Guido Trotter
    @type seq: int
119 eb58f9b1 Guido Trotter
    @param nic: nic we're acting on
120 eb58f9b1 Guido Trotter
    @type nic: nic object
121 eb58f9b1 Guido Trotter
    @return: netscript file name
122 eb58f9b1 Guido Trotter
    @rtype: string
123 eb58f9b1 Guido Trotter

124 eb58f9b1 Guido Trotter
    """
125 eb58f9b1 Guido Trotter
    script = StringIO()
126 eb58f9b1 Guido Trotter
    script.write("#!/bin/sh\n")
127 eb58f9b1 Guido Trotter
    script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
128 eb58f9b1 Guido Trotter
    script.write("export INSTANCE=%s\n" % instance.name)
129 eb58f9b1 Guido Trotter
    script.write("export MAC=%s\n" % nic.mac)
130 eb58f9b1 Guido Trotter
    script.write("export IP=%s\n" % nic.ip)
131 eb58f9b1 Guido Trotter
    script.write("export BRIDGE=%s\n" % nic.bridge)
132 eb58f9b1 Guido Trotter
    script.write("export INTERFACE=$1\n")
133 eb58f9b1 Guido Trotter
    # TODO: make this configurable at ./configure time
134 eb58f9b1 Guido Trotter
    script.write("if [ -x /etc/ganeti/kvm-vif-bridge ]; then\n")
135 eb58f9b1 Guido Trotter
    script.write("  # Execute the user-specific vif file\n")
136 eb58f9b1 Guido Trotter
    script.write("  /etc/ganeti/kvm-vif-bridge\n")
137 eb58f9b1 Guido Trotter
    script.write("else\n")
138 eb58f9b1 Guido Trotter
    script.write("  # Connect the interface to the bridge\n")
139 eb58f9b1 Guido Trotter
    script.write("  /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
140 eb58f9b1 Guido Trotter
    script.write("  /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
141 eb58f9b1 Guido Trotter
    script.write("fi\n\n")
142 eb58f9b1 Guido Trotter
    # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
143 eb58f9b1 Guido Trotter
    # mounted noexec sometimes, so we'll have to find another place.
144 eb58f9b1 Guido Trotter
    (tmpfd, tmpfile_name) = tempfile.mkstemp()
145 eb58f9b1 Guido Trotter
    tmpfile = os.fdopen(tmpfd, 'w')
146 eb58f9b1 Guido Trotter
    tmpfile.write(script.getvalue())
147 eb58f9b1 Guido Trotter
    tmpfile.close()
148 eb58f9b1 Guido Trotter
    os.chmod(tmpfile_name, 0755)
149 eb58f9b1 Guido Trotter
    return tmpfile_name
150 eb58f9b1 Guido Trotter
151 eb58f9b1 Guido Trotter
  def ListInstances(self):
152 eb58f9b1 Guido Trotter
    """Get the list of running instances.
153 eb58f9b1 Guido Trotter

154 c41eea6e Iustin Pop
    We can do this by listing our live instances directory and
155 c41eea6e Iustin Pop
    checking whether the associated kvm process is still alive.
156 eb58f9b1 Guido Trotter

157 eb58f9b1 Guido Trotter
    """
158 eb58f9b1 Guido Trotter
    result = []
159 eb58f9b1 Guido Trotter
    for name in os.listdir(self._PIDS_DIR):
160 08137f9e Iustin Pop
      filename = "%s/%s" % (self._PIDS_DIR, name)
161 08137f9e Iustin Pop
      if utils.IsProcessAlive(utils.ReadPidFile(filename)):
162 eb58f9b1 Guido Trotter
        result.append(name)
163 eb58f9b1 Guido Trotter
    return result
164 eb58f9b1 Guido Trotter
165 eb58f9b1 Guido Trotter
  def GetInstanceInfo(self, instance_name):
166 eb58f9b1 Guido Trotter
    """Get instance properties.
167 eb58f9b1 Guido Trotter

168 c41eea6e Iustin Pop
    @param instance_name: the instance name
169 c41eea6e Iustin Pop

170 c41eea6e Iustin Pop
    @return: tuple (name, id, memory, vcpus, stat, times)
171 eb58f9b1 Guido Trotter

172 eb58f9b1 Guido Trotter
    """
173 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
174 1f8b3a27 Guido Trotter
    if not alive:
175 eb58f9b1 Guido Trotter
      return None
176 eb58f9b1 Guido Trotter
177 eb58f9b1 Guido Trotter
    cmdline_file = "/proc/%s/cmdline" % pid
178 eb58f9b1 Guido Trotter
    try:
179 eb58f9b1 Guido Trotter
      fh = open(cmdline_file, 'r')
180 eb58f9b1 Guido Trotter
      try:
181 eb58f9b1 Guido Trotter
        cmdline = fh.read()
182 eb58f9b1 Guido Trotter
      finally:
183 eb58f9b1 Guido Trotter
        fh.close()
184 90c024f6 Guido Trotter
    except EnvironmentError, err:
185 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list instance %s: %s" %
186 eb58f9b1 Guido Trotter
                                   (instance_name, err))
187 eb58f9b1 Guido Trotter
188 eb58f9b1 Guido Trotter
    memory = 0
189 eb58f9b1 Guido Trotter
    vcpus = 0
190 eb58f9b1 Guido Trotter
    stat = "---b-"
191 eb58f9b1 Guido Trotter
    times = "0"
192 eb58f9b1 Guido Trotter
193 eb58f9b1 Guido Trotter
    arg_list = cmdline.split('\x00')
194 eb58f9b1 Guido Trotter
    while arg_list:
195 eb58f9b1 Guido Trotter
      arg =  arg_list.pop(0)
196 eb58f9b1 Guido Trotter
      if arg == '-m':
197 eb58f9b1 Guido Trotter
        memory = arg_list.pop(0)
198 eb58f9b1 Guido Trotter
      elif arg == '-smp':
199 eb58f9b1 Guido Trotter
        vcpus = arg_list.pop(0)
200 eb58f9b1 Guido Trotter
201 eb58f9b1 Guido Trotter
    return (instance_name, pid, memory, vcpus, stat, times)
202 eb58f9b1 Guido Trotter
203 eb58f9b1 Guido Trotter
  def GetAllInstancesInfo(self):
204 eb58f9b1 Guido Trotter
    """Get properties of all instances.
205 eb58f9b1 Guido Trotter

206 c41eea6e Iustin Pop
    @return: list of tuples (name, id, memory, vcpus, stat, times)
207 c41eea6e Iustin Pop

208 eb58f9b1 Guido Trotter
    """
209 eb58f9b1 Guido Trotter
    data = []
210 eb58f9b1 Guido Trotter
    for name in os.listdir(self._PIDS_DIR):
211 08137f9e Iustin Pop
      filename = "%s/%s" % (self._PIDS_DIR, name)
212 08137f9e Iustin Pop
      if utils.IsProcessAlive(utils.ReadPidFile(filename)):
213 00ad5362 Guido Trotter
        try:
214 00ad5362 Guido Trotter
          info = self.GetInstanceInfo(name)
215 00ad5362 Guido Trotter
        except errors.HypervisorError, err:
216 00ad5362 Guido Trotter
          continue
217 00ad5362 Guido Trotter
        if info:
218 00ad5362 Guido Trotter
          data.append(info)
219 eb58f9b1 Guido Trotter
220 eb58f9b1 Guido Trotter
    return data
221 eb58f9b1 Guido Trotter
222 07813a9e Iustin Pop
  def _GenerateKVMRuntime(self, instance, block_devices):
223 ee5f20b0 Guido Trotter
    """Generate KVM information to start an instance.
224 eb58f9b1 Guido Trotter

225 eb58f9b1 Guido Trotter
    """
226 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
227 eb58f9b1 Guido Trotter
    kvm = constants.KVM_PATH
228 eb58f9b1 Guido Trotter
    kvm_cmd = [kvm]
229 8b3fd458 Iustin Pop
    kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
230 8b3fd458 Iustin Pop
    kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
231 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-pidfile', pidfile])
232 eb58f9b1 Guido Trotter
    # used just by the vnc server, if enabled
233 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-name', instance.name])
234 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-daemonize'])
235 6b5605e8 Iustin Pop
    if not instance.hvparams[constants.HV_ACPI]:
236 eb58f9b1 Guido Trotter
      kvm_cmd.extend(['-no-acpi'])
237 eb58f9b1 Guido Trotter
238 a985b417 Iustin Pop
    hvp = instance.hvparams
239 a985b417 Iustin Pop
    boot_disk = hvp[constants.HV_BOOT_ORDER] == "disk"
240 a985b417 Iustin Pop
    boot_cdrom = hvp[constants.HV_BOOT_ORDER] == "cdrom"
241 a985b417 Iustin Pop
    boot_network = hvp[constants.HV_BOOT_ORDER] == "network"
242 8745c3d7 Guido Trotter
243 8745c3d7 Guido Trotter
    if boot_network:
244 8745c3d7 Guido Trotter
      kvm_cmd.extend(['-boot', 'n'])
245 1213604d Guido Trotter
246 a985b417 Iustin Pop
    disk_type = hvp[constants.HV_DISK_TYPE]
247 1213604d Guido Trotter
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
248 1213604d Guido Trotter
      if_val = ',if=virtio'
249 1213604d Guido Trotter
    else:
250 1213604d Guido Trotter
      if_val = ',if=%s' % disk_type
251 069cfbf1 Iustin Pop
    for cfdev, dev_path in block_devices:
252 d34b16d7 Iustin Pop
      if cfdev.mode != constants.DISK_RDWR:
253 d34b16d7 Iustin Pop
        raise errors.HypervisorError("Instance has read-only disks which"
254 d34b16d7 Iustin Pop
                                     " are not supported by KVM")
255 eb58f9b1 Guido Trotter
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
256 66d5dbef Guido Trotter
      if boot_disk:
257 9dd363eb Guido Trotter
        kvm_cmd.extend(['-boot', 'c'])
258 eb58f9b1 Guido Trotter
        boot_val = ',boot=on'
259 8745c3d7 Guido Trotter
        # We only boot from the first disk
260 66d5dbef Guido Trotter
        boot_disk = False
261 eb58f9b1 Guido Trotter
      else:
262 eb58f9b1 Guido Trotter
        boot_val = ''
263 eb58f9b1 Guido Trotter
264 069cfbf1 Iustin Pop
      drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
265 eb58f9b1 Guido Trotter
      kvm_cmd.extend(['-drive', drive_val])
266 eb58f9b1 Guido Trotter
267 a985b417 Iustin Pop
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
268 66d5dbef Guido Trotter
    if iso_image:
269 9dd363eb Guido Trotter
      options = ',format=raw,media=cdrom'
270 66d5dbef Guido Trotter
      if boot_cdrom:
271 9dd363eb Guido Trotter
        kvm_cmd.extend(['-boot', 'd'])
272 66d5dbef Guido Trotter
        options = '%s,boot=on' % options
273 9dd363eb Guido Trotter
      else:
274 9dd363eb Guido Trotter
        options = '%s,if=virtio' % options
275 66d5dbef Guido Trotter
      drive_val = 'file=%s%s' % (iso_image, options)
276 66d5dbef Guido Trotter
      kvm_cmd.extend(['-drive', drive_val])
277 66d5dbef Guido Trotter
278 a985b417 Iustin Pop
    kernel_path = hvp[constants.HV_KERNEL_PATH]
279 df5ab9f0 Guido Trotter
    if kernel_path:
280 df5ab9f0 Guido Trotter
      kvm_cmd.extend(['-kernel', kernel_path])
281 a985b417 Iustin Pop
      initrd_path = hvp[constants.HV_INITRD_PATH]
282 df5ab9f0 Guido Trotter
      if initrd_path:
283 df5ab9f0 Guido Trotter
        kvm_cmd.extend(['-initrd', initrd_path])
284 07813a9e Iustin Pop
      root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
285 07813a9e Iustin Pop
                     hvp[constants.HV_KERNEL_ARGS]]
286 07813a9e Iustin Pop
      if hvp[constants.HV_SERIAL_CONSOLE]:
287 07813a9e Iustin Pop
        root_append.append('console=ttyS0,38400')
288 07813a9e Iustin Pop
      kvm_cmd.extend(['-append', ' '.join(root_append)])
289 eb58f9b1 Guido Trotter
290 a985b417 Iustin Pop
    mouse_type = hvp[constants.HV_USB_MOUSE]
291 11344a50 Guido Trotter
    if mouse_type:
292 11344a50 Guido Trotter
      kvm_cmd.extend(['-usb'])
293 11344a50 Guido Trotter
      kvm_cmd.extend(['-usbdevice', mouse_type])
294 11344a50 Guido Trotter
295 8470c8db Guido Trotter
    # FIXME: handle vnc password
296 a985b417 Iustin Pop
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
297 8470c8db Guido Trotter
    if vnc_bind_address:
298 8447f52b Guido Trotter
      if utils.IsValidIP(vnc_bind_address):
299 377d74c9 Guido Trotter
        if instance.network_port > constants.VNC_BASE_PORT:
300 377d74c9 Guido Trotter
          display = instance.network_port - constants.VNC_BASE_PORT
301 8447f52b Guido Trotter
          if vnc_bind_address == '0.0.0.0':
302 8447f52b Guido Trotter
            vnc_arg = ':%d' % (display)
303 8447f52b Guido Trotter
          else:
304 8447f52b Guido Trotter
            vnc_arg = '%s:%d' % (constants.HV_VNC_BIND_ADDRESS, display)
305 8470c8db Guido Trotter
        else:
306 8447f52b Guido Trotter
          logging.error("Network port is not a valid VNC display (%d < %d)."
307 8447f52b Guido Trotter
                        " Not starting VNC" %
308 8447f52b Guido Trotter
                        (instance.network_port,
309 377d74c9 Guido Trotter
                         constants.VNC_BASE_PORT))
310 8447f52b Guido Trotter
          vnc_arg = 'none'
311 8b2d1013 Guido Trotter
312 8b2d1013 Guido Trotter
        # Only allow tls and other option when not binding to a file, for now.
313 8b2d1013 Guido Trotter
        # kvm/qemu gets confused otherwise about the filename to use.
314 8b2d1013 Guido Trotter
        vnc_append = ''
315 a985b417 Iustin Pop
        if hvp[constants.HV_VNC_TLS]:
316 8b2d1013 Guido Trotter
          vnc_append = '%s,tls' % vnc_append
317 a985b417 Iustin Pop
          if hvp[constants.HV_VNC_X509_VERIFY]:
318 8b2d1013 Guido Trotter
            vnc_append = '%s,x509verify=%s' % (vnc_append,
319 a985b417 Iustin Pop
                                               hvp[constants.HV_VNC_X509])
320 a985b417 Iustin Pop
          elif hvp[constants.HV_VNC_X509]:
321 8b2d1013 Guido Trotter
            vnc_append = '%s,x509=%s' % (vnc_append,
322 a985b417 Iustin Pop
                                         hvp[constants.HV_VNC_X509])
323 8b2d1013 Guido Trotter
        vnc_arg = '%s%s' % (vnc_arg, vnc_append)
324 8b2d1013 Guido Trotter
325 8470c8db Guido Trotter
      else:
326 8b2d1013 Guido Trotter
        vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
327 8b2d1013 Guido Trotter
328 8447f52b Guido Trotter
      kvm_cmd.extend(['-vnc', vnc_arg])
329 8470c8db Guido Trotter
    else:
330 8470c8db Guido Trotter
      kvm_cmd.extend(['-nographic'])
331 8470c8db Guido Trotter
332 c4fbefc8 Guido Trotter
    monitor_dev = 'unix:%s,server,nowait' % \
333 c4fbefc8 Guido Trotter
      self._InstanceMonitor(instance.name)
334 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-monitor', monitor_dev])
335 a985b417 Iustin Pop
    if hvp[constants.HV_SERIAL_CONSOLE]:
336 a985b417 Iustin Pop
      serial_dev = ('unix:%s,server,nowait' %
337 a985b417 Iustin Pop
                    self._InstanceSerial(instance.name))
338 a2faf9ee Guido Trotter
      kvm_cmd.extend(['-serial', serial_dev])
339 a2faf9ee Guido Trotter
    else:
340 a2faf9ee Guido Trotter
      kvm_cmd.extend(['-serial', 'none'])
341 eb58f9b1 Guido Trotter
342 ee5f20b0 Guido Trotter
    # Save the current instance nics, but defer their expansion as parameters,
343 ee5f20b0 Guido Trotter
    # as we'll need to generate executable temp files for them.
344 ee5f20b0 Guido Trotter
    kvm_nics = instance.nics
345 a985b417 Iustin Pop
    hvparams = hvp
346 ee5f20b0 Guido Trotter
347 c2672466 Guido Trotter
    return (kvm_cmd, kvm_nics, hvparams)
348 ee5f20b0 Guido Trotter
349 38e250ba Guido Trotter
  def _WriteKVMRuntime(self, instance_name, data):
350 38e250ba Guido Trotter
    """Write an instance's KVM runtime
351 38e250ba Guido Trotter

352 38e250ba Guido Trotter
    """
353 38e250ba Guido Trotter
    try:
354 38e250ba Guido Trotter
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
355 38e250ba Guido Trotter
                      data=data)
356 90c024f6 Guido Trotter
    except EnvironmentError, err:
357 38e250ba Guido Trotter
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
358 38e250ba Guido Trotter
359 38e250ba Guido Trotter
  def _ReadKVMRuntime(self, instance_name):
360 38e250ba Guido Trotter
    """Read an instance's KVM runtime
361 38e250ba Guido Trotter

362 38e250ba Guido Trotter
    """
363 38e250ba Guido Trotter
    try:
364 38e250ba Guido Trotter
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
365 90c024f6 Guido Trotter
    except EnvironmentError, err:
366 38e250ba Guido Trotter
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
367 38e250ba Guido Trotter
    return file_content
368 38e250ba Guido Trotter
369 38e250ba Guido Trotter
  def _SaveKVMRuntime(self, instance, kvm_runtime):
370 38e250ba Guido Trotter
    """Save an instance's KVM runtime
371 38e250ba Guido Trotter

372 38e250ba Guido Trotter
    """
373 c2672466 Guido Trotter
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
374 38e250ba Guido Trotter
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
375 c2672466 Guido Trotter
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
376 38e250ba Guido Trotter
    self._WriteKVMRuntime(instance.name, serialized_form)
377 38e250ba Guido Trotter
378 30e42c4e Guido Trotter
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
379 38e250ba Guido Trotter
    """Load an instance's KVM runtime
380 38e250ba Guido Trotter

381 38e250ba Guido Trotter
    """
382 30e42c4e Guido Trotter
    if not serialized_runtime:
383 30e42c4e Guido Trotter
      serialized_runtime = self._ReadKVMRuntime(instance.name)
384 30e42c4e Guido Trotter
    loaded_runtime = serializer.Load(serialized_runtime)
385 c2672466 Guido Trotter
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
386 38e250ba Guido Trotter
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
387 c2672466 Guido Trotter
    return (kvm_cmd, kvm_nics, hvparams)
388 38e250ba Guido Trotter
389 30e42c4e Guido Trotter
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
390 ee5f20b0 Guido Trotter
    """Execute a KVM cmd, after completing it with some last minute data
391 ee5f20b0 Guido Trotter

392 30e42c4e Guido Trotter
    @type incoming: tuple of strings
393 30e42c4e Guido Trotter
    @param incoming: (target_host_ip, port)
394 30e42c4e Guido Trotter

395 ee5f20b0 Guido Trotter
    """
396 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
397 1f8b3a27 Guido Trotter
    if alive:
398 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
399 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
400 ee5f20b0 Guido Trotter
401 ee5f20b0 Guido Trotter
    temp_files = []
402 ee5f20b0 Guido Trotter
403 c2672466 Guido Trotter
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
404 ee5f20b0 Guido Trotter
405 ee5f20b0 Guido Trotter
    if not kvm_nics:
406 ee5f20b0 Guido Trotter
      kvm_cmd.extend(['-net', 'none'])
407 ee5f20b0 Guido Trotter
    else:
408 37f88dc6 Guido Trotter
      nic_type = hvparams[constants.HV_NIC_TYPE]
409 37f88dc6 Guido Trotter
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
410 37f88dc6 Guido Trotter
        nic_model = "model=virtio"
411 37f88dc6 Guido Trotter
      else:
412 37f88dc6 Guido Trotter
        nic_model = "model=%s" % nic_type
413 37f88dc6 Guido Trotter
414 ee5f20b0 Guido Trotter
      for nic_seq, nic in enumerate(kvm_nics):
415 37f88dc6 Guido Trotter
        nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
416 ee5f20b0 Guido Trotter
        script = self._WriteNetScript(instance, nic_seq, nic)
417 ee5f20b0 Guido Trotter
        kvm_cmd.extend(['-net', nic_val])
418 ee5f20b0 Guido Trotter
        kvm_cmd.extend(['-net', 'tap,script=%s' % script])
419 ee5f20b0 Guido Trotter
        temp_files.append(script)
420 ee5f20b0 Guido Trotter
421 30e42c4e Guido Trotter
    if incoming:
422 30e42c4e Guido Trotter
      target, port = incoming
423 30e42c4e Guido Trotter
      kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
424 30e42c4e Guido Trotter
425 eb58f9b1 Guido Trotter
    result = utils.RunCmd(kvm_cmd)
426 eb58f9b1 Guido Trotter
    if result.failed:
427 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
428 eb58f9b1 Guido Trotter
                                   (instance.name, result.fail_reason,
429 eb58f9b1 Guido Trotter
                                    result.output))
430 eb58f9b1 Guido Trotter
431 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
432 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
433 eb58f9b1 Guido Trotter
                                   (instance.name))
434 eb58f9b1 Guido Trotter
435 08137f9e Iustin Pop
    for filename in temp_files:
436 08137f9e Iustin Pop
      utils.RemoveFile(filename)
437 eb58f9b1 Guido Trotter
438 07813a9e Iustin Pop
  def StartInstance(self, instance, block_devices):
439 ee5f20b0 Guido Trotter
    """Start an instance.
440 ee5f20b0 Guido Trotter

441 ee5f20b0 Guido Trotter
    """
442 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
443 1f8b3a27 Guido Trotter
    if alive:
444 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
445 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
446 ee5f20b0 Guido Trotter
447 07813a9e Iustin Pop
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
448 38e250ba Guido Trotter
    self._SaveKVMRuntime(instance, kvm_runtime)
449 ee5f20b0 Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime)
450 ee5f20b0 Guido Trotter
451 6567aff3 Guido Trotter
  def _CallMonitorCommand(self, instance_name, command):
452 6567aff3 Guido Trotter
    """Invoke a command on the instance monitor.
453 6567aff3 Guido Trotter

454 6567aff3 Guido Trotter
    """
455 6567aff3 Guido Trotter
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
456 6567aff3 Guido Trotter
             (utils.ShellQuote(command),
457 6567aff3 Guido Trotter
              constants.SOCAT_PATH,
458 6567aff3 Guido Trotter
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
459 6567aff3 Guido Trotter
    result = utils.RunCmd(socat)
460 6567aff3 Guido Trotter
    if result.failed:
461 6567aff3 Guido Trotter
      msg = ("Failed to send command '%s' to instance %s."
462 6567aff3 Guido Trotter
             " output: %s, error: %s, fail_reason: %s" %
463 9798fcae Guido Trotter
             (command, instance_name,
464 9798fcae Guido Trotter
              result.stdout, result.stderr, result.fail_reason))
465 6567aff3 Guido Trotter
      raise errors.HypervisorError(msg)
466 6567aff3 Guido Trotter
467 6567aff3 Guido Trotter
    return result
468 6567aff3 Guido Trotter
469 6567aff3 Guido Trotter
  def _RetryInstancePowerdown(self, instance, pid, timeout=30):
470 6567aff3 Guido Trotter
    """Wait for an instance  to power down.
471 6567aff3 Guido Trotter

472 6567aff3 Guido Trotter
    """
473 6567aff3 Guido Trotter
    # Wait up to $timeout seconds
474 6567aff3 Guido Trotter
    end = time.time() + timeout
475 6567aff3 Guido Trotter
    wait = 1
476 6567aff3 Guido Trotter
    while time.time() < end and utils.IsProcessAlive(pid):
477 6567aff3 Guido Trotter
      self._CallMonitorCommand(instance.name, 'system_powerdown')
478 6567aff3 Guido Trotter
      time.sleep(wait)
479 6567aff3 Guido Trotter
      # Make wait time longer for next try
480 6567aff3 Guido Trotter
      if wait < 5:
481 6567aff3 Guido Trotter
        wait *= 1.3
482 6567aff3 Guido Trotter
483 eb58f9b1 Guido Trotter
  def StopInstance(self, instance, force=False):
484 eb58f9b1 Guido Trotter
    """Stop an instance.
485 eb58f9b1 Guido Trotter

486 eb58f9b1 Guido Trotter
    """
487 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
488 1f8b3a27 Guido Trotter
    if pid > 0 and alive:
489 6b5605e8 Iustin Pop
      if force or not instance.hvparams[constants.HV_ACPI]:
490 eb58f9b1 Guido Trotter
        utils.KillProcess(pid)
491 eb58f9b1 Guido Trotter
      else:
492 6567aff3 Guido Trotter
        self._RetryInstancePowerdown(instance, pid)
493 eb58f9b1 Guido Trotter
494 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(pid):
495 1f8b3a27 Guido Trotter
      utils.RemoveFile(pidfile)
496 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceMonitor(instance.name))
497 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceSerial(instance.name))
498 38e250ba Guido Trotter
      utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
499 6567aff3 Guido Trotter
      return True
500 6567aff3 Guido Trotter
    else:
501 6567aff3 Guido Trotter
      return False
502 eb58f9b1 Guido Trotter
503 eb58f9b1 Guido Trotter
  def RebootInstance(self, instance):
504 eb58f9b1 Guido Trotter
    """Reboot an instance.
505 eb58f9b1 Guido Trotter

506 eb58f9b1 Guido Trotter
    """
507 eb58f9b1 Guido Trotter
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
508 eb58f9b1 Guido Trotter
    # socket the instance will stop, but now power up again. So we'll resort
509 eb58f9b1 Guido Trotter
    # to shutdown and restart.
510 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
511 1f8b3a27 Guido Trotter
    if not alive:
512 1f8b3a27 Guido Trotter
      raise errors.HypervisorError("Failed to reboot instance %s: not running" %
513 1f8b3a27 Guido Trotter
                                             (instance.name))
514 f02881e0 Guido Trotter
    # StopInstance will delete the saved KVM runtime so:
515 f02881e0 Guido Trotter
    # ...first load it...
516 f02881e0 Guido Trotter
    kvm_runtime = self._LoadKVMRuntime(instance)
517 f02881e0 Guido Trotter
    # ...now we can safely call StopInstance...
518 f02881e0 Guido Trotter
    if not self.StopInstance(instance):
519 f02881e0 Guido Trotter
      self.StopInstance(instance, force=True)
520 f02881e0 Guido Trotter
    # ...and finally we can save it again, and execute it...
521 f02881e0 Guido Trotter
    self._SaveKVMRuntime(instance, kvm_runtime)
522 f02881e0 Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime)
523 eb58f9b1 Guido Trotter
524 30e42c4e Guido Trotter
  def MigrationInfo(self, instance):
525 30e42c4e Guido Trotter
    """Get instance information to perform a migration.
526 30e42c4e Guido Trotter

527 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
528 30e42c4e Guido Trotter
    @param instance: instance to be migrated
529 30e42c4e Guido Trotter
    @rtype: string
530 30e42c4e Guido Trotter
    @return: content of the KVM runtime file
531 30e42c4e Guido Trotter

532 30e42c4e Guido Trotter
    """
533 30e42c4e Guido Trotter
    return self._ReadKVMRuntime(instance.name)
534 30e42c4e Guido Trotter
535 30e42c4e Guido Trotter
  def AcceptInstance(self, instance, info, target):
536 30e42c4e Guido Trotter
    """Prepare to accept an instance.
537 30e42c4e Guido Trotter

538 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
539 30e42c4e Guido Trotter
    @param instance: instance to be accepted
540 30e42c4e Guido Trotter
    @type info: string
541 30e42c4e Guido Trotter
    @param info: content of the KVM runtime file on the source node
542 30e42c4e Guido Trotter
    @type target: string
543 30e42c4e Guido Trotter
    @param target: target host (usually ip), on this node
544 30e42c4e Guido Trotter

545 30e42c4e Guido Trotter
    """
546 30e42c4e Guido Trotter
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
547 30e42c4e Guido Trotter
    incoming_address = (target, constants.KVM_MIGRATION_PORT)
548 30e42c4e Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
549 30e42c4e Guido Trotter
550 30e42c4e Guido Trotter
  def FinalizeMigration(self, instance, info, success):
551 30e42c4e Guido Trotter
    """Finalize an instance migration.
552 30e42c4e Guido Trotter

553 30e42c4e Guido Trotter
    Stop the incoming mode KVM.
554 30e42c4e Guido Trotter

555 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
556 30e42c4e Guido Trotter
    @param instance: instance whose migration is being aborted
557 30e42c4e Guido Trotter

558 30e42c4e Guido Trotter
    """
559 30e42c4e Guido Trotter
    if success:
560 30e42c4e Guido Trotter
      self._WriteKVMRuntime(instance.name, info)
561 30e42c4e Guido Trotter
    else:
562 30e42c4e Guido Trotter
      self.StopInstance(instance, force=True)
563 30e42c4e Guido Trotter
564 30e42c4e Guido Trotter
  def MigrateInstance(self, instance_name, target, live):
565 30e42c4e Guido Trotter
    """Migrate an instance to a target node.
566 30e42c4e Guido Trotter

567 30e42c4e Guido Trotter
    The migration will not be attempted if the instance is not
568 30e42c4e Guido Trotter
    currently running.
569 30e42c4e Guido Trotter

570 30e42c4e Guido Trotter
    @type instance_name: string
571 30e42c4e Guido Trotter
    @param instance_name: name of the instance to be migrated
572 30e42c4e Guido Trotter
    @type target: string
573 30e42c4e Guido Trotter
    @param target: ip address of the target node
574 30e42c4e Guido Trotter
    @type live: boolean
575 30e42c4e Guido Trotter
    @param live: perform a live migration
576 30e42c4e Guido Trotter

577 30e42c4e Guido Trotter
    """
578 30e42c4e Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
579 30e42c4e Guido Trotter
    if not alive:
580 30e42c4e Guido Trotter
      raise errors.HypervisorError("Instance not running, cannot migrate")
581 30e42c4e Guido Trotter
582 30e42c4e Guido Trotter
    if not live:
583 30e42c4e Guido Trotter
      self._CallMonitorCommand(instance_name, 'stop')
584 30e42c4e Guido Trotter
585 30e42c4e Guido Trotter
    migrate_command = ('migrate -d tcp:%s:%s' %
586 30e42c4e Guido Trotter
                       (target, constants.KVM_MIGRATION_PORT))
587 30e42c4e Guido Trotter
    self._CallMonitorCommand(instance_name, migrate_command)
588 30e42c4e Guido Trotter
589 30e42c4e Guido Trotter
    info_command = 'info migrate'
590 30e42c4e Guido Trotter
    done = False
591 30e42c4e Guido Trotter
    while not done:
592 30e42c4e Guido Trotter
      result = self._CallMonitorCommand(instance_name, info_command)
593 30e42c4e Guido Trotter
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
594 30e42c4e Guido Trotter
      if not match:
595 30e42c4e Guido Trotter
        raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
596 30e42c4e Guido Trotter
                                     result.stdout)
597 30e42c4e Guido Trotter
      else:
598 30e42c4e Guido Trotter
        status = match.group(1)
599 30e42c4e Guido Trotter
        if status == 'completed':
600 30e42c4e Guido Trotter
          done = True
601 30e42c4e Guido Trotter
        elif status == 'active':
602 30e42c4e Guido Trotter
          time.sleep(2)
603 c087266c Guido Trotter
        elif status == 'failed' or status == 'cancelled':
604 c087266c Guido Trotter
          if not live:
605 c087266c Guido Trotter
            self._CallMonitorCommand(instance_name, 'cont')
606 c087266c Guido Trotter
          raise errors.HypervisorError("Migration %s at the kvm level" %
607 c087266c Guido Trotter
                                       status)
608 30e42c4e Guido Trotter
        else:
609 30e42c4e Guido Trotter
          logging.info("KVM: unknown migration status '%s'" % status)
610 30e42c4e Guido Trotter
          time.sleep(2)
611 30e42c4e Guido Trotter
612 30e42c4e Guido Trotter
    utils.KillProcess(pid)
613 30e42c4e Guido Trotter
    utils.RemoveFile(pidfile)
614 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceMonitor(instance_name))
615 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceSerial(instance_name))
616 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceKVMRuntime(instance_name))
617 30e42c4e Guido Trotter
618 eb58f9b1 Guido Trotter
  def GetNodeInfo(self):
619 eb58f9b1 Guido Trotter
    """Return information about the node.
620 eb58f9b1 Guido Trotter

621 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
622 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
623 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
624 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
625 eb58f9b1 Guido Trotter

626 eb58f9b1 Guido Trotter
    """
627 eb58f9b1 Guido Trotter
    # global ram usage from the xm info command
628 eb58f9b1 Guido Trotter
    # memory                 : 3583
629 eb58f9b1 Guido Trotter
    # free_memory            : 747
630 eb58f9b1 Guido Trotter
    # note: in xen 3, memory has changed to total_memory
631 eb58f9b1 Guido Trotter
    try:
632 eb58f9b1 Guido Trotter
      fh = file("/proc/meminfo")
633 eb58f9b1 Guido Trotter
      try:
634 eb58f9b1 Guido Trotter
        data = fh.readlines()
635 eb58f9b1 Guido Trotter
      finally:
636 eb58f9b1 Guido Trotter
        fh.close()
637 90c024f6 Guido Trotter
    except EnvironmentError, err:
638 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
639 eb58f9b1 Guido Trotter
640 eb58f9b1 Guido Trotter
    result = {}
641 eb58f9b1 Guido Trotter
    sum_free = 0
642 eb58f9b1 Guido Trotter
    for line in data:
643 eb58f9b1 Guido Trotter
      splitfields = line.split(":", 1)
644 eb58f9b1 Guido Trotter
645 eb58f9b1 Guido Trotter
      if len(splitfields) > 1:
646 eb58f9b1 Guido Trotter
        key = splitfields[0].strip()
647 eb58f9b1 Guido Trotter
        val = splitfields[1].strip()
648 eb58f9b1 Guido Trotter
        if key == 'MemTotal':
649 eb58f9b1 Guido Trotter
          result['memory_total'] = int(val.split()[0])/1024
650 eb58f9b1 Guido Trotter
        elif key in ('MemFree', 'Buffers', 'Cached'):
651 eb58f9b1 Guido Trotter
          sum_free += int(val.split()[0])/1024
652 eb58f9b1 Guido Trotter
        elif key == 'Active':
653 eb58f9b1 Guido Trotter
          result['memory_dom0'] = int(val.split()[0])/1024
654 eb58f9b1 Guido Trotter
    result['memory_free'] = sum_free
655 eb58f9b1 Guido Trotter
656 eb58f9b1 Guido Trotter
    cpu_total = 0
657 eb58f9b1 Guido Trotter
    try:
658 eb58f9b1 Guido Trotter
      fh = open("/proc/cpuinfo")
659 eb58f9b1 Guido Trotter
      try:
660 eb58f9b1 Guido Trotter
        cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
661 eb58f9b1 Guido Trotter
                                   fh.read()))
662 eb58f9b1 Guido Trotter
      finally:
663 eb58f9b1 Guido Trotter
        fh.close()
664 eb58f9b1 Guido Trotter
    except EnvironmentError, err:
665 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
666 eb58f9b1 Guido Trotter
    result['cpu_total'] = cpu_total
667 0105bad3 Iustin Pop
    # FIXME: export correct data here
668 0105bad3 Iustin Pop
    result['cpu_nodes'] = 1
669 0105bad3 Iustin Pop
    result['cpu_sockets'] = 1
670 eb58f9b1 Guido Trotter
671 eb58f9b1 Guido Trotter
    return result
672 eb58f9b1 Guido Trotter
673 637ce7f9 Guido Trotter
  @classmethod
674 5431b2e4 Guido Trotter
  def GetShellCommandForConsole(cls, instance, hvparams, beparams):
675 eb58f9b1 Guido Trotter
    """Return a command for connecting to the console of an instance.
676 eb58f9b1 Guido Trotter

677 eb58f9b1 Guido Trotter
    """
678 a2faf9ee Guido Trotter
    if hvparams[constants.HV_SERIAL_CONSOLE]:
679 a2faf9ee Guido Trotter
      # FIXME: The socat shell is not perfect. In particular the way we start
680 a2faf9ee Guido Trotter
      # it ctrl+c will close it, rather than being passed to the other end.
681 a2faf9ee Guido Trotter
      # On the other hand if we pass the option 'raw' (or ignbrk=1) there
682 a2faf9ee Guido Trotter
      # will be no way of exiting socat (except killing it from another shell)
683 a2faf9ee Guido Trotter
      # and ctrl+c doesn't work anyway, printing ^C rather than being
684 a2faf9ee Guido Trotter
      # interpreted by kvm. For now we'll leave it this way, which at least
685 a2faf9ee Guido Trotter
      # allows a minimal interaction and changes on the machine.
686 a2faf9ee Guido Trotter
      shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
687 a2faf9ee Guido Trotter
                       (constants.SOCAT_PATH,
688 a2faf9ee Guido Trotter
                        utils.ShellQuote(cls._InstanceSerial(instance.name))))
689 a2faf9ee Guido Trotter
    else:
690 a2faf9ee Guido Trotter
      shell_command = "echo 'No serial shell for instance %s'" % instance.name
691 3be34f57 Guido Trotter
692 3be34f57 Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
693 3be34f57 Guido Trotter
    if vnc_bind_address:
694 377d74c9 Guido Trotter
      if instance.network_port > constants.VNC_BASE_PORT:
695 377d74c9 Guido Trotter
        display = instance.network_port - constants.VNC_BASE_PORT
696 3be34f57 Guido Trotter
        vnc_command = ("echo 'Instance has VNC listening on %s:%d"
697 3be34f57 Guido Trotter
                       " (display: %d)'" % (vnc_bind_address,
698 3be34f57 Guido Trotter
                                            instance.network_port,
699 3be34f57 Guido Trotter
                                            display))
700 3be34f57 Guido Trotter
        shell_command = "%s; %s" % (vnc_command, shell_command)
701 3be34f57 Guido Trotter
702 a2faf9ee Guido Trotter
    return shell_command
703 eb58f9b1 Guido Trotter
704 eb58f9b1 Guido Trotter
  def Verify(self):
705 eb58f9b1 Guido Trotter
    """Verify the hypervisor.
706 eb58f9b1 Guido Trotter

707 eb58f9b1 Guido Trotter
    Check that the binary exists.
708 eb58f9b1 Guido Trotter

709 eb58f9b1 Guido Trotter
    """
710 eb58f9b1 Guido Trotter
    if not os.path.exists(constants.KVM_PATH):
711 eb58f9b1 Guido Trotter
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
712 14aa53cb Guido Trotter
    if not os.path.exists(constants.SOCAT_PATH):
713 14aa53cb Guido Trotter
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
714 14aa53cb Guido Trotter
715 6b5605e8 Iustin Pop
716 6b5605e8 Iustin Pop
  @classmethod
717 6b5605e8 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
718 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
719 6b5605e8 Iustin Pop

720 6b5605e8 Iustin Pop
    @type hvparams:  dict
721 6b5605e8 Iustin Pop
    @param hvparams: dictionary with parameter names/value
722 6b5605e8 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
723 6b5605e8 Iustin Pop

724 6b5605e8 Iustin Pop
    """
725 47387b1e Guido Trotter
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
726 6b5605e8 Iustin Pop
727 df5ab9f0 Guido Trotter
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
728 df5ab9f0 Guido Trotter
    if kernel_path:
729 df5ab9f0 Guido Trotter
      if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
730 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("The kernel path must be an absolute path"
731 df5ab9f0 Guido Trotter
                                     ", if defined")
732 6b5605e8 Iustin Pop
733 df5ab9f0 Guido Trotter
      if not hvparams[constants.HV_ROOT_PATH]:
734 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("Need a root partition for the instance"
735 df5ab9f0 Guido Trotter
                                     ", if a kernel is defined")
736 074ca009 Guido Trotter
737 6b5605e8 Iustin Pop
    if hvparams[constants.HV_INITRD_PATH]:
738 6b5605e8 Iustin Pop
      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
739 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("The initrd path must an absolute path"
740 6b5605e8 Iustin Pop
                                     ", if defined")
741 6b5605e8 Iustin Pop
742 56fee73b Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
743 56fee73b Guido Trotter
    if vnc_bind_address:
744 56fee73b Guido Trotter
      if not utils.IsValidIP(vnc_bind_address):
745 8447f52b Guido Trotter
        if not os.path.isabs(vnc_bind_address):
746 8447f52b Guido Trotter
          raise errors.HypervisorError("The VNC bind address must be either"
747 8447f52b Guido Trotter
                                       " a valid IP address or an absolute"
748 8447f52b Guido Trotter
                                       " pathname. '%s' given" %
749 8447f52b Guido Trotter
                                       vnc_bind_address)
750 56fee73b Guido Trotter
751 8b2d1013 Guido Trotter
    if hvparams[constants.HV_VNC_X509_VERIFY] and \
752 8b2d1013 Guido Trotter
      not hvparams[constants.HV_VNC_X509]:
753 8b2d1013 Guido Trotter
        raise errors.HypervisorError("%s must be defined, if %s is" %
754 8b2d1013 Guido Trotter
                                     (constants.HV_VNC_X509,
755 8b2d1013 Guido Trotter
                                      constants.HV_VNC_X509_VERIFY))
756 8b2d1013 Guido Trotter
757 8b2d1013 Guido Trotter
    if hvparams[constants.HV_VNC_X509]:
758 8b2d1013 Guido Trotter
      if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
759 8b2d1013 Guido Trotter
        raise errors.HypervisorError("The vnc x509 path must an absolute path"
760 8b2d1013 Guido Trotter
                                     ", if defined")
761 8b2d1013 Guido Trotter
762 66d5dbef Guido Trotter
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
763 66d5dbef Guido Trotter
    if iso_path and not os.path.isabs(iso_path):
764 66d5dbef Guido Trotter
      raise errors.HypervisorError("The path to the CDROM image must be"
765 66d5dbef Guido Trotter
                                   " an absolute path, if defined")
766 66d5dbef Guido Trotter
767 66d5dbef Guido Trotter
    boot_order = hvparams[constants.HV_BOOT_ORDER]
768 8745c3d7 Guido Trotter
    if boot_order not in ('cdrom', 'disk', 'network'):
769 8745c3d7 Guido Trotter
      raise errors.HypervisorError("The boot order must be 'cdrom', 'disk' or"
770 8745c3d7 Guido Trotter
                                   " 'network'")
771 66d5dbef Guido Trotter
772 ec91c05d Guido Trotter
    if boot_order == 'cdrom' and not iso_path:
773 ec91c05d Guido Trotter
      raise errors.HypervisorError("Cannot boot from cdrom without an ISO path")
774 ec91c05d Guido Trotter
775 43440815 Guido Trotter
    nic_type = hvparams[constants.HV_NIC_TYPE]
776 43440815 Guido Trotter
    if nic_type not in constants.HT_KVM_VALID_NIC_TYPES:
777 43440815 Guido Trotter
      raise errors.HypervisorError("Invalid NIC type %s specified for the KVM"
778 43440815 Guido Trotter
                                   " hypervisor. Please choose one of: %s" %
779 43440815 Guido Trotter
                                   (nic_type,
780 43440815 Guido Trotter
                                    constants.HT_KVM_VALID_NIC_TYPES))
781 8745c3d7 Guido Trotter
    elif boot_order == 'network' and nic_type == constants.HT_NIC_PARAVIRTUAL:
782 8745c3d7 Guido Trotter
      raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
783 8745c3d7 Guido Trotter
                                   " change the nic type.")
784 43440815 Guido Trotter
785 43440815 Guido Trotter
    disk_type = hvparams[constants.HV_DISK_TYPE]
786 43440815 Guido Trotter
    if disk_type not in constants.HT_KVM_VALID_DISK_TYPES:
787 43440815 Guido Trotter
      raise errors.HypervisorError("Invalid disk type %s specified for the KVM"
788 43440815 Guido Trotter
                                   " hypervisor. Please choose one of: %s" %
789 43440815 Guido Trotter
                                   (disk_type,
790 43440815 Guido Trotter
                                    constants.HT_KVM_VALID_DISK_TYPES))
791 43440815 Guido Trotter
792 11344a50 Guido Trotter
    mouse_type = hvparams[constants.HV_USB_MOUSE]
793 11344a50 Guido Trotter
    if mouse_type and mouse_type not in ('mouse', 'tablet'):
794 11344a50 Guido Trotter
      raise errors.HypervisorError("Invalid usb mouse type %s specified for"
795 11344a50 Guido Trotter
                                   " the KVM hyervisor. Please choose"
796 11344a50 Guido Trotter
                                   " 'mouse' or 'tablet'" % mouse_type)
797 11344a50 Guido Trotter
798 6b5605e8 Iustin Pop
  def ValidateParameters(self, hvparams):
799 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
800 6b5605e8 Iustin Pop

801 6b5605e8 Iustin Pop
    For the KVM hypervisor, this checks the existence of the
802 6b5605e8 Iustin Pop
    kernel.
803 6b5605e8 Iustin Pop

804 6b5605e8 Iustin Pop
    """
805 47387b1e Guido Trotter
    super(KVMHypervisor, self).ValidateParameters(hvparams)
806 6b5605e8 Iustin Pop
807 6b5605e8 Iustin Pop
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
808 df5ab9f0 Guido Trotter
    if kernel_path and not os.path.isfile(kernel_path):
809 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance kernel '%s' not found or"
810 6b5605e8 Iustin Pop
                                   " not a file" % kernel_path)
811 6b5605e8 Iustin Pop
    initrd_path = hvparams[constants.HV_INITRD_PATH]
812 6b5605e8 Iustin Pop
    if initrd_path and not os.path.isfile(initrd_path):
813 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance initrd '%s' not found or"
814 6b5605e8 Iustin Pop
                                   " not a file" % initrd_path)
815 8b2d1013 Guido Trotter
816 8b2d1013 Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
817 8b2d1013 Guido Trotter
    if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
818 8b2d1013 Guido Trotter
       not os.path.isdir(vnc_bind_address):
819 8b2d1013 Guido Trotter
       raise errors.HypervisorError("Instance vnc bind address must be either"
820 8b2d1013 Guido Trotter
                                    " an ip address or an existing directory")
821 8b2d1013 Guido Trotter
822 8b2d1013 Guido Trotter
    vnc_x509 = hvparams[constants.HV_VNC_X509]
823 8b2d1013 Guido Trotter
    if vnc_x509 and not os.path.isdir(vnc_x509):
824 8b2d1013 Guido Trotter
      raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
825 8b2d1013 Guido Trotter
                                   " or not a directory" % vnc_x509)
826 8b2d1013 Guido Trotter
827 66d5dbef Guido Trotter
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
828 66d5dbef Guido Trotter
    if iso_path and not os.path.isfile(iso_path):
829 66d5dbef Guido Trotter
      raise errors.HypervisorError("Instance cdrom image '%s' not found or"
830 66d5dbef Guido Trotter
                                   " not a file" % iso_path)