Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 8b2d1013

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

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

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

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

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

108 eb58f9b1 Guido Trotter
    This can be used by any qemu-type hypervisor.
109 eb58f9b1 Guido Trotter

110 eb58f9b1 Guido Trotter
    @param instance: instance we're acting on
111 eb58f9b1 Guido Trotter
    @type instance: instance object
112 eb58f9b1 Guido Trotter
    @param seq: nic sequence number
113 eb58f9b1 Guido Trotter
    @type seq: int
114 eb58f9b1 Guido Trotter
    @param nic: nic we're acting on
115 eb58f9b1 Guido Trotter
    @type nic: nic object
116 eb58f9b1 Guido Trotter
    @return: netscript file name
117 eb58f9b1 Guido Trotter
    @rtype: string
118 eb58f9b1 Guido Trotter

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

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

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

163 c41eea6e Iustin Pop
    @param instance_name: the instance name
164 c41eea6e Iustin Pop

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

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

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

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

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

322 38e250ba Guido Trotter
    """
323 38e250ba Guido Trotter
    try:
324 38e250ba Guido Trotter
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
325 38e250ba Guido Trotter
                      data=data)
326 90c024f6 Guido Trotter
    except EnvironmentError, err:
327 38e250ba Guido Trotter
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
328 38e250ba Guido Trotter
329 38e250ba Guido Trotter
  def _ReadKVMRuntime(self, instance_name):
330 38e250ba Guido Trotter
    """Read an instance's KVM runtime
331 38e250ba Guido Trotter

332 38e250ba Guido Trotter
    """
333 38e250ba Guido Trotter
    try:
334 38e250ba Guido Trotter
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
335 90c024f6 Guido Trotter
    except EnvironmentError, err:
336 38e250ba Guido Trotter
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
337 38e250ba Guido Trotter
    return file_content
338 38e250ba Guido Trotter
339 38e250ba Guido Trotter
  def _SaveKVMRuntime(self, instance, kvm_runtime):
340 38e250ba Guido Trotter
    """Save an instance's KVM runtime
341 38e250ba Guido Trotter

342 38e250ba Guido Trotter
    """
343 38e250ba Guido Trotter
    kvm_cmd, kvm_nics = kvm_runtime
344 38e250ba Guido Trotter
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
345 38e250ba Guido Trotter
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics))
346 38e250ba Guido Trotter
    self._WriteKVMRuntime(instance.name, serialized_form)
347 38e250ba Guido Trotter
348 30e42c4e Guido Trotter
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
349 38e250ba Guido Trotter
    """Load an instance's KVM runtime
350 38e250ba Guido Trotter

351 38e250ba Guido Trotter
    """
352 30e42c4e Guido Trotter
    if not serialized_runtime:
353 30e42c4e Guido Trotter
      serialized_runtime = self._ReadKVMRuntime(instance.name)
354 30e42c4e Guido Trotter
    loaded_runtime = serializer.Load(serialized_runtime)
355 38e250ba Guido Trotter
    kvm_cmd, serialized_nics = loaded_runtime
356 38e250ba Guido Trotter
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
357 38e250ba Guido Trotter
    return (kvm_cmd, kvm_nics)
358 38e250ba Guido Trotter
359 30e42c4e Guido Trotter
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
360 ee5f20b0 Guido Trotter
    """Execute a KVM cmd, after completing it with some last minute data
361 ee5f20b0 Guido Trotter

362 30e42c4e Guido Trotter
    @type incoming: tuple of strings
363 30e42c4e Guido Trotter
    @param incoming: (target_host_ip, port)
364 30e42c4e Guido Trotter

365 ee5f20b0 Guido Trotter
    """
366 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
367 1f8b3a27 Guido Trotter
    if alive:
368 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
369 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
370 ee5f20b0 Guido Trotter
371 ee5f20b0 Guido Trotter
    temp_files = []
372 ee5f20b0 Guido Trotter
373 ee5f20b0 Guido Trotter
    kvm_cmd, kvm_nics = kvm_runtime
374 ee5f20b0 Guido Trotter
375 ee5f20b0 Guido Trotter
    if not kvm_nics:
376 ee5f20b0 Guido Trotter
      kvm_cmd.extend(['-net', 'none'])
377 ee5f20b0 Guido Trotter
    else:
378 ee5f20b0 Guido Trotter
      for nic_seq, nic in enumerate(kvm_nics):
379 ee5f20b0 Guido Trotter
        nic_val = "nic,macaddr=%s,model=virtio" % nic.mac
380 ee5f20b0 Guido Trotter
        script = self._WriteNetScript(instance, nic_seq, nic)
381 ee5f20b0 Guido Trotter
        kvm_cmd.extend(['-net', nic_val])
382 ee5f20b0 Guido Trotter
        kvm_cmd.extend(['-net', 'tap,script=%s' % script])
383 ee5f20b0 Guido Trotter
        temp_files.append(script)
384 ee5f20b0 Guido Trotter
385 30e42c4e Guido Trotter
    if incoming:
386 30e42c4e Guido Trotter
      target, port = incoming
387 30e42c4e Guido Trotter
      kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
388 30e42c4e Guido Trotter
389 eb58f9b1 Guido Trotter
    result = utils.RunCmd(kvm_cmd)
390 eb58f9b1 Guido Trotter
    if result.failed:
391 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
392 eb58f9b1 Guido Trotter
                                   (instance.name, result.fail_reason,
393 eb58f9b1 Guido Trotter
                                    result.output))
394 eb58f9b1 Guido Trotter
395 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
396 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
397 eb58f9b1 Guido Trotter
                                   (instance.name))
398 eb58f9b1 Guido Trotter
399 08137f9e Iustin Pop
    for filename in temp_files:
400 08137f9e Iustin Pop
      utils.RemoveFile(filename)
401 eb58f9b1 Guido Trotter
402 ee5f20b0 Guido Trotter
  def StartInstance(self, instance, block_devices, extra_args):
403 ee5f20b0 Guido Trotter
    """Start an instance.
404 ee5f20b0 Guido Trotter

405 ee5f20b0 Guido Trotter
    """
406 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
407 1f8b3a27 Guido Trotter
    if alive:
408 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
409 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
410 ee5f20b0 Guido Trotter
411 ee5f20b0 Guido Trotter
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices, extra_args)
412 38e250ba Guido Trotter
    self._SaveKVMRuntime(instance, kvm_runtime)
413 ee5f20b0 Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime)
414 ee5f20b0 Guido Trotter
415 6567aff3 Guido Trotter
  def _CallMonitorCommand(self, instance_name, command):
416 6567aff3 Guido Trotter
    """Invoke a command on the instance monitor.
417 6567aff3 Guido Trotter

418 6567aff3 Guido Trotter
    """
419 6567aff3 Guido Trotter
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
420 6567aff3 Guido Trotter
             (utils.ShellQuote(command),
421 6567aff3 Guido Trotter
              constants.SOCAT_PATH,
422 6567aff3 Guido Trotter
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
423 6567aff3 Guido Trotter
    result = utils.RunCmd(socat)
424 6567aff3 Guido Trotter
    if result.failed:
425 6567aff3 Guido Trotter
      msg = ("Failed to send command '%s' to instance %s."
426 6567aff3 Guido Trotter
             " output: %s, error: %s, fail_reason: %s" %
427 6567aff3 Guido Trotter
             (instance.name, result.stdout, result.stderr, result.fail_reason))
428 6567aff3 Guido Trotter
      raise errors.HypervisorError(msg)
429 6567aff3 Guido Trotter
430 6567aff3 Guido Trotter
    return result
431 6567aff3 Guido Trotter
432 6567aff3 Guido Trotter
  def _RetryInstancePowerdown(self, instance, pid, timeout=30):
433 6567aff3 Guido Trotter
    """Wait for an instance  to power down.
434 6567aff3 Guido Trotter

435 6567aff3 Guido Trotter
    """
436 6567aff3 Guido Trotter
    # Wait up to $timeout seconds
437 6567aff3 Guido Trotter
    end = time.time() + timeout
438 6567aff3 Guido Trotter
    wait = 1
439 6567aff3 Guido Trotter
    while time.time() < end and utils.IsProcessAlive(pid):
440 6567aff3 Guido Trotter
      self._CallMonitorCommand(instance.name, 'system_powerdown')
441 6567aff3 Guido Trotter
      time.sleep(wait)
442 6567aff3 Guido Trotter
      # Make wait time longer for next try
443 6567aff3 Guido Trotter
      if wait < 5:
444 6567aff3 Guido Trotter
        wait *= 1.3
445 6567aff3 Guido Trotter
446 eb58f9b1 Guido Trotter
  def StopInstance(self, instance, force=False):
447 eb58f9b1 Guido Trotter
    """Stop an instance.
448 eb58f9b1 Guido Trotter

449 eb58f9b1 Guido Trotter
    """
450 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
451 1f8b3a27 Guido Trotter
    if pid > 0 and alive:
452 6b5605e8 Iustin Pop
      if force or not instance.hvparams[constants.HV_ACPI]:
453 eb58f9b1 Guido Trotter
        utils.KillProcess(pid)
454 eb58f9b1 Guido Trotter
      else:
455 6567aff3 Guido Trotter
        self._RetryInstancePowerdown(instance, pid)
456 eb58f9b1 Guido Trotter
457 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(pid):
458 1f8b3a27 Guido Trotter
      utils.RemoveFile(pidfile)
459 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceMonitor(instance.name))
460 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceSerial(instance.name))
461 38e250ba Guido Trotter
      utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
462 6567aff3 Guido Trotter
      return True
463 6567aff3 Guido Trotter
    else:
464 6567aff3 Guido Trotter
      return False
465 eb58f9b1 Guido Trotter
466 eb58f9b1 Guido Trotter
  def RebootInstance(self, instance):
467 eb58f9b1 Guido Trotter
    """Reboot an instance.
468 eb58f9b1 Guido Trotter

469 eb58f9b1 Guido Trotter
    """
470 eb58f9b1 Guido Trotter
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
471 eb58f9b1 Guido Trotter
    # socket the instance will stop, but now power up again. So we'll resort
472 eb58f9b1 Guido Trotter
    # to shutdown and restart.
473 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
474 1f8b3a27 Guido Trotter
    if not alive:
475 1f8b3a27 Guido Trotter
      raise errors.HypervisorError("Failed to reboot instance %s: not running" %
476 1f8b3a27 Guido Trotter
                                             (instance.name))
477 f02881e0 Guido Trotter
    # StopInstance will delete the saved KVM runtime so:
478 f02881e0 Guido Trotter
    # ...first load it...
479 f02881e0 Guido Trotter
    kvm_runtime = self._LoadKVMRuntime(instance)
480 f02881e0 Guido Trotter
    # ...now we can safely call StopInstance...
481 f02881e0 Guido Trotter
    if not self.StopInstance(instance):
482 f02881e0 Guido Trotter
      self.StopInstance(instance, force=True)
483 f02881e0 Guido Trotter
    # ...and finally we can save it again, and execute it...
484 f02881e0 Guido Trotter
    self._SaveKVMRuntime(instance, kvm_runtime)
485 f02881e0 Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime)
486 eb58f9b1 Guido Trotter
487 30e42c4e Guido Trotter
  def MigrationInfo(self, instance):
488 30e42c4e Guido Trotter
    """Get instance information to perform a migration.
489 30e42c4e Guido Trotter

490 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
491 30e42c4e Guido Trotter
    @param instance: instance to be migrated
492 30e42c4e Guido Trotter
    @rtype: string
493 30e42c4e Guido Trotter
    @return: content of the KVM runtime file
494 30e42c4e Guido Trotter

495 30e42c4e Guido Trotter
    """
496 30e42c4e Guido Trotter
    return self._ReadKVMRuntime(instance.name)
497 30e42c4e Guido Trotter
498 30e42c4e Guido Trotter
  def AcceptInstance(self, instance, info, target):
499 30e42c4e Guido Trotter
    """Prepare to accept an instance.
500 30e42c4e Guido Trotter

501 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
502 30e42c4e Guido Trotter
    @param instance: instance to be accepted
503 30e42c4e Guido Trotter
    @type info: string
504 30e42c4e Guido Trotter
    @param info: content of the KVM runtime file on the source node
505 30e42c4e Guido Trotter
    @type target: string
506 30e42c4e Guido Trotter
    @param target: target host (usually ip), on this node
507 30e42c4e Guido Trotter

508 30e42c4e Guido Trotter
    """
509 30e42c4e Guido Trotter
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
510 30e42c4e Guido Trotter
    incoming_address = (target, constants.KVM_MIGRATION_PORT)
511 30e42c4e Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
512 30e42c4e Guido Trotter
513 30e42c4e Guido Trotter
  def FinalizeMigration(self, instance, info, success):
514 30e42c4e Guido Trotter
    """Finalize an instance migration.
515 30e42c4e Guido Trotter

516 30e42c4e Guido Trotter
    Stop the incoming mode KVM.
517 30e42c4e Guido Trotter

518 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
519 30e42c4e Guido Trotter
    @param instance: instance whose migration is being aborted
520 30e42c4e Guido Trotter

521 30e42c4e Guido Trotter
    """
522 30e42c4e Guido Trotter
    if success:
523 30e42c4e Guido Trotter
      self._WriteKVMRuntime(instance.name, info)
524 30e42c4e Guido Trotter
    else:
525 30e42c4e Guido Trotter
      self.StopInstance(instance, force=True)
526 30e42c4e Guido Trotter
527 30e42c4e Guido Trotter
  def MigrateInstance(self, instance_name, target, live):
528 30e42c4e Guido Trotter
    """Migrate an instance to a target node.
529 30e42c4e Guido Trotter

530 30e42c4e Guido Trotter
    The migration will not be attempted if the instance is not
531 30e42c4e Guido Trotter
    currently running.
532 30e42c4e Guido Trotter

533 30e42c4e Guido Trotter
    @type instance_name: string
534 30e42c4e Guido Trotter
    @param instance_name: name of the instance to be migrated
535 30e42c4e Guido Trotter
    @type target: string
536 30e42c4e Guido Trotter
    @param target: ip address of the target node
537 30e42c4e Guido Trotter
    @type live: boolean
538 30e42c4e Guido Trotter
    @param live: perform a live migration
539 30e42c4e Guido Trotter

540 30e42c4e Guido Trotter
    """
541 30e42c4e Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
542 30e42c4e Guido Trotter
    if not alive:
543 30e42c4e Guido Trotter
      raise errors.HypervisorError("Instance not running, cannot migrate")
544 30e42c4e Guido Trotter
545 30e42c4e Guido Trotter
    if not live:
546 30e42c4e Guido Trotter
      self._CallMonitorCommand(instance_name, 'stop')
547 30e42c4e Guido Trotter
548 30e42c4e Guido Trotter
    migrate_command = ('migrate -d tcp:%s:%s' %
549 30e42c4e Guido Trotter
                       (target, constants.KVM_MIGRATION_PORT))
550 30e42c4e Guido Trotter
    self._CallMonitorCommand(instance_name, migrate_command)
551 30e42c4e Guido Trotter
552 30e42c4e Guido Trotter
    info_command = 'info migrate'
553 30e42c4e Guido Trotter
    done = False
554 30e42c4e Guido Trotter
    while not done:
555 30e42c4e Guido Trotter
      result = self._CallMonitorCommand(instance_name, info_command)
556 30e42c4e Guido Trotter
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
557 30e42c4e Guido Trotter
      if not match:
558 30e42c4e Guido Trotter
        raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
559 30e42c4e Guido Trotter
                                     result.stdout)
560 30e42c4e Guido Trotter
      else:
561 30e42c4e Guido Trotter
        status = match.group(1)
562 30e42c4e Guido Trotter
        if status == 'completed':
563 30e42c4e Guido Trotter
          done = True
564 30e42c4e Guido Trotter
        elif status == 'active':
565 30e42c4e Guido Trotter
          time.sleep(2)
566 c087266c Guido Trotter
        elif status == 'failed' or status == 'cancelled':
567 c087266c Guido Trotter
          if not live:
568 c087266c Guido Trotter
            self._CallMonitorCommand(instance_name, 'cont')
569 c087266c Guido Trotter
          raise errors.HypervisorError("Migration %s at the kvm level" %
570 c087266c Guido Trotter
                                       status)
571 30e42c4e Guido Trotter
        else:
572 30e42c4e Guido Trotter
          logging.info("KVM: unknown migration status '%s'" % status)
573 30e42c4e Guido Trotter
          time.sleep(2)
574 30e42c4e Guido Trotter
575 30e42c4e Guido Trotter
    utils.KillProcess(pid)
576 30e42c4e Guido Trotter
    utils.RemoveFile(pidfile)
577 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceMonitor(instance_name))
578 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceSerial(instance_name))
579 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceKVMRuntime(instance_name))
580 30e42c4e Guido Trotter
581 eb58f9b1 Guido Trotter
  def GetNodeInfo(self):
582 eb58f9b1 Guido Trotter
    """Return information about the node.
583 eb58f9b1 Guido Trotter

584 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
585 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
586 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
587 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
588 eb58f9b1 Guido Trotter

589 eb58f9b1 Guido Trotter
    """
590 eb58f9b1 Guido Trotter
    # global ram usage from the xm info command
591 eb58f9b1 Guido Trotter
    # memory                 : 3583
592 eb58f9b1 Guido Trotter
    # free_memory            : 747
593 eb58f9b1 Guido Trotter
    # note: in xen 3, memory has changed to total_memory
594 eb58f9b1 Guido Trotter
    try:
595 eb58f9b1 Guido Trotter
      fh = file("/proc/meminfo")
596 eb58f9b1 Guido Trotter
      try:
597 eb58f9b1 Guido Trotter
        data = fh.readlines()
598 eb58f9b1 Guido Trotter
      finally:
599 eb58f9b1 Guido Trotter
        fh.close()
600 90c024f6 Guido Trotter
    except EnvironmentError, err:
601 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
602 eb58f9b1 Guido Trotter
603 eb58f9b1 Guido Trotter
    result = {}
604 eb58f9b1 Guido Trotter
    sum_free = 0
605 eb58f9b1 Guido Trotter
    for line in data:
606 eb58f9b1 Guido Trotter
      splitfields = line.split(":", 1)
607 eb58f9b1 Guido Trotter
608 eb58f9b1 Guido Trotter
      if len(splitfields) > 1:
609 eb58f9b1 Guido Trotter
        key = splitfields[0].strip()
610 eb58f9b1 Guido Trotter
        val = splitfields[1].strip()
611 eb58f9b1 Guido Trotter
        if key == 'MemTotal':
612 eb58f9b1 Guido Trotter
          result['memory_total'] = int(val.split()[0])/1024
613 eb58f9b1 Guido Trotter
        elif key in ('MemFree', 'Buffers', 'Cached'):
614 eb58f9b1 Guido Trotter
          sum_free += int(val.split()[0])/1024
615 eb58f9b1 Guido Trotter
        elif key == 'Active':
616 eb58f9b1 Guido Trotter
          result['memory_dom0'] = int(val.split()[0])/1024
617 eb58f9b1 Guido Trotter
    result['memory_free'] = sum_free
618 eb58f9b1 Guido Trotter
619 eb58f9b1 Guido Trotter
    cpu_total = 0
620 eb58f9b1 Guido Trotter
    try:
621 eb58f9b1 Guido Trotter
      fh = open("/proc/cpuinfo")
622 eb58f9b1 Guido Trotter
      try:
623 eb58f9b1 Guido Trotter
        cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
624 eb58f9b1 Guido Trotter
                                   fh.read()))
625 eb58f9b1 Guido Trotter
      finally:
626 eb58f9b1 Guido Trotter
        fh.close()
627 eb58f9b1 Guido Trotter
    except EnvironmentError, err:
628 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
629 eb58f9b1 Guido Trotter
    result['cpu_total'] = cpu_total
630 eb58f9b1 Guido Trotter
631 eb58f9b1 Guido Trotter
    return result
632 eb58f9b1 Guido Trotter
633 637ce7f9 Guido Trotter
  @classmethod
634 5431b2e4 Guido Trotter
  def GetShellCommandForConsole(cls, instance, hvparams, beparams):
635 eb58f9b1 Guido Trotter
    """Return a command for connecting to the console of an instance.
636 eb58f9b1 Guido Trotter

637 eb58f9b1 Guido Trotter
    """
638 a2faf9ee Guido Trotter
    if hvparams[constants.HV_SERIAL_CONSOLE]:
639 a2faf9ee Guido Trotter
      # FIXME: The socat shell is not perfect. In particular the way we start
640 a2faf9ee Guido Trotter
      # it ctrl+c will close it, rather than being passed to the other end.
641 a2faf9ee Guido Trotter
      # On the other hand if we pass the option 'raw' (or ignbrk=1) there
642 a2faf9ee Guido Trotter
      # will be no way of exiting socat (except killing it from another shell)
643 a2faf9ee Guido Trotter
      # and ctrl+c doesn't work anyway, printing ^C rather than being
644 a2faf9ee Guido Trotter
      # interpreted by kvm. For now we'll leave it this way, which at least
645 a2faf9ee Guido Trotter
      # allows a minimal interaction and changes on the machine.
646 a2faf9ee Guido Trotter
      shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
647 a2faf9ee Guido Trotter
                       (constants.SOCAT_PATH,
648 a2faf9ee Guido Trotter
                        utils.ShellQuote(cls._InstanceSerial(instance.name))))
649 a2faf9ee Guido Trotter
    else:
650 a2faf9ee Guido Trotter
      shell_command = "echo 'No serial shell for instance %s'" % instance.name
651 3be34f57 Guido Trotter
652 3be34f57 Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
653 3be34f57 Guido Trotter
    if vnc_bind_address:
654 3be34f57 Guido Trotter
      if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
655 3be34f57 Guido Trotter
        display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
656 3be34f57 Guido Trotter
        vnc_command = ("echo 'Instance has VNC listening on %s:%d"
657 3be34f57 Guido Trotter
                       " (display: %d)'" % (vnc_bind_address,
658 3be34f57 Guido Trotter
                                            instance.network_port,
659 3be34f57 Guido Trotter
                                            display))
660 3be34f57 Guido Trotter
        shell_command = "%s; %s" % (vnc_command, shell_command)
661 3be34f57 Guido Trotter
662 a2faf9ee Guido Trotter
    return shell_command
663 eb58f9b1 Guido Trotter
664 eb58f9b1 Guido Trotter
  def Verify(self):
665 eb58f9b1 Guido Trotter
    """Verify the hypervisor.
666 eb58f9b1 Guido Trotter

667 eb58f9b1 Guido Trotter
    Check that the binary exists.
668 eb58f9b1 Guido Trotter

669 eb58f9b1 Guido Trotter
    """
670 eb58f9b1 Guido Trotter
    if not os.path.exists(constants.KVM_PATH):
671 eb58f9b1 Guido Trotter
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
672 14aa53cb Guido Trotter
    if not os.path.exists(constants.SOCAT_PATH):
673 14aa53cb Guido Trotter
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
674 14aa53cb Guido Trotter
675 6b5605e8 Iustin Pop
676 6b5605e8 Iustin Pop
  @classmethod
677 6b5605e8 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
678 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
679 6b5605e8 Iustin Pop

680 6b5605e8 Iustin Pop
    For the KVM hypervisor, this only check the existence of the
681 6b5605e8 Iustin Pop
    kernel.
682 6b5605e8 Iustin Pop

683 6b5605e8 Iustin Pop
    @type hvparams:  dict
684 6b5605e8 Iustin Pop
    @param hvparams: dictionary with parameter names/value
685 6b5605e8 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
686 6b5605e8 Iustin Pop

687 6b5605e8 Iustin Pop
    """
688 47387b1e Guido Trotter
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
689 6b5605e8 Iustin Pop
690 df5ab9f0 Guido Trotter
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
691 df5ab9f0 Guido Trotter
    if kernel_path:
692 df5ab9f0 Guido Trotter
      if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
693 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("The kernel path must be an absolute path"
694 df5ab9f0 Guido Trotter
                                     ", if defined")
695 6b5605e8 Iustin Pop
696 df5ab9f0 Guido Trotter
      if not hvparams[constants.HV_ROOT_PATH]:
697 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("Need a root partition for the instance"
698 df5ab9f0 Guido Trotter
                                     ", if a kernel is defined")
699 074ca009 Guido Trotter
700 6b5605e8 Iustin Pop
    if hvparams[constants.HV_INITRD_PATH]:
701 6b5605e8 Iustin Pop
      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
702 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("The initrd path must an absolute path"
703 6b5605e8 Iustin Pop
                                     ", if defined")
704 6b5605e8 Iustin Pop
705 56fee73b Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
706 56fee73b Guido Trotter
    if vnc_bind_address:
707 56fee73b Guido Trotter
      if not utils.IsValidIP(vnc_bind_address):
708 8447f52b Guido Trotter
        if not os.path.isabs(vnc_bind_address):
709 8447f52b Guido Trotter
          raise errors.HypervisorError("The VNC bind address must be either"
710 8447f52b Guido Trotter
                                       " a valid IP address or an absolute"
711 8447f52b Guido Trotter
                                       " pathname. '%s' given" %
712 8447f52b Guido Trotter
                                       vnc_bind_address)
713 56fee73b Guido Trotter
714 8b2d1013 Guido Trotter
    if hvparams[constants.HV_VNC_X509_VERIFY] and \
715 8b2d1013 Guido Trotter
      not hvparams[constants.HV_VNC_X509]:
716 8b2d1013 Guido Trotter
        raise errors.HypervisorError("%s must be defined, if %s is" %
717 8b2d1013 Guido Trotter
                                     (constants.HV_VNC_X509,
718 8b2d1013 Guido Trotter
                                      constants.HV_VNC_X509_VERIFY))
719 8b2d1013 Guido Trotter
720 8b2d1013 Guido Trotter
    if hvparams[constants.HV_VNC_X509]:
721 8b2d1013 Guido Trotter
      if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
722 8b2d1013 Guido Trotter
        raise errors.HypervisorError("The vnc x509 path must an absolute path"
723 8b2d1013 Guido Trotter
                                     ", if defined")
724 8b2d1013 Guido Trotter
725 6b5605e8 Iustin Pop
  def ValidateParameters(self, hvparams):
726 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
727 6b5605e8 Iustin Pop

728 6b5605e8 Iustin Pop
    For the KVM hypervisor, this checks the existence of the
729 6b5605e8 Iustin Pop
    kernel.
730 6b5605e8 Iustin Pop

731 6b5605e8 Iustin Pop
    """
732 47387b1e Guido Trotter
    super(KVMHypervisor, self).ValidateParameters(hvparams)
733 6b5605e8 Iustin Pop
734 6b5605e8 Iustin Pop
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
735 df5ab9f0 Guido Trotter
    if kernel_path and not os.path.isfile(kernel_path):
736 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance kernel '%s' not found or"
737 6b5605e8 Iustin Pop
                                   " not a file" % kernel_path)
738 6b5605e8 Iustin Pop
    initrd_path = hvparams[constants.HV_INITRD_PATH]
739 6b5605e8 Iustin Pop
    if initrd_path and not os.path.isfile(initrd_path):
740 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance initrd '%s' not found or"
741 6b5605e8 Iustin Pop
                                   " not a file" % initrd_path)
742 8b2d1013 Guido Trotter
743 8b2d1013 Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
744 8b2d1013 Guido Trotter
    if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
745 8b2d1013 Guido Trotter
       not os.path.isdir(vnc_bind_address):
746 8b2d1013 Guido Trotter
       raise errors.HypervisorError("Instance vnc bind address must be either"
747 8b2d1013 Guido Trotter
                                    " an ip address or an existing directory")
748 8b2d1013 Guido Trotter
749 8b2d1013 Guido Trotter
    vnc_x509 = hvparams[constants.HV_VNC_X509]
750 8b2d1013 Guido Trotter
    if vnc_x509 and not os.path.isdir(vnc_x509):
751 8b2d1013 Guido Trotter
      raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
752 8b2d1013 Guido Trotter
                                   " or not a directory" % vnc_x509)