Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 38e250ba

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

326 ee5f20b0 Guido Trotter
    """
327 ee5f20b0 Guido Trotter
    pidfile = self._PIDS_DIR + "/%s" % instance.name
328 ee5f20b0 Guido Trotter
    if utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
329 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
330 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
331 ee5f20b0 Guido Trotter
332 ee5f20b0 Guido Trotter
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices, extra_args)
333 38e250ba Guido Trotter
    self._SaveKVMRuntime(instance, kvm_runtime)
334 ee5f20b0 Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime)
335 ee5f20b0 Guido Trotter
336 eb58f9b1 Guido Trotter
  def StopInstance(self, instance, force=False):
337 eb58f9b1 Guido Trotter
    """Stop an instance.
338 eb58f9b1 Guido Trotter

339 eb58f9b1 Guido Trotter
    """
340 14aa53cb Guido Trotter
    socat_bin = constants.SOCAT_PATH
341 eb58f9b1 Guido Trotter
    pid_file = self._PIDS_DIR + "/%s" % instance.name
342 eb58f9b1 Guido Trotter
    pid = utils.ReadPidFile(pid_file)
343 eb58f9b1 Guido Trotter
    if pid > 0 and utils.IsProcessAlive(pid):
344 6b5605e8 Iustin Pop
      if force or not instance.hvparams[constants.HV_ACPI]:
345 eb58f9b1 Guido Trotter
        utils.KillProcess(pid)
346 eb58f9b1 Guido Trotter
      else:
347 eb58f9b1 Guido Trotter
        # This only works if the instance os has acpi support
348 eb58f9b1 Guido Trotter
        monitor_socket = '%s/%s.monitor'  % (self._CTRL_DIR, instance.name)
349 14aa53cb Guido Trotter
        socat = '%s -u STDIN UNIX-CONNECT:%s' % (socat_bin, monitor_socket)
350 eb58f9b1 Guido Trotter
        command = "echo 'system_powerdown' | %s" % socat
351 eb58f9b1 Guido Trotter
        result = utils.RunCmd(command)
352 eb58f9b1 Guido Trotter
        if result.failed:
353 eb58f9b1 Guido Trotter
          raise errors.HypervisorError("Failed to stop instance %s: %s" %
354 eb58f9b1 Guido Trotter
                                       (instance.name, result.fail_reason))
355 eb58f9b1 Guido Trotter
356 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(pid):
357 eb58f9b1 Guido Trotter
      utils.RemoveFile(pid_file)
358 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceMonitor(instance.name))
359 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceSerial(instance.name))
360 38e250ba Guido Trotter
      utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
361 eb58f9b1 Guido Trotter
362 eb58f9b1 Guido Trotter
  def RebootInstance(self, instance):
363 eb58f9b1 Guido Trotter
    """Reboot an instance.
364 eb58f9b1 Guido Trotter

365 eb58f9b1 Guido Trotter
    """
366 eb58f9b1 Guido Trotter
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
367 eb58f9b1 Guido Trotter
    # socket the instance will stop, but now power up again. So we'll resort
368 eb58f9b1 Guido Trotter
    # to shutdown and restart.
369 eb58f9b1 Guido Trotter
    self.StopInstance(instance)
370 eb58f9b1 Guido Trotter
    self.StartInstance(instance)
371 eb58f9b1 Guido Trotter
372 eb58f9b1 Guido Trotter
  def GetNodeInfo(self):
373 eb58f9b1 Guido Trotter
    """Return information about the node.
374 eb58f9b1 Guido Trotter

375 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
376 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
377 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
378 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
379 eb58f9b1 Guido Trotter

380 eb58f9b1 Guido Trotter
    """
381 eb58f9b1 Guido Trotter
    # global ram usage from the xm info command
382 eb58f9b1 Guido Trotter
    # memory                 : 3583
383 eb58f9b1 Guido Trotter
    # free_memory            : 747
384 eb58f9b1 Guido Trotter
    # note: in xen 3, memory has changed to total_memory
385 eb58f9b1 Guido Trotter
    try:
386 eb58f9b1 Guido Trotter
      fh = file("/proc/meminfo")
387 eb58f9b1 Guido Trotter
      try:
388 eb58f9b1 Guido Trotter
        data = fh.readlines()
389 eb58f9b1 Guido Trotter
      finally:
390 eb58f9b1 Guido Trotter
        fh.close()
391 eb58f9b1 Guido Trotter
    except IOError, err:
392 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
393 eb58f9b1 Guido Trotter
394 eb58f9b1 Guido Trotter
    result = {}
395 eb58f9b1 Guido Trotter
    sum_free = 0
396 eb58f9b1 Guido Trotter
    for line in data:
397 eb58f9b1 Guido Trotter
      splitfields = line.split(":", 1)
398 eb58f9b1 Guido Trotter
399 eb58f9b1 Guido Trotter
      if len(splitfields) > 1:
400 eb58f9b1 Guido Trotter
        key = splitfields[0].strip()
401 eb58f9b1 Guido Trotter
        val = splitfields[1].strip()
402 eb58f9b1 Guido Trotter
        if key == 'MemTotal':
403 eb58f9b1 Guido Trotter
          result['memory_total'] = int(val.split()[0])/1024
404 eb58f9b1 Guido Trotter
        elif key in ('MemFree', 'Buffers', 'Cached'):
405 eb58f9b1 Guido Trotter
          sum_free += int(val.split()[0])/1024
406 eb58f9b1 Guido Trotter
        elif key == 'Active':
407 eb58f9b1 Guido Trotter
          result['memory_dom0'] = int(val.split()[0])/1024
408 eb58f9b1 Guido Trotter
    result['memory_free'] = sum_free
409 eb58f9b1 Guido Trotter
410 eb58f9b1 Guido Trotter
    cpu_total = 0
411 eb58f9b1 Guido Trotter
    try:
412 eb58f9b1 Guido Trotter
      fh = open("/proc/cpuinfo")
413 eb58f9b1 Guido Trotter
      try:
414 eb58f9b1 Guido Trotter
        cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
415 eb58f9b1 Guido Trotter
                                   fh.read()))
416 eb58f9b1 Guido Trotter
      finally:
417 eb58f9b1 Guido Trotter
        fh.close()
418 eb58f9b1 Guido Trotter
    except EnvironmentError, err:
419 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
420 eb58f9b1 Guido Trotter
    result['cpu_total'] = cpu_total
421 eb58f9b1 Guido Trotter
422 eb58f9b1 Guido Trotter
    return result
423 eb58f9b1 Guido Trotter
424 eb58f9b1 Guido Trotter
  @staticmethod
425 eb58f9b1 Guido Trotter
  def GetShellCommandForConsole(instance):
426 eb58f9b1 Guido Trotter
    """Return a command for connecting to the console of an instance.
427 eb58f9b1 Guido Trotter

428 eb58f9b1 Guido Trotter
    """
429 eb58f9b1 Guido Trotter
    # TODO: we can either try the serial socket or suggest vnc
430 eb58f9b1 Guido Trotter
    return "echo Console not available for the kvm hypervisor yet"
431 eb58f9b1 Guido Trotter
432 eb58f9b1 Guido Trotter
  def Verify(self):
433 eb58f9b1 Guido Trotter
    """Verify the hypervisor.
434 eb58f9b1 Guido Trotter

435 eb58f9b1 Guido Trotter
    Check that the binary exists.
436 eb58f9b1 Guido Trotter

437 eb58f9b1 Guido Trotter
    """
438 eb58f9b1 Guido Trotter
    if not os.path.exists(constants.KVM_PATH):
439 eb58f9b1 Guido Trotter
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
440 14aa53cb Guido Trotter
    if not os.path.exists(constants.SOCAT_PATH):
441 14aa53cb Guido Trotter
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
442 14aa53cb Guido Trotter
443 6b5605e8 Iustin Pop
444 6b5605e8 Iustin Pop
  @classmethod
445 6b5605e8 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
446 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
447 6b5605e8 Iustin Pop

448 6b5605e8 Iustin Pop
    For the KVM hypervisor, this only check the existence of the
449 6b5605e8 Iustin Pop
    kernel.
450 6b5605e8 Iustin Pop

451 6b5605e8 Iustin Pop
    @type hvparams:  dict
452 6b5605e8 Iustin Pop
    @param hvparams: dictionary with parameter names/value
453 6b5605e8 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
454 6b5605e8 Iustin Pop

455 6b5605e8 Iustin Pop
    """
456 47387b1e Guido Trotter
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
457 6b5605e8 Iustin Pop
458 6b5605e8 Iustin Pop
    if not hvparams[constants.HV_KERNEL_PATH]:
459 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Need a kernel for the instance")
460 6b5605e8 Iustin Pop
461 6b5605e8 Iustin Pop
    if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
462 6b5605e8 Iustin Pop
      raise errors.HypervisorError("The kernel path must an absolute path")
463 6b5605e8 Iustin Pop
464 6b5605e8 Iustin Pop
    if hvparams[constants.HV_INITRD_PATH]:
465 6b5605e8 Iustin Pop
      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
466 6b5605e8 Iustin Pop
        raise errors.HypervisorError("The initrd path must an absolute path"
467 6b5605e8 Iustin Pop
                                     ", if defined")
468 6b5605e8 Iustin Pop
469 6b5605e8 Iustin Pop
  def ValidateParameters(self, hvparams):
470 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
471 6b5605e8 Iustin Pop

472 6b5605e8 Iustin Pop
    For the KVM hypervisor, this checks the existence of the
473 6b5605e8 Iustin Pop
    kernel.
474 6b5605e8 Iustin Pop

475 6b5605e8 Iustin Pop
    """
476 47387b1e Guido Trotter
    super(KVMHypervisor, self).ValidateParameters(hvparams)
477 6b5605e8 Iustin Pop
478 6b5605e8 Iustin Pop
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
479 6b5605e8 Iustin Pop
    if not os.path.isfile(kernel_path):
480 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance kernel '%s' not found or"
481 6b5605e8 Iustin Pop
                                   " not a file" % kernel_path)
482 6b5605e8 Iustin Pop
    initrd_path = hvparams[constants.HV_INITRD_PATH]
483 6b5605e8 Iustin Pop
    if initrd_path and not os.path.isfile(initrd_path):
484 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance initrd '%s' not found or"
485 6b5605e8 Iustin Pop
                                   " not a file" % initrd_path)