Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 3213d3c8

History | View | Annotate | Download (29.4 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 6b5605e8 Iustin Pop
    constants.HV_ACPI,
56 a2faf9ee Guido Trotter
    constants.HV_SERIAL_CONSOLE,
57 56fee73b Guido Trotter
    constants.HV_VNC_BIND_ADDRESS,
58 8b2d1013 Guido Trotter
    constants.HV_VNC_TLS,
59 8b2d1013 Guido Trotter
    constants.HV_VNC_X509,
60 8b2d1013 Guido Trotter
    constants.HV_VNC_X509_VERIFY,
61 66d5dbef Guido Trotter
    constants.HV_CDROM_IMAGE_PATH,
62 66d5dbef Guido Trotter
    constants.HV_BOOT_ORDER,
63 43440815 Guido Trotter
    constants.HV_NIC_TYPE,
64 43440815 Guido Trotter
    constants.HV_DISK_TYPE,
65 11344a50 Guido Trotter
    constants.HV_USB_MOUSE,
66 6b5605e8 Iustin Pop
    ]
67 6b5605e8 Iustin Pop
68 30e42c4e Guido Trotter
  _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
69 30e42c4e Guido Trotter
                                    re.M | re.I)
70 30e42c4e Guido Trotter
71 eb58f9b1 Guido Trotter
  def __init__(self):
72 eb58f9b1 Guido Trotter
    hv_base.BaseHypervisor.__init__(self)
73 eb58f9b1 Guido Trotter
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
74 eb58f9b1 Guido Trotter
    # in a tmpfs filesystem or has been otherwise wiped out.
75 08137f9e Iustin Pop
    for mydir in self._DIRS:
76 08137f9e Iustin Pop
      if not os.path.exists(mydir):
77 08137f9e Iustin Pop
        os.mkdir(mydir)
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 ee5f20b0 Guido Trotter
  def _GenerateKVMRuntime(self, instance, block_devices, extra_args):
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 66d5dbef Guido Trotter
    boot_disk = (instance.hvparams[constants.HV_BOOT_ORDER] == "disk")
239 66d5dbef Guido Trotter
    boot_cdrom = (instance.hvparams[constants.HV_BOOT_ORDER] == "cdrom")
240 8745c3d7 Guido Trotter
    boot_network = (instance.hvparams[constants.HV_BOOT_ORDER] == "network")
241 8745c3d7 Guido Trotter
242 8745c3d7 Guido Trotter
    if boot_network:
243 8745c3d7 Guido Trotter
      kvm_cmd.extend(['-boot', 'n'])
244 1213604d Guido Trotter
245 1213604d Guido Trotter
    disk_type = instance.hvparams[constants.HV_DISK_TYPE]
246 1213604d Guido Trotter
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
247 1213604d Guido Trotter
      if_val = ',if=virtio'
248 1213604d Guido Trotter
    else:
249 1213604d Guido Trotter
      if_val = ',if=%s' % disk_type
250 069cfbf1 Iustin Pop
    for cfdev, dev_path in block_devices:
251 d34b16d7 Iustin Pop
      if cfdev.mode != constants.DISK_RDWR:
252 d34b16d7 Iustin Pop
        raise errors.HypervisorError("Instance has read-only disks which"
253 d34b16d7 Iustin Pop
                                     " are not supported by KVM")
254 eb58f9b1 Guido Trotter
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
255 66d5dbef Guido Trotter
      if boot_disk:
256 9dd363eb Guido Trotter
        kvm_cmd.extend(['-boot', 'c'])
257 eb58f9b1 Guido Trotter
        boot_val = ',boot=on'
258 8745c3d7 Guido Trotter
        # We only boot from the first disk
259 66d5dbef Guido Trotter
        boot_disk = False
260 eb58f9b1 Guido Trotter
      else:
261 eb58f9b1 Guido Trotter
        boot_val = ''
262 eb58f9b1 Guido Trotter
263 069cfbf1 Iustin Pop
      drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
264 eb58f9b1 Guido Trotter
      kvm_cmd.extend(['-drive', drive_val])
265 eb58f9b1 Guido Trotter
266 66d5dbef Guido Trotter
    iso_image = instance.hvparams[constants.HV_CDROM_IMAGE_PATH]
267 66d5dbef Guido Trotter
    if iso_image:
268 9dd363eb Guido Trotter
      options = ',format=raw,media=cdrom'
269 66d5dbef Guido Trotter
      if boot_cdrom:
270 9dd363eb Guido Trotter
        kvm_cmd.extend(['-boot', 'd'])
271 66d5dbef Guido Trotter
        options = '%s,boot=on' % options
272 9dd363eb Guido Trotter
      else:
273 9dd363eb Guido Trotter
        options = '%s,if=virtio' % options
274 66d5dbef Guido Trotter
      drive_val = 'file=%s%s' % (iso_image, options)
275 66d5dbef Guido Trotter
      kvm_cmd.extend(['-drive', drive_val])
276 66d5dbef Guido Trotter
277 df5ab9f0 Guido Trotter
    kernel_path = instance.hvparams[constants.HV_KERNEL_PATH]
278 df5ab9f0 Guido Trotter
    if kernel_path:
279 df5ab9f0 Guido Trotter
      kvm_cmd.extend(['-kernel', kernel_path])
280 df5ab9f0 Guido Trotter
      initrd_path = instance.hvparams[constants.HV_INITRD_PATH]
281 df5ab9f0 Guido Trotter
      if initrd_path:
282 df5ab9f0 Guido Trotter
        kvm_cmd.extend(['-initrd', initrd_path])
283 df5ab9f0 Guido Trotter
      root_append = 'root=%s ro' % instance.hvparams[constants.HV_ROOT_PATH]
284 df5ab9f0 Guido Trotter
      if instance.hvparams[constants.HV_SERIAL_CONSOLE]:
285 df5ab9f0 Guido Trotter
        kvm_cmd.extend(['-append', 'console=ttyS0,38400 %s' % root_append])
286 df5ab9f0 Guido Trotter
      else:
287 df5ab9f0 Guido Trotter
        kvm_cmd.extend(['-append', root_append])
288 eb58f9b1 Guido Trotter
289 11344a50 Guido Trotter
    mouse_type = instance.hvparams[constants.HV_USB_MOUSE]
290 11344a50 Guido Trotter
    if mouse_type:
291 11344a50 Guido Trotter
      kvm_cmd.extend(['-usb'])
292 11344a50 Guido Trotter
      kvm_cmd.extend(['-usbdevice', mouse_type])
293 11344a50 Guido Trotter
294 8470c8db Guido Trotter
    # FIXME: handle vnc password
295 8470c8db Guido Trotter
    vnc_bind_address = instance.hvparams[constants.HV_VNC_BIND_ADDRESS]
296 8470c8db Guido Trotter
    if vnc_bind_address:
297 8447f52b Guido Trotter
      if utils.IsValidIP(vnc_bind_address):
298 377d74c9 Guido Trotter
        if instance.network_port > constants.VNC_BASE_PORT:
299 377d74c9 Guido Trotter
          display = instance.network_port - constants.VNC_BASE_PORT
300 8447f52b Guido Trotter
          if vnc_bind_address == '0.0.0.0':
301 8447f52b Guido Trotter
            vnc_arg = ':%d' % (display)
302 8447f52b Guido Trotter
          else:
303 8447f52b Guido Trotter
            vnc_arg = '%s:%d' % (constants.HV_VNC_BIND_ADDRESS, display)
304 8470c8db Guido Trotter
        else:
305 8447f52b Guido Trotter
          logging.error("Network port is not a valid VNC display (%d < %d)."
306 8447f52b Guido Trotter
                        " Not starting VNC" %
307 8447f52b Guido Trotter
                        (instance.network_port,
308 377d74c9 Guido Trotter
                         constants.VNC_BASE_PORT))
309 8447f52b Guido Trotter
          vnc_arg = 'none'
310 8b2d1013 Guido Trotter
311 8b2d1013 Guido Trotter
        # Only allow tls and other option when not binding to a file, for now.
312 8b2d1013 Guido Trotter
        # kvm/qemu gets confused otherwise about the filename to use.
313 8b2d1013 Guido Trotter
        vnc_append = ''
314 8b2d1013 Guido Trotter
        if instance.hvparams[constants.HV_VNC_TLS]:
315 8b2d1013 Guido Trotter
          vnc_append = '%s,tls' % vnc_append
316 8b2d1013 Guido Trotter
          if instance.hvparams[constants.HV_VNC_X509_VERIFY]:
317 8b2d1013 Guido Trotter
            vnc_append = '%s,x509verify=%s' % (vnc_append,
318 8b2d1013 Guido Trotter
              instance.hvparams[constants.HV_VNC_X509])
319 8b2d1013 Guido Trotter
          elif instance.hvparams[constants.HV_VNC_X509]:
320 8b2d1013 Guido Trotter
            vnc_append = '%s,x509=%s' % (vnc_append,
321 8b2d1013 Guido Trotter
              instance.hvparams[constants.HV_VNC_X509])
322 8b2d1013 Guido Trotter
        vnc_arg = '%s%s' % (vnc_arg, vnc_append)
323 8b2d1013 Guido Trotter
324 8470c8db Guido Trotter
      else:
325 8b2d1013 Guido Trotter
        vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
326 8b2d1013 Guido Trotter
327 8447f52b Guido Trotter
      kvm_cmd.extend(['-vnc', vnc_arg])
328 8470c8db Guido Trotter
    else:
329 8470c8db Guido Trotter
      kvm_cmd.extend(['-nographic'])
330 8470c8db Guido Trotter
331 c4fbefc8 Guido Trotter
    monitor_dev = 'unix:%s,server,nowait' % \
332 c4fbefc8 Guido Trotter
      self._InstanceMonitor(instance.name)
333 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-monitor', monitor_dev])
334 a2faf9ee Guido Trotter
    if instance.hvparams[constants.HV_SERIAL_CONSOLE]:
335 a2faf9ee Guido Trotter
      serial_dev = 'unix:%s,server,nowait' % self._InstanceSerial(instance.name)
336 a2faf9ee Guido Trotter
      kvm_cmd.extend(['-serial', serial_dev])
337 a2faf9ee Guido Trotter
    else:
338 a2faf9ee Guido Trotter
      kvm_cmd.extend(['-serial', 'none'])
339 eb58f9b1 Guido Trotter
340 ee5f20b0 Guido Trotter
    # Save the current instance nics, but defer their expansion as parameters,
341 ee5f20b0 Guido Trotter
    # as we'll need to generate executable temp files for them.
342 ee5f20b0 Guido Trotter
    kvm_nics = instance.nics
343 c2672466 Guido Trotter
    hvparams = instance.hvparams
344 ee5f20b0 Guido Trotter
345 c2672466 Guido Trotter
    return (kvm_cmd, kvm_nics, hvparams)
346 ee5f20b0 Guido Trotter
347 38e250ba Guido Trotter
  def _WriteKVMRuntime(self, instance_name, data):
348 38e250ba Guido Trotter
    """Write an instance's KVM runtime
349 38e250ba Guido Trotter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

551 30e42c4e Guido Trotter
    Stop the incoming mode KVM.
552 30e42c4e Guido Trotter

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

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

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

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

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

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

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

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

705 eb58f9b1 Guido Trotter
    Check that the binary exists.
706 eb58f9b1 Guido Trotter

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

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

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

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

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