Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 6567aff3

History | View | Annotate | Download (16.4 kB)

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

24 eb58f9b1 Guido Trotter
"""
25 eb58f9b1 Guido Trotter
26 eb58f9b1 Guido Trotter
import os
27 eb58f9b1 Guido Trotter
import os.path
28 eb58f9b1 Guido Trotter
import re
29 eb58f9b1 Guido Trotter
import tempfile
30 6567aff3 Guido Trotter
import time
31 eb58f9b1 Guido Trotter
from cStringIO import StringIO
32 eb58f9b1 Guido Trotter
33 eb58f9b1 Guido Trotter
from ganeti import utils
34 eb58f9b1 Guido Trotter
from ganeti import constants
35 eb58f9b1 Guido Trotter
from ganeti import errors
36 38e250ba Guido Trotter
from ganeti import serializer
37 38e250ba Guido Trotter
from ganeti import objects
38 eb58f9b1 Guido Trotter
from ganeti.hypervisor import hv_base
39 eb58f9b1 Guido Trotter
40 eb58f9b1 Guido Trotter
41 eb58f9b1 Guido Trotter
class KVMHypervisor(hv_base.BaseHypervisor):
42 c4469f75 Guido Trotter
  """KVM hypervisor interface"""
43 eb58f9b1 Guido Trotter
44 eb58f9b1 Guido Trotter
  _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
45 a1d79fc6 Guido Trotter
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
46 a1d79fc6 Guido Trotter
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
47 a1d79fc6 Guido Trotter
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
48 a1d79fc6 Guido Trotter
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _CTRL_DIR, _CONF_DIR]
49 eb58f9b1 Guido Trotter
50 6b5605e8 Iustin Pop
  PARAMETERS = [
51 6b5605e8 Iustin Pop
    constants.HV_KERNEL_PATH,
52 6b5605e8 Iustin Pop
    constants.HV_INITRD_PATH,
53 6b5605e8 Iustin Pop
    constants.HV_ACPI,
54 6b5605e8 Iustin Pop
    ]
55 6b5605e8 Iustin Pop
56 eb58f9b1 Guido Trotter
  def __init__(self):
57 eb58f9b1 Guido Trotter
    hv_base.BaseHypervisor.__init__(self)
58 eb58f9b1 Guido Trotter
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
59 eb58f9b1 Guido Trotter
    # in a tmpfs filesystem or has been otherwise wiped out.
60 08137f9e Iustin Pop
    for mydir in self._DIRS:
61 08137f9e Iustin Pop
      if not os.path.exists(mydir):
62 08137f9e Iustin Pop
        os.mkdir(mydir)
63 eb58f9b1 Guido Trotter
64 c4fbefc8 Guido Trotter
  def _InstanceMonitor(self, instance_name):
65 c4fbefc8 Guido Trotter
    """Returns the instance monitor socket name
66 c4fbefc8 Guido Trotter

67 c4fbefc8 Guido Trotter
    """
68 c4fbefc8 Guido Trotter
    return '%s/%s.monitor' % (self._CTRL_DIR, instance_name)
69 c4fbefc8 Guido Trotter
70 c4fbefc8 Guido Trotter
  def _InstanceSerial(self, instance_name):
71 c4fbefc8 Guido Trotter
    """Returns the instance serial socket name
72 c4fbefc8 Guido Trotter

73 c4fbefc8 Guido Trotter
    """
74 c4fbefc8 Guido Trotter
    return '%s/%s.serial' % (self._CTRL_DIR, instance_name)
75 c4fbefc8 Guido Trotter
76 38e250ba Guido Trotter
  def _InstanceKVMRuntime(self, instance_name):
77 38e250ba Guido Trotter
    """Returns the instance KVM runtime filename
78 38e250ba Guido Trotter

79 38e250ba Guido Trotter
    """
80 38e250ba Guido Trotter
    return '%s/%s.runtime' % (self._CONF_DIR, instance_name)
81 38e250ba Guido Trotter
82 eb58f9b1 Guido Trotter
  def _WriteNetScript(self, instance, seq, nic):
83 eb58f9b1 Guido Trotter
    """Write a script to connect a net interface to the proper bridge.
84 eb58f9b1 Guido Trotter

85 eb58f9b1 Guido Trotter
    This can be used by any qemu-type hypervisor.
86 eb58f9b1 Guido Trotter

87 eb58f9b1 Guido Trotter
    @param instance: instance we're acting on
88 eb58f9b1 Guido Trotter
    @type instance: instance object
89 eb58f9b1 Guido Trotter
    @param seq: nic sequence number
90 eb58f9b1 Guido Trotter
    @type seq: int
91 eb58f9b1 Guido Trotter
    @param nic: nic we're acting on
92 eb58f9b1 Guido Trotter
    @type nic: nic object
93 eb58f9b1 Guido Trotter
    @return: netscript file name
94 eb58f9b1 Guido Trotter
    @rtype: string
95 eb58f9b1 Guido Trotter

96 eb58f9b1 Guido Trotter
    """
97 eb58f9b1 Guido Trotter
    script = StringIO()
98 eb58f9b1 Guido Trotter
    script.write("#!/bin/sh\n")
99 eb58f9b1 Guido Trotter
    script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
100 eb58f9b1 Guido Trotter
    script.write("export INSTANCE=%s\n" % instance.name)
101 eb58f9b1 Guido Trotter
    script.write("export MAC=%s\n" % nic.mac)
102 eb58f9b1 Guido Trotter
    script.write("export IP=%s\n" % nic.ip)
103 eb58f9b1 Guido Trotter
    script.write("export BRIDGE=%s\n" % nic.bridge)
104 eb58f9b1 Guido Trotter
    script.write("export INTERFACE=$1\n")
105 eb58f9b1 Guido Trotter
    # TODO: make this configurable at ./configure time
106 eb58f9b1 Guido Trotter
    script.write("if [ -x /etc/ganeti/kvm-vif-bridge ]; then\n")
107 eb58f9b1 Guido Trotter
    script.write("  # Execute the user-specific vif file\n")
108 eb58f9b1 Guido Trotter
    script.write("  /etc/ganeti/kvm-vif-bridge\n")
109 eb58f9b1 Guido Trotter
    script.write("else\n")
110 eb58f9b1 Guido Trotter
    script.write("  # Connect the interface to the bridge\n")
111 eb58f9b1 Guido Trotter
    script.write("  /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
112 eb58f9b1 Guido Trotter
    script.write("  /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
113 eb58f9b1 Guido Trotter
    script.write("fi\n\n")
114 eb58f9b1 Guido Trotter
    # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
115 eb58f9b1 Guido Trotter
    # mounted noexec sometimes, so we'll have to find another place.
116 eb58f9b1 Guido Trotter
    (tmpfd, tmpfile_name) = tempfile.mkstemp()
117 eb58f9b1 Guido Trotter
    tmpfile = os.fdopen(tmpfd, 'w')
118 eb58f9b1 Guido Trotter
    tmpfile.write(script.getvalue())
119 eb58f9b1 Guido Trotter
    tmpfile.close()
120 eb58f9b1 Guido Trotter
    os.chmod(tmpfile_name, 0755)
121 eb58f9b1 Guido Trotter
    return tmpfile_name
122 eb58f9b1 Guido Trotter
123 eb58f9b1 Guido Trotter
  def ListInstances(self):
124 eb58f9b1 Guido Trotter
    """Get the list of running instances.
125 eb58f9b1 Guido Trotter

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

129 eb58f9b1 Guido Trotter
    """
130 eb58f9b1 Guido Trotter
    result = []
131 eb58f9b1 Guido Trotter
    for name in os.listdir(self._PIDS_DIR):
132 08137f9e Iustin Pop
      filename = "%s/%s" % (self._PIDS_DIR, name)
133 08137f9e Iustin Pop
      if utils.IsProcessAlive(utils.ReadPidFile(filename)):
134 eb58f9b1 Guido Trotter
        result.append(name)
135 eb58f9b1 Guido Trotter
    return result
136 eb58f9b1 Guido Trotter
137 eb58f9b1 Guido Trotter
  def GetInstanceInfo(self, instance_name):
138 eb58f9b1 Guido Trotter
    """Get instance properties.
139 eb58f9b1 Guido Trotter

140 c41eea6e Iustin Pop
    @param instance_name: the instance name
141 c41eea6e Iustin Pop

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

144 eb58f9b1 Guido Trotter
    """
145 eb58f9b1 Guido Trotter
    pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
146 eb58f9b1 Guido Trotter
    pid = utils.ReadPidFile(pidfile)
147 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(pid):
148 eb58f9b1 Guido Trotter
      return None
149 eb58f9b1 Guido Trotter
150 eb58f9b1 Guido Trotter
    cmdline_file = "/proc/%s/cmdline" % pid
151 eb58f9b1 Guido Trotter
    try:
152 eb58f9b1 Guido Trotter
      fh = open(cmdline_file, 'r')
153 eb58f9b1 Guido Trotter
      try:
154 eb58f9b1 Guido Trotter
        cmdline = fh.read()
155 eb58f9b1 Guido Trotter
      finally:
156 eb58f9b1 Guido Trotter
        fh.close()
157 eb58f9b1 Guido Trotter
    except IOError, err:
158 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list instance %s: %s" %
159 eb58f9b1 Guido Trotter
                                   (instance_name, err))
160 eb58f9b1 Guido Trotter
161 eb58f9b1 Guido Trotter
    memory = 0
162 eb58f9b1 Guido Trotter
    vcpus = 0
163 eb58f9b1 Guido Trotter
    stat = "---b-"
164 eb58f9b1 Guido Trotter
    times = "0"
165 eb58f9b1 Guido Trotter
166 eb58f9b1 Guido Trotter
    arg_list = cmdline.split('\x00')
167 eb58f9b1 Guido Trotter
    while arg_list:
168 eb58f9b1 Guido Trotter
      arg =  arg_list.pop(0)
169 eb58f9b1 Guido Trotter
      if arg == '-m':
170 eb58f9b1 Guido Trotter
        memory = arg_list.pop(0)
171 eb58f9b1 Guido Trotter
      elif arg == '-smp':
172 eb58f9b1 Guido Trotter
        vcpus = arg_list.pop(0)
173 eb58f9b1 Guido Trotter
174 eb58f9b1 Guido Trotter
    return (instance_name, pid, memory, vcpus, stat, times)
175 eb58f9b1 Guido Trotter
176 eb58f9b1 Guido Trotter
  def GetAllInstancesInfo(self):
177 eb58f9b1 Guido Trotter
    """Get properties of all instances.
178 eb58f9b1 Guido Trotter

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

181 eb58f9b1 Guido Trotter
    """
182 eb58f9b1 Guido Trotter
    data = []
183 eb58f9b1 Guido Trotter
    for name in os.listdir(self._PIDS_DIR):
184 08137f9e Iustin Pop
      filename = "%s/%s" % (self._PIDS_DIR, name)
185 08137f9e Iustin Pop
      if utils.IsProcessAlive(utils.ReadPidFile(filename)):
186 eb58f9b1 Guido Trotter
        data.append(self.GetInstanceInfo(name))
187 eb58f9b1 Guido Trotter
188 eb58f9b1 Guido Trotter
    return data
189 eb58f9b1 Guido Trotter
190 ee5f20b0 Guido Trotter
  def _GenerateKVMRuntime(self, instance, block_devices, extra_args):
191 ee5f20b0 Guido Trotter
    """Generate KVM information to start an instance.
192 eb58f9b1 Guido Trotter

193 eb58f9b1 Guido Trotter
    """
194 eb58f9b1 Guido Trotter
    pidfile = self._PIDS_DIR + "/%s" % instance.name
195 eb58f9b1 Guido Trotter
    kvm = constants.KVM_PATH
196 eb58f9b1 Guido Trotter
    kvm_cmd = [kvm]
197 8b3fd458 Iustin Pop
    kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
198 8b3fd458 Iustin Pop
    kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
199 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-pidfile', pidfile])
200 eb58f9b1 Guido Trotter
    # used just by the vnc server, if enabled
201 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-name', instance.name])
202 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-daemonize'])
203 6b5605e8 Iustin Pop
    if not instance.hvparams[constants.HV_ACPI]:
204 eb58f9b1 Guido Trotter
      kvm_cmd.extend(['-no-acpi'])
205 eb58f9b1 Guido Trotter
206 eb58f9b1 Guido Trotter
    boot_drive = True
207 069cfbf1 Iustin Pop
    for cfdev, dev_path in block_devices:
208 eb58f9b1 Guido Trotter
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
209 eb58f9b1 Guido Trotter
      if boot_drive:
210 eb58f9b1 Guido Trotter
        boot_val = ',boot=on'
211 d47d3d38 Guido Trotter
        boot_drive = False
212 eb58f9b1 Guido Trotter
      else:
213 eb58f9b1 Guido Trotter
        boot_val = ''
214 eb58f9b1 Guido Trotter
215 d47d3d38 Guido Trotter
      # TODO: handle different if= types
216 d47d3d38 Guido Trotter
      if_val = ',if=virtio'
217 d47d3d38 Guido Trotter
218 069cfbf1 Iustin Pop
      drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
219 eb58f9b1 Guido Trotter
      kvm_cmd.extend(['-drive', drive_val])
220 eb58f9b1 Guido Trotter
221 8a74a9b9 Guido Trotter
    kvm_cmd.extend(['-kernel', instance.hvparams[constants.HV_KERNEL_PATH]])
222 8a74a9b9 Guido Trotter
223 8a74a9b9 Guido Trotter
    initrd_path = instance.hvparams[constants.HV_INITRD_PATH]
224 eb58f9b1 Guido Trotter
    if initrd_path:
225 eb58f9b1 Guido Trotter
      kvm_cmd.extend(['-initrd', initrd_path])
226 eb58f9b1 Guido Trotter
227 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-append', 'console=ttyS0,38400 root=/dev/vda'])
228 eb58f9b1 Guido Trotter
229 eb58f9b1 Guido Trotter
    #"hvm_boot_order",
230 eb58f9b1 Guido Trotter
    #"hvm_cdrom_image_path",
231 eb58f9b1 Guido Trotter
232 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-nographic'])
233 eb58f9b1 Guido Trotter
    # FIXME: handle vnc, if needed
234 eb58f9b1 Guido Trotter
    # How do we decide whether to have it or not?? :(
235 eb58f9b1 Guido Trotter
    #"vnc_bind_address",
236 eb58f9b1 Guido Trotter
    #"network_port"
237 c4fbefc8 Guido Trotter
    monitor_dev = 'unix:%s,server,nowait' % \
238 c4fbefc8 Guido Trotter
      self._InstanceMonitor(instance.name)
239 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-monitor', monitor_dev])
240 c4fbefc8 Guido Trotter
    serial_dev = 'unix:%s,server,nowait' % self._InstanceSerial(instance.name)
241 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-serial', serial_dev])
242 eb58f9b1 Guido Trotter
243 ee5f20b0 Guido Trotter
    # Save the current instance nics, but defer their expansion as parameters,
244 ee5f20b0 Guido Trotter
    # as we'll need to generate executable temp files for them.
245 ee5f20b0 Guido Trotter
    kvm_nics = instance.nics
246 ee5f20b0 Guido Trotter
247 ee5f20b0 Guido Trotter
    return (kvm_cmd, kvm_nics)
248 ee5f20b0 Guido Trotter
249 38e250ba Guido Trotter
  def _WriteKVMRuntime(self, instance_name, data):
250 38e250ba Guido Trotter
    """Write an instance's KVM runtime
251 38e250ba Guido Trotter

252 38e250ba Guido Trotter
    """
253 38e250ba Guido Trotter
    try:
254 38e250ba Guido Trotter
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
255 38e250ba Guido Trotter
                      data=data)
256 38e250ba Guido Trotter
    except IOError, err:
257 38e250ba Guido Trotter
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
258 38e250ba Guido Trotter
259 38e250ba Guido Trotter
  def _ReadKVMRuntime(self, instance_name):
260 38e250ba Guido Trotter
    """Read an instance's KVM runtime
261 38e250ba Guido Trotter

262 38e250ba Guido Trotter
    """
263 38e250ba Guido Trotter
    try:
264 38e250ba Guido Trotter
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
265 38e250ba Guido Trotter
    except IOError, err:
266 38e250ba Guido Trotter
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
267 38e250ba Guido Trotter
    return file_content
268 38e250ba Guido Trotter
269 38e250ba Guido Trotter
  def _SaveKVMRuntime(self, instance, kvm_runtime):
270 38e250ba Guido Trotter
    """Save an instance's KVM runtime
271 38e250ba Guido Trotter

272 38e250ba Guido Trotter
    """
273 38e250ba Guido Trotter
    kvm_cmd, kvm_nics = kvm_runtime
274 38e250ba Guido Trotter
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
275 38e250ba Guido Trotter
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics))
276 38e250ba Guido Trotter
    self._WriteKVMRuntime(instance.name, serialized_form)
277 38e250ba Guido Trotter
278 38e250ba Guido Trotter
  def _LoadKVMRuntime(self, instance):
279 38e250ba Guido Trotter
    """Load an instance's KVM runtime
280 38e250ba Guido Trotter

281 38e250ba Guido Trotter
    """
282 38e250ba Guido Trotter
    serialized_form = self._ReadKVMRuntime(instance.name)
283 38e250ba Guido Trotter
    loaded_runtime = serializer.Load(serialized_form)
284 38e250ba Guido Trotter
    kvm_cmd, serialized_nics = loaded_runtime
285 38e250ba Guido Trotter
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
286 38e250ba Guido Trotter
    return (kvm_cmd, kvm_nics)
287 38e250ba Guido Trotter
288 ee5f20b0 Guido Trotter
  def _ExecuteKVMRuntime(self, instance, kvm_runtime):
289 ee5f20b0 Guido Trotter
    """Execute a KVM cmd, after completing it with some last minute data
290 ee5f20b0 Guido Trotter

291 ee5f20b0 Guido Trotter
    """
292 ee5f20b0 Guido Trotter
    pidfile = self._PIDS_DIR + "/%s" % instance.name
293 ee5f20b0 Guido Trotter
    if utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
294 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
295 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
296 ee5f20b0 Guido Trotter
297 ee5f20b0 Guido Trotter
    temp_files = []
298 ee5f20b0 Guido Trotter
299 ee5f20b0 Guido Trotter
    kvm_cmd, kvm_nics = kvm_runtime
300 ee5f20b0 Guido Trotter
301 ee5f20b0 Guido Trotter
    if not kvm_nics:
302 ee5f20b0 Guido Trotter
      kvm_cmd.extend(['-net', 'none'])
303 ee5f20b0 Guido Trotter
    else:
304 ee5f20b0 Guido Trotter
      for nic_seq, nic in enumerate(kvm_nics):
305 ee5f20b0 Guido Trotter
        nic_val = "nic,macaddr=%s,model=virtio" % nic.mac
306 ee5f20b0 Guido Trotter
        script = self._WriteNetScript(instance, nic_seq, nic)
307 ee5f20b0 Guido Trotter
        kvm_cmd.extend(['-net', nic_val])
308 ee5f20b0 Guido Trotter
        kvm_cmd.extend(['-net', 'tap,script=%s' % script])
309 ee5f20b0 Guido Trotter
        temp_files.append(script)
310 ee5f20b0 Guido Trotter
311 eb58f9b1 Guido Trotter
    result = utils.RunCmd(kvm_cmd)
312 eb58f9b1 Guido Trotter
    if result.failed:
313 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
314 eb58f9b1 Guido Trotter
                                   (instance.name, result.fail_reason,
315 eb58f9b1 Guido Trotter
                                    result.output))
316 eb58f9b1 Guido Trotter
317 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
318 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
319 eb58f9b1 Guido Trotter
                                   (instance.name))
320 eb58f9b1 Guido Trotter
321 08137f9e Iustin Pop
    for filename in temp_files:
322 08137f9e Iustin Pop
      utils.RemoveFile(filename)
323 eb58f9b1 Guido Trotter
324 ee5f20b0 Guido Trotter
  def StartInstance(self, instance, block_devices, extra_args):
325 ee5f20b0 Guido Trotter
    """Start an instance.
326 ee5f20b0 Guido Trotter

327 ee5f20b0 Guido Trotter
    """
328 ee5f20b0 Guido Trotter
    pidfile = self._PIDS_DIR + "/%s" % instance.name
329 ee5f20b0 Guido Trotter
    if utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
330 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
331 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
332 ee5f20b0 Guido Trotter
333 ee5f20b0 Guido Trotter
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices, extra_args)
334 38e250ba Guido Trotter
    self._SaveKVMRuntime(instance, kvm_runtime)
335 ee5f20b0 Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime)
336 ee5f20b0 Guido Trotter
337 6567aff3 Guido Trotter
  def _CallMonitorCommand(self, instance_name, command):
338 6567aff3 Guido Trotter
    """Invoke a command on the instance monitor.
339 6567aff3 Guido Trotter

340 6567aff3 Guido Trotter
    """
341 6567aff3 Guido Trotter
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
342 6567aff3 Guido Trotter
             (utils.ShellQuote(command),
343 6567aff3 Guido Trotter
              constants.SOCAT_PATH,
344 6567aff3 Guido Trotter
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
345 6567aff3 Guido Trotter
    result = utils.RunCmd(socat)
346 6567aff3 Guido Trotter
    if result.failed:
347 6567aff3 Guido Trotter
      msg = ("Failed to send command '%s' to instance %s."
348 6567aff3 Guido Trotter
             " output: %s, error: %s, fail_reason: %s" %
349 6567aff3 Guido Trotter
             (instance.name, result.stdout, result.stderr, result.fail_reason))
350 6567aff3 Guido Trotter
      raise errors.HypervisorError(msg)
351 6567aff3 Guido Trotter
352 6567aff3 Guido Trotter
    return result
353 6567aff3 Guido Trotter
354 6567aff3 Guido Trotter
  def _RetryInstancePowerdown(self, instance, pid, timeout=30):
355 6567aff3 Guido Trotter
    """Wait for an instance  to power down.
356 6567aff3 Guido Trotter

357 6567aff3 Guido Trotter
    """
358 6567aff3 Guido Trotter
    # Wait up to $timeout seconds
359 6567aff3 Guido Trotter
    end = time.time() + timeout
360 6567aff3 Guido Trotter
    wait = 1
361 6567aff3 Guido Trotter
    while time.time() < end and utils.IsProcessAlive(pid):
362 6567aff3 Guido Trotter
      self._CallMonitorCommand(instance.name, 'system_powerdown')
363 6567aff3 Guido Trotter
      time.sleep(wait)
364 6567aff3 Guido Trotter
      # Make wait time longer for next try
365 6567aff3 Guido Trotter
      if wait < 5:
366 6567aff3 Guido Trotter
        wait *= 1.3
367 6567aff3 Guido Trotter
368 eb58f9b1 Guido Trotter
  def StopInstance(self, instance, force=False):
369 eb58f9b1 Guido Trotter
    """Stop an instance.
370 eb58f9b1 Guido Trotter

371 eb58f9b1 Guido Trotter
    """
372 eb58f9b1 Guido Trotter
    pid_file = self._PIDS_DIR + "/%s" % instance.name
373 eb58f9b1 Guido Trotter
    pid = utils.ReadPidFile(pid_file)
374 eb58f9b1 Guido Trotter
    if pid > 0 and utils.IsProcessAlive(pid):
375 6b5605e8 Iustin Pop
      if force or not instance.hvparams[constants.HV_ACPI]:
376 eb58f9b1 Guido Trotter
        utils.KillProcess(pid)
377 eb58f9b1 Guido Trotter
      else:
378 6567aff3 Guido Trotter
        self._RetryInstancePowerdown(instance, pid)
379 eb58f9b1 Guido Trotter
380 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(pid):
381 eb58f9b1 Guido Trotter
      utils.RemoveFile(pid_file)
382 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceMonitor(instance.name))
383 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceSerial(instance.name))
384 38e250ba Guido Trotter
      utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
385 6567aff3 Guido Trotter
      return True
386 6567aff3 Guido Trotter
    else:
387 6567aff3 Guido Trotter
      return False
388 eb58f9b1 Guido Trotter
389 eb58f9b1 Guido Trotter
  def RebootInstance(self, instance):
390 eb58f9b1 Guido Trotter
    """Reboot an instance.
391 eb58f9b1 Guido Trotter

392 eb58f9b1 Guido Trotter
    """
393 eb58f9b1 Guido Trotter
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
394 eb58f9b1 Guido Trotter
    # socket the instance will stop, but now power up again. So we'll resort
395 eb58f9b1 Guido Trotter
    # to shutdown and restart.
396 eb58f9b1 Guido Trotter
    self.StopInstance(instance)
397 eb58f9b1 Guido Trotter
    self.StartInstance(instance)
398 eb58f9b1 Guido Trotter
399 eb58f9b1 Guido Trotter
  def GetNodeInfo(self):
400 eb58f9b1 Guido Trotter
    """Return information about the node.
401 eb58f9b1 Guido Trotter

402 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
403 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
404 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
405 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
406 eb58f9b1 Guido Trotter

407 eb58f9b1 Guido Trotter
    """
408 eb58f9b1 Guido Trotter
    # global ram usage from the xm info command
409 eb58f9b1 Guido Trotter
    # memory                 : 3583
410 eb58f9b1 Guido Trotter
    # free_memory            : 747
411 eb58f9b1 Guido Trotter
    # note: in xen 3, memory has changed to total_memory
412 eb58f9b1 Guido Trotter
    try:
413 eb58f9b1 Guido Trotter
      fh = file("/proc/meminfo")
414 eb58f9b1 Guido Trotter
      try:
415 eb58f9b1 Guido Trotter
        data = fh.readlines()
416 eb58f9b1 Guido Trotter
      finally:
417 eb58f9b1 Guido Trotter
        fh.close()
418 eb58f9b1 Guido Trotter
    except IOError, err:
419 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
420 eb58f9b1 Guido Trotter
421 eb58f9b1 Guido Trotter
    result = {}
422 eb58f9b1 Guido Trotter
    sum_free = 0
423 eb58f9b1 Guido Trotter
    for line in data:
424 eb58f9b1 Guido Trotter
      splitfields = line.split(":", 1)
425 eb58f9b1 Guido Trotter
426 eb58f9b1 Guido Trotter
      if len(splitfields) > 1:
427 eb58f9b1 Guido Trotter
        key = splitfields[0].strip()
428 eb58f9b1 Guido Trotter
        val = splitfields[1].strip()
429 eb58f9b1 Guido Trotter
        if key == 'MemTotal':
430 eb58f9b1 Guido Trotter
          result['memory_total'] = int(val.split()[0])/1024
431 eb58f9b1 Guido Trotter
        elif key in ('MemFree', 'Buffers', 'Cached'):
432 eb58f9b1 Guido Trotter
          sum_free += int(val.split()[0])/1024
433 eb58f9b1 Guido Trotter
        elif key == 'Active':
434 eb58f9b1 Guido Trotter
          result['memory_dom0'] = int(val.split()[0])/1024
435 eb58f9b1 Guido Trotter
    result['memory_free'] = sum_free
436 eb58f9b1 Guido Trotter
437 eb58f9b1 Guido Trotter
    cpu_total = 0
438 eb58f9b1 Guido Trotter
    try:
439 eb58f9b1 Guido Trotter
      fh = open("/proc/cpuinfo")
440 eb58f9b1 Guido Trotter
      try:
441 eb58f9b1 Guido Trotter
        cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
442 eb58f9b1 Guido Trotter
                                   fh.read()))
443 eb58f9b1 Guido Trotter
      finally:
444 eb58f9b1 Guido Trotter
        fh.close()
445 eb58f9b1 Guido Trotter
    except EnvironmentError, err:
446 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
447 eb58f9b1 Guido Trotter
    result['cpu_total'] = cpu_total
448 eb58f9b1 Guido Trotter
449 eb58f9b1 Guido Trotter
    return result
450 eb58f9b1 Guido Trotter
451 eb58f9b1 Guido Trotter
  @staticmethod
452 eb58f9b1 Guido Trotter
  def GetShellCommandForConsole(instance):
453 eb58f9b1 Guido Trotter
    """Return a command for connecting to the console of an instance.
454 eb58f9b1 Guido Trotter

455 eb58f9b1 Guido Trotter
    """
456 eb58f9b1 Guido Trotter
    # TODO: we can either try the serial socket or suggest vnc
457 eb58f9b1 Guido Trotter
    return "echo Console not available for the kvm hypervisor yet"
458 eb58f9b1 Guido Trotter
459 eb58f9b1 Guido Trotter
  def Verify(self):
460 eb58f9b1 Guido Trotter
    """Verify the hypervisor.
461 eb58f9b1 Guido Trotter

462 eb58f9b1 Guido Trotter
    Check that the binary exists.
463 eb58f9b1 Guido Trotter

464 eb58f9b1 Guido Trotter
    """
465 eb58f9b1 Guido Trotter
    if not os.path.exists(constants.KVM_PATH):
466 eb58f9b1 Guido Trotter
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
467 14aa53cb Guido Trotter
    if not os.path.exists(constants.SOCAT_PATH):
468 14aa53cb Guido Trotter
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
469 14aa53cb Guido Trotter
470 6b5605e8 Iustin Pop
471 6b5605e8 Iustin Pop
  @classmethod
472 6b5605e8 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
473 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
474 6b5605e8 Iustin Pop

475 6b5605e8 Iustin Pop
    For the KVM hypervisor, this only check the existence of the
476 6b5605e8 Iustin Pop
    kernel.
477 6b5605e8 Iustin Pop

478 6b5605e8 Iustin Pop
    @type hvparams:  dict
479 6b5605e8 Iustin Pop
    @param hvparams: dictionary with parameter names/value
480 6b5605e8 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
481 6b5605e8 Iustin Pop

482 6b5605e8 Iustin Pop
    """
483 47387b1e Guido Trotter
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
484 6b5605e8 Iustin Pop
485 6b5605e8 Iustin Pop
    if not hvparams[constants.HV_KERNEL_PATH]:
486 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Need a kernel for the instance")
487 6b5605e8 Iustin Pop
488 6b5605e8 Iustin Pop
    if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
489 6b5605e8 Iustin Pop
      raise errors.HypervisorError("The kernel path must an absolute path")
490 6b5605e8 Iustin Pop
491 6b5605e8 Iustin Pop
    if hvparams[constants.HV_INITRD_PATH]:
492 6b5605e8 Iustin Pop
      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
493 6b5605e8 Iustin Pop
        raise errors.HypervisorError("The initrd path must an absolute path"
494 6b5605e8 Iustin Pop
                                     ", if defined")
495 6b5605e8 Iustin Pop
496 6b5605e8 Iustin Pop
  def ValidateParameters(self, hvparams):
497 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
498 6b5605e8 Iustin Pop

499 6b5605e8 Iustin Pop
    For the KVM hypervisor, this checks the existence of the
500 6b5605e8 Iustin Pop
    kernel.
501 6b5605e8 Iustin Pop

502 6b5605e8 Iustin Pop
    """
503 47387b1e Guido Trotter
    super(KVMHypervisor, self).ValidateParameters(hvparams)
504 6b5605e8 Iustin Pop
505 6b5605e8 Iustin Pop
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
506 6b5605e8 Iustin Pop
    if not os.path.isfile(kernel_path):
507 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance kernel '%s' not found or"
508 6b5605e8 Iustin Pop
                                   " not a file" % kernel_path)
509 6b5605e8 Iustin Pop
    initrd_path = hvparams[constants.HV_INITRD_PATH]
510 6b5605e8 Iustin Pop
    if initrd_path and not os.path.isfile(initrd_path):
511 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance initrd '%s' not found or"
512 6b5605e8 Iustin Pop
                                   " not a file" % initrd_path)