Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 8745c3d7

History | View | Annotate | Download (29 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 6b5605e8 Iustin Pop
    ]
66 6b5605e8 Iustin Pop
67 30e42c4e Guido Trotter
  _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
68 30e42c4e Guido Trotter
                                    re.M | re.I)
69 30e42c4e Guido Trotter
70 eb58f9b1 Guido Trotter
  def __init__(self):
71 eb58f9b1 Guido Trotter
    hv_base.BaseHypervisor.__init__(self)
72 eb58f9b1 Guido Trotter
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
73 eb58f9b1 Guido Trotter
    # in a tmpfs filesystem or has been otherwise wiped out.
74 08137f9e Iustin Pop
    for mydir in self._DIRS:
75 08137f9e Iustin Pop
      if not os.path.exists(mydir):
76 08137f9e Iustin Pop
        os.mkdir(mydir)
77 eb58f9b1 Guido Trotter
78 1f8b3a27 Guido Trotter
  def _InstancePidAlive(self, instance_name):
79 1f8b3a27 Guido Trotter
    """Returns the instance pid and pidfile
80 1f8b3a27 Guido Trotter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

385 30e42c4e Guido Trotter
    @type incoming: tuple of strings
386 30e42c4e Guido Trotter
    @param incoming: (target_host_ip, port)
387 30e42c4e Guido Trotter

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

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

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

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

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

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

519 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
520 30e42c4e Guido Trotter
    @param instance: instance to be migrated
521 30e42c4e Guido Trotter
    @rtype: string
522 30e42c4e Guido Trotter
    @return: content of the KVM runtime file
523 30e42c4e Guido Trotter

524 30e42c4e Guido Trotter
    """
525 30e42c4e Guido Trotter
    return self._ReadKVMRuntime(instance.name)
526 30e42c4e Guido Trotter
527 30e42c4e Guido Trotter
  def AcceptInstance(self, instance, info, target):
528 30e42c4e Guido Trotter
    """Prepare to accept an instance.
529 30e42c4e Guido Trotter

530 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
531 30e42c4e Guido Trotter
    @param instance: instance to be accepted
532 30e42c4e Guido Trotter
    @type info: string
533 30e42c4e Guido Trotter
    @param info: content of the KVM runtime file on the source node
534 30e42c4e Guido Trotter
    @type target: string
535 30e42c4e Guido Trotter
    @param target: target host (usually ip), on this node
536 30e42c4e Guido Trotter

537 30e42c4e Guido Trotter
    """
538 30e42c4e Guido Trotter
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
539 30e42c4e Guido Trotter
    incoming_address = (target, constants.KVM_MIGRATION_PORT)
540 30e42c4e Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
541 30e42c4e Guido Trotter
542 30e42c4e Guido Trotter
  def FinalizeMigration(self, instance, info, success):
543 30e42c4e Guido Trotter
    """Finalize an instance migration.
544 30e42c4e Guido Trotter

545 30e42c4e Guido Trotter
    Stop the incoming mode KVM.
546 30e42c4e Guido Trotter

547 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
548 30e42c4e Guido Trotter
    @param instance: instance whose migration is being aborted
549 30e42c4e Guido Trotter

550 30e42c4e Guido Trotter
    """
551 30e42c4e Guido Trotter
    if success:
552 30e42c4e Guido Trotter
      self._WriteKVMRuntime(instance.name, info)
553 30e42c4e Guido Trotter
    else:
554 30e42c4e Guido Trotter
      self.StopInstance(instance, force=True)
555 30e42c4e Guido Trotter
556 30e42c4e Guido Trotter
  def MigrateInstance(self, instance_name, target, live):
557 30e42c4e Guido Trotter
    """Migrate an instance to a target node.
558 30e42c4e Guido Trotter

559 30e42c4e Guido Trotter
    The migration will not be attempted if the instance is not
560 30e42c4e Guido Trotter
    currently running.
561 30e42c4e Guido Trotter

562 30e42c4e Guido Trotter
    @type instance_name: string
563 30e42c4e Guido Trotter
    @param instance_name: name of the instance to be migrated
564 30e42c4e Guido Trotter
    @type target: string
565 30e42c4e Guido Trotter
    @param target: ip address of the target node
566 30e42c4e Guido Trotter
    @type live: boolean
567 30e42c4e Guido Trotter
    @param live: perform a live migration
568 30e42c4e Guido Trotter

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

613 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
614 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
615 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
616 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
617 eb58f9b1 Guido Trotter

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

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

699 eb58f9b1 Guido Trotter
    Check that the binary exists.
700 eb58f9b1 Guido Trotter

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

712 6b5605e8 Iustin Pop
    For the KVM hypervisor, this only check the existence of the
713 6b5605e8 Iustin Pop
    kernel.
714 6b5605e8 Iustin Pop

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

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

790 6b5605e8 Iustin Pop
    For the KVM hypervisor, this checks the existence of the
791 6b5605e8 Iustin Pop
    kernel.
792 6b5605e8 Iustin Pop

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