Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 73cd67f4

History | View | Annotate | Download (21.3 kB)

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

24 65a6f9b7 Michael Hanselmann
"""
25 65a6f9b7 Michael Hanselmann
26 65a6f9b7 Michael Hanselmann
import os
27 65a6f9b7 Michael Hanselmann
import os.path
28 65a6f9b7 Michael Hanselmann
import time
29 b48909c8 Iustin Pop
import logging
30 65a6f9b7 Michael Hanselmann
from cStringIO import StringIO
31 65a6f9b7 Michael Hanselmann
32 65a6f9b7 Michael Hanselmann
from ganeti import constants
33 65a6f9b7 Michael Hanselmann
from ganeti import errors
34 65a6f9b7 Michael Hanselmann
from ganeti import utils
35 a2d32034 Michael Hanselmann
from ganeti.hypervisor import hv_base
36 65a6f9b7 Michael Hanselmann
37 65a6f9b7 Michael Hanselmann
38 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
39 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
40 65a6f9b7 Michael Hanselmann

41 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
42 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
43 65a6f9b7 Michael Hanselmann

44 65a6f9b7 Michael Hanselmann
  """
45 65a6f9b7 Michael Hanselmann
46 5661b908 Iustin Pop
  @classmethod
47 5661b908 Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
48 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
49 65a6f9b7 Michael Hanselmann

50 65a6f9b7 Michael Hanselmann
    """
51 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
52 65a6f9b7 Michael Hanselmann
53 65a6f9b7 Michael Hanselmann
  @staticmethod
54 4390ccff Guido Trotter
  def _WriteConfigFileStatic(instance_name, data):
55 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
56 4390ccff Guido Trotter

57 4390ccff Guido Trotter
    This version of the function just writes the config file from static data.
58 4390ccff Guido Trotter

59 4390ccff Guido Trotter
    """
60 4390ccff Guido Trotter
    utils.WriteFile("/etc/xen/%s" % instance_name, data=data)
61 4390ccff Guido Trotter
62 4390ccff Guido Trotter
  @staticmethod
63 4390ccff Guido Trotter
  def _ReadConfigFile(instance_name):
64 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
65 4390ccff Guido Trotter

66 4390ccff Guido Trotter
    """
67 4390ccff Guido Trotter
    try:
68 4390ccff Guido Trotter
      file_content = utils.ReadFile("/etc/xen/%s" % instance_name)
69 4390ccff Guido Trotter
    except EnvironmentError, err:
70 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
71 4390ccff Guido Trotter
    return file_content
72 4390ccff Guido Trotter
73 4390ccff Guido Trotter
  @staticmethod
74 53c776b5 Iustin Pop
  def _RemoveConfigFile(instance_name):
75 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
76 65a6f9b7 Michael Hanselmann

77 65a6f9b7 Michael Hanselmann
    """
78 53c776b5 Iustin Pop
    utils.RemoveFile("/etc/xen/%s" % instance_name)
79 65a6f9b7 Michael Hanselmann
80 65a6f9b7 Michael Hanselmann
  @staticmethod
81 65a6f9b7 Michael Hanselmann
  def _GetXMList(include_node):
82 65a6f9b7 Michael Hanselmann
    """Return the list of running instances.
83 65a6f9b7 Michael Hanselmann

84 c41eea6e Iustin Pop
    If the include_node argument is True, then we return information
85 65a6f9b7 Michael Hanselmann
    for dom0 also, otherwise we filter that from the return value.
86 65a6f9b7 Michael Hanselmann

87 c41eea6e Iustin Pop
    @return: list of (name, id, memory, vcpus, state, time spent)
88 65a6f9b7 Michael Hanselmann

89 65a6f9b7 Michael Hanselmann
    """
90 65a6f9b7 Michael Hanselmann
    for dummy in range(5):
91 65a6f9b7 Michael Hanselmann
      result = utils.RunCmd(["xm", "list"])
92 65a6f9b7 Michael Hanselmann
      if not result.failed:
93 65a6f9b7 Michael Hanselmann
        break
94 b48909c8 Iustin Pop
      logging.error("xm list failed (%s): %s", result.fail_reason,
95 b48909c8 Iustin Pop
                    result.output)
96 65a6f9b7 Michael Hanselmann
      time.sleep(1)
97 65a6f9b7 Michael Hanselmann
98 65a6f9b7 Michael Hanselmann
    if result.failed:
99 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("xm list failed, retries"
100 65a6f9b7 Michael Hanselmann
                                   " exceeded (%s): %s" %
101 65a6f9b7 Michael Hanselmann
                                   (result.fail_reason, result.stderr))
102 65a6f9b7 Michael Hanselmann
103 65a6f9b7 Michael Hanselmann
    # skip over the heading
104 65a6f9b7 Michael Hanselmann
    lines = result.stdout.splitlines()[1:]
105 65a6f9b7 Michael Hanselmann
    result = []
106 65a6f9b7 Michael Hanselmann
    for line in lines:
107 65a6f9b7 Michael Hanselmann
      # The format of lines is:
108 65a6f9b7 Michael Hanselmann
      # Name      ID Mem(MiB) VCPUs State  Time(s)
109 65a6f9b7 Michael Hanselmann
      # Domain-0   0  3418     4 r-----    266.2
110 65a6f9b7 Michael Hanselmann
      data = line.split()
111 65a6f9b7 Michael Hanselmann
      if len(data) != 6:
112 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
113 65a6f9b7 Michael Hanselmann
                                     " line: %s" % line)
114 65a6f9b7 Michael Hanselmann
      try:
115 65a6f9b7 Michael Hanselmann
        data[1] = int(data[1])
116 65a6f9b7 Michael Hanselmann
        data[2] = int(data[2])
117 65a6f9b7 Michael Hanselmann
        data[3] = int(data[3])
118 65a6f9b7 Michael Hanselmann
        data[5] = float(data[5])
119 65a6f9b7 Michael Hanselmann
      except ValueError, err:
120 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
121 65a6f9b7 Michael Hanselmann
                                     " line: %s, error: %s" % (line, err))
122 65a6f9b7 Michael Hanselmann
123 65a6f9b7 Michael Hanselmann
      # skip the Domain-0 (optional)
124 65a6f9b7 Michael Hanselmann
      if include_node or data[0] != 'Domain-0':
125 65a6f9b7 Michael Hanselmann
        result.append(data)
126 65a6f9b7 Michael Hanselmann
127 65a6f9b7 Michael Hanselmann
    return result
128 65a6f9b7 Michael Hanselmann
129 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
130 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
131 65a6f9b7 Michael Hanselmann

132 65a6f9b7 Michael Hanselmann
    """
133 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
134 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
135 65a6f9b7 Michael Hanselmann
    return names
136 65a6f9b7 Michael Hanselmann
137 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
138 65a6f9b7 Michael Hanselmann
    """Get instance properties.
139 65a6f9b7 Michael Hanselmann

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 65a6f9b7 Michael Hanselmann

144 65a6f9b7 Michael Hanselmann
    """
145 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(instance_name=="Domain-0")
146 65a6f9b7 Michael Hanselmann
    result = None
147 65a6f9b7 Michael Hanselmann
    for data in xm_list:
148 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
149 65a6f9b7 Michael Hanselmann
        result = data
150 65a6f9b7 Michael Hanselmann
        break
151 65a6f9b7 Michael Hanselmann
    return result
152 65a6f9b7 Michael Hanselmann
153 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
154 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
155 65a6f9b7 Michael Hanselmann

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

158 65a6f9b7 Michael Hanselmann
    """
159 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
160 65a6f9b7 Michael Hanselmann
    return xm_list
161 65a6f9b7 Michael Hanselmann
162 65a6f9b7 Michael Hanselmann
  def StartInstance(self, instance, block_devices, extra_args):
163 c41eea6e Iustin Pop
    """Start an instance.
164 c41eea6e Iustin Pop

165 c41eea6e Iustin Pop
    """
166 65a6f9b7 Michael Hanselmann
    self._WriteConfigFile(instance, block_devices, extra_args)
167 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "create", instance.name])
168 65a6f9b7 Michael Hanselmann
169 65a6f9b7 Michael Hanselmann
    if result.failed:
170 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
171 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
172 65a6f9b7 Michael Hanselmann
                                    result.output))
173 65a6f9b7 Michael Hanselmann
174 65a6f9b7 Michael Hanselmann
  def StopInstance(self, instance, force=False):
175 c41eea6e Iustin Pop
    """Stop an instance.
176 c41eea6e Iustin Pop

177 c41eea6e Iustin Pop
    """
178 53c776b5 Iustin Pop
    self._RemoveConfigFile(instance.name)
179 65a6f9b7 Michael Hanselmann
    if force:
180 65a6f9b7 Michael Hanselmann
      command = ["xm", "destroy", instance.name]
181 65a6f9b7 Michael Hanselmann
    else:
182 65a6f9b7 Michael Hanselmann
      command = ["xm", "shutdown", instance.name]
183 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
184 65a6f9b7 Michael Hanselmann
185 65a6f9b7 Michael Hanselmann
    if result.failed:
186 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
187 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason))
188 65a6f9b7 Michael Hanselmann
189 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
190 c41eea6e Iustin Pop
    """Reboot an instance.
191 c41eea6e Iustin Pop

192 c41eea6e Iustin Pop
    """
193 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "reboot", instance.name])
194 65a6f9b7 Michael Hanselmann
195 65a6f9b7 Michael Hanselmann
    if result.failed:
196 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to reboot instance %s: %s" %
197 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason))
198 65a6f9b7 Michael Hanselmann
199 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
200 65a6f9b7 Michael Hanselmann
    """Return information about the node.
201 65a6f9b7 Michael Hanselmann

202 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
203 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
204 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
205 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
206 65a6f9b7 Michael Hanselmann

207 65a6f9b7 Michael Hanselmann
    """
208 65a6f9b7 Michael Hanselmann
    # note: in xen 3, memory has changed to total_memory
209 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
210 65a6f9b7 Michael Hanselmann
    if result.failed:
211 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
212 b48909c8 Iustin Pop
                    result.output)
213 65a6f9b7 Michael Hanselmann
      return None
214 65a6f9b7 Michael Hanselmann
215 65a6f9b7 Michael Hanselmann
    xmoutput = result.stdout.splitlines()
216 65a6f9b7 Michael Hanselmann
    result = {}
217 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
218 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
219 65a6f9b7 Michael Hanselmann
220 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
221 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
222 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
223 65a6f9b7 Michael Hanselmann
        if key == 'memory' or key == 'total_memory':
224 65a6f9b7 Michael Hanselmann
          result['memory_total'] = int(val)
225 65a6f9b7 Michael Hanselmann
        elif key == 'free_memory':
226 65a6f9b7 Michael Hanselmann
          result['memory_free'] = int(val)
227 e8a4c138 Iustin Pop
        elif key == 'nr_cpus':
228 e8a4c138 Iustin Pop
          result['cpu_total'] = int(val)
229 65a6f9b7 Michael Hanselmann
    dom0_info = self.GetInstanceInfo("Domain-0")
230 65a6f9b7 Michael Hanselmann
    if dom0_info is not None:
231 65a6f9b7 Michael Hanselmann
      result['memory_dom0'] = dom0_info[2]
232 65a6f9b7 Michael Hanselmann
233 65a6f9b7 Michael Hanselmann
    return result
234 65a6f9b7 Michael Hanselmann
235 637ce7f9 Guido Trotter
  @classmethod
236 637ce7f9 Guido Trotter
  def GetShellCommandForConsole(cls, instance):
237 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
238 65a6f9b7 Michael Hanselmann

239 65a6f9b7 Michael Hanselmann
    """
240 04c4330c Alexander Schreiber
    return "xm console %s" % instance.name
241 04c4330c Alexander Schreiber
242 65a6f9b7 Michael Hanselmann
243 65a6f9b7 Michael Hanselmann
  def Verify(self):
244 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
245 65a6f9b7 Michael Hanselmann

246 65a6f9b7 Michael Hanselmann
    For Xen, this verifies that the xend process is running.
247 65a6f9b7 Michael Hanselmann

248 65a6f9b7 Michael Hanselmann
    """
249 e3e66f02 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
250 e3e66f02 Michael Hanselmann
    if result.failed:
251 e3e66f02 Michael Hanselmann
      return "'xm info' failed: %s" % result.fail_reason
252 65a6f9b7 Michael Hanselmann
253 65a6f9b7 Michael Hanselmann
  @staticmethod
254 65a6f9b7 Michael Hanselmann
  def _GetConfigFileDiskData(disk_template, block_devices):
255 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
256 65a6f9b7 Michael Hanselmann

257 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
258 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
259 65a6f9b7 Michael Hanselmann

260 c41eea6e Iustin Pop
    @param disk_template: string containing instance disk template
261 c41eea6e Iustin Pop
    @param block_devices: list of tuples (cfdev, rldev):
262 c41eea6e Iustin Pop
        - cfdev: dict containing ganeti config disk part
263 c41eea6e Iustin Pop
        - rldev: ganeti.bdev.BlockDev object
264 65a6f9b7 Michael Hanselmann

265 c41eea6e Iustin Pop
    @return: string containing disk directive for xen instance config file
266 65a6f9b7 Michael Hanselmann

267 65a6f9b7 Michael Hanselmann
    """
268 65a6f9b7 Michael Hanselmann
    FILE_DRIVER_MAP = {
269 65a6f9b7 Michael Hanselmann
      constants.FD_LOOP: "file",
270 65a6f9b7 Michael Hanselmann
      constants.FD_BLKTAP: "tap:aio",
271 65a6f9b7 Michael Hanselmann
      }
272 65a6f9b7 Michael Hanselmann
    disk_data = []
273 2864f2d9 Iustin Pop
    if len(block_devices) > 24:
274 2864f2d9 Iustin Pop
      # 'z' - 'a' = 24
275 2864f2d9 Iustin Pop
      raise errors.HypervisorError("Too many disks")
276 2864f2d9 Iustin Pop
    # FIXME: instead of this hardcoding here, each of PVM/HVM should
277 2864f2d9 Iustin Pop
    # directly export their info (currently HVM will just sed this info)
278 2864f2d9 Iustin Pop
    namespace = ["sd" + chr(i + ord('a')) for i in range(24)]
279 069cfbf1 Iustin Pop
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
280 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
281 65a6f9b7 Michael Hanselmann
        line = "'%s:%s,%s,w'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
282 069cfbf1 Iustin Pop
                                 dev_path, sd_name)
283 65a6f9b7 Michael Hanselmann
      else:
284 069cfbf1 Iustin Pop
        line = "'phy:%s,%s,w'" % (dev_path, sd_name)
285 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
286 65a6f9b7 Michael Hanselmann
287 65a6f9b7 Michael Hanselmann
    return disk_data
288 65a6f9b7 Michael Hanselmann
289 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
290 4390ccff Guido Trotter
    """Get instance information to perform a migration.
291 4390ccff Guido Trotter

292 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
293 4390ccff Guido Trotter
    @param instance: instance to be migrated
294 4390ccff Guido Trotter
    @rtype: string
295 4390ccff Guido Trotter
    @return: content of the xen config file
296 4390ccff Guido Trotter

297 4390ccff Guido Trotter
    """
298 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
299 4390ccff Guido Trotter
300 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
301 4390ccff Guido Trotter
    """Prepare to accept an instance.
302 4390ccff Guido Trotter

303 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
304 4390ccff Guido Trotter
    @param instance: instance to be accepted
305 4390ccff Guido Trotter
    @type info: string
306 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
307 4390ccff Guido Trotter
    @type target: string
308 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
309 4390ccff Guido Trotter

310 4390ccff Guido Trotter
    """
311 4390ccff Guido Trotter
    pass
312 4390ccff Guido Trotter
313 4390ccff Guido Trotter
  def FinalizeMigration(self, instance, info, success):
314 4390ccff Guido Trotter
    """Finalize an instance migration.
315 4390ccff Guido Trotter

316 4390ccff Guido Trotter
    After a successful migration we write the xen config file.
317 4390ccff Guido Trotter
    We do nothing on a failure, as we did not change anything at accept time.
318 4390ccff Guido Trotter

319 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
320 4390ccff Guido Trotter
    @param instance: instance whose migration is being aborted
321 4390ccff Guido Trotter
    @type info: string
322 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
323 4390ccff Guido Trotter
    @type success: boolean
324 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
325 4390ccff Guido Trotter

326 4390ccff Guido Trotter
    """
327 4390ccff Guido Trotter
    if success:
328 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
329 4390ccff Guido Trotter
330 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
331 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
332 6e7275c0 Iustin Pop

333 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
334 6e7275c0 Iustin Pop
    currently running.
335 6e7275c0 Iustin Pop

336 fdf7f055 Guido Trotter
    @type instance: string
337 fdf7f055 Guido Trotter
    @param instance: instance name
338 fdf7f055 Guido Trotter
    @type target: string
339 fdf7f055 Guido Trotter
    @param target: ip address of the target node
340 fdf7f055 Guido Trotter
    @type live: boolean
341 fdf7f055 Guido Trotter
    @param live: perform a live migration
342 fdf7f055 Guido Trotter

343 6e7275c0 Iustin Pop
    """
344 6e7275c0 Iustin Pop
    if self.GetInstanceInfo(instance) is None:
345 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
346 6e7275c0 Iustin Pop
    args = ["xm", "migrate"]
347 6e7275c0 Iustin Pop
    if live:
348 6e7275c0 Iustin Pop
      args.append("-l")
349 6e7275c0 Iustin Pop
    args.extend([instance, target])
350 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
351 6e7275c0 Iustin Pop
    if result.failed:
352 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
353 6e7275c0 Iustin Pop
                                   (instance, result.output))
354 53c776b5 Iustin Pop
    # remove old xen file after migration succeeded
355 53c776b5 Iustin Pop
    try:
356 53c776b5 Iustin Pop
      self._RemoveConfigFile(instance)
357 c979d253 Iustin Pop
    except EnvironmentError:
358 c979d253 Iustin Pop
      logging.exception("Failure while removing instance config file")
359 6e7275c0 Iustin Pop
360 65a6f9b7 Michael Hanselmann
361 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
362 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
363 65a6f9b7 Michael Hanselmann
364 f48148c3 Iustin Pop
  PARAMETERS = [
365 f48148c3 Iustin Pop
    constants.HV_KERNEL_PATH,
366 f48148c3 Iustin Pop
    constants.HV_INITRD_PATH,
367 074ca009 Guido Trotter
    constants.HV_ROOT_PATH,
368 f48148c3 Iustin Pop
    ]
369 f48148c3 Iustin Pop
370 f48148c3 Iustin Pop
  @classmethod
371 f48148c3 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
372 f48148c3 Iustin Pop
    """Check the given parameters for validity.
373 f48148c3 Iustin Pop

374 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
375 f48148c3 Iustin Pop
    kernel.
376 f48148c3 Iustin Pop

377 f48148c3 Iustin Pop
    @type hvparams:  dict
378 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
379 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
380 f48148c3 Iustin Pop

381 f48148c3 Iustin Pop
    """
382 f48148c3 Iustin Pop
    super(XenPvmHypervisor, cls).CheckParameterSyntax(hvparams)
383 f48148c3 Iustin Pop
384 f48148c3 Iustin Pop
    if not hvparams[constants.HV_KERNEL_PATH]:
385 f48148c3 Iustin Pop
      raise errors.HypervisorError("Need a kernel for the instance")
386 f48148c3 Iustin Pop
387 f48148c3 Iustin Pop
    if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
388 50cb2e2a Guido Trotter
      raise errors.HypervisorError("The kernel path must be an absolute path")
389 f48148c3 Iustin Pop
390 074ca009 Guido Trotter
    if not hvparams[constants.HV_ROOT_PATH]:
391 074ca009 Guido Trotter
      raise errors.HypervisorError("Need a root partition for the instance")
392 074ca009 Guido Trotter
393 f48148c3 Iustin Pop
    if hvparams[constants.HV_INITRD_PATH]:
394 f48148c3 Iustin Pop
      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
395 50cb2e2a Guido Trotter
        raise errors.HypervisorError("The initrd path must be an absolute path"
396 f48148c3 Iustin Pop
                                     ", if defined")
397 f48148c3 Iustin Pop
398 f48148c3 Iustin Pop
  def ValidateParameters(self, hvparams):
399 f48148c3 Iustin Pop
    """Check the given parameters for validity.
400 f48148c3 Iustin Pop

401 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
402 f48148c3 Iustin Pop
    kernel.
403 f48148c3 Iustin Pop

404 f48148c3 Iustin Pop
    """
405 f48148c3 Iustin Pop
    super(XenPvmHypervisor, self).ValidateParameters(hvparams)
406 f48148c3 Iustin Pop
407 f48148c3 Iustin Pop
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
408 f48148c3 Iustin Pop
    if not os.path.isfile(kernel_path):
409 f48148c3 Iustin Pop
      raise errors.HypervisorError("Instance kernel '%s' not found or"
410 f48148c3 Iustin Pop
                                   " not a file" % kernel_path)
411 f48148c3 Iustin Pop
    initrd_path = hvparams[constants.HV_INITRD_PATH]
412 f48148c3 Iustin Pop
    if initrd_path and not os.path.isfile(initrd_path):
413 f48148c3 Iustin Pop
      raise errors.HypervisorError("Instance initrd '%s' not found or"
414 f48148c3 Iustin Pop
                                   " not a file" % initrd_path)
415 f48148c3 Iustin Pop
416 65a6f9b7 Michael Hanselmann
  @classmethod
417 65a6f9b7 Michael Hanselmann
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
418 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
419 65a6f9b7 Michael Hanselmann

420 65a6f9b7 Michael Hanselmann
    """
421 65a6f9b7 Michael Hanselmann
    config = StringIO()
422 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
423 65a6f9b7 Michael Hanselmann
424 65a6f9b7 Michael Hanselmann
    # kernel handling
425 f48148c3 Iustin Pop
    kpath = instance.hvparams[constants.HV_KERNEL_PATH]
426 65a6f9b7 Michael Hanselmann
    config.write("kernel = '%s'\n" % kpath)
427 65a6f9b7 Michael Hanselmann
428 65a6f9b7 Michael Hanselmann
    # initrd handling
429 f48148c3 Iustin Pop
    initrd_path = instance.hvparams[constants.HV_INITRD_PATH]
430 65a6f9b7 Michael Hanselmann
    if initrd_path:
431 65a6f9b7 Michael Hanselmann
      config.write("ramdisk = '%s'\n" % initrd_path)
432 65a6f9b7 Michael Hanselmann
433 65a6f9b7 Michael Hanselmann
    # rest of the settings
434 8b3fd458 Iustin Pop
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
435 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
436 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
437 65a6f9b7 Michael Hanselmann
438 65a6f9b7 Michael Hanselmann
    vif_data = []
439 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
440 65a6f9b7 Michael Hanselmann
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
441 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
442 65a6f9b7 Michael Hanselmann
      if ip is not None:
443 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
444 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
445 65a6f9b7 Michael Hanselmann
446 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
447 65a6f9b7 Michael Hanselmann
    config.write("disk = [%s]\n" % ",".join(
448 65a6f9b7 Michael Hanselmann
                 cls._GetConfigFileDiskData(instance.disk_template,
449 65a6f9b7 Michael Hanselmann
                                            block_devices)))
450 074ca009 Guido Trotter
451 074ca009 Guido Trotter
    rpath = instance.hvparams[constants.HV_ROOT_PATH]
452 074ca009 Guido Trotter
    config.write("root = '%s ro'\n" % rpath)
453 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
454 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
455 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
456 65a6f9b7 Michael Hanselmann
    if extra_args:
457 65a6f9b7 Michael Hanselmann
      config.write("extra = '%s'\n" % extra_args)
458 65a6f9b7 Michael Hanselmann
    # just in case it exists
459 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
460 65a6f9b7 Michael Hanselmann
    try:
461 73cd67f4 Guido Trotter
      utils.WriteFile("/etc/xen/%s" % instance.name,
462 73cd67f4 Guido Trotter
                      data=config.getvalue())
463 73cd67f4 Guido Trotter
    except EnvironmentError, err:
464 73cd67f4 Guido Trotter
      raise errors.HypervisorError("Cannot write Xen instance confile"
465 73cd67f4 Guido Trotter
                                   " file /etc/xen/%s: %s" %
466 73cd67f4 Guido Trotter
                                   (instance.name, err))
467 73cd67f4 Guido Trotter
468 65a6f9b7 Michael Hanselmann
    return True
469 65a6f9b7 Michael Hanselmann
470 65a6f9b7 Michael Hanselmann
471 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
472 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
473 65a6f9b7 Michael Hanselmann
474 f48148c3 Iustin Pop
  PARAMETERS = [
475 f48148c3 Iustin Pop
    constants.HV_ACPI,
476 f48148c3 Iustin Pop
    constants.HV_BOOT_ORDER,
477 f48148c3 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH,
478 f48148c3 Iustin Pop
    constants.HV_DISK_TYPE,
479 f48148c3 Iustin Pop
    constants.HV_NIC_TYPE,
480 f48148c3 Iustin Pop
    constants.HV_PAE,
481 f48148c3 Iustin Pop
    constants.HV_VNC_BIND_ADDRESS,
482 f48148c3 Iustin Pop
    ]
483 f48148c3 Iustin Pop
484 f48148c3 Iustin Pop
  @classmethod
485 f48148c3 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
486 f48148c3 Iustin Pop
    """Check the given parameter syntax.
487 f48148c3 Iustin Pop

488 f48148c3 Iustin Pop
    """
489 f48148c3 Iustin Pop
    super(XenHvmHypervisor, cls).CheckParameterSyntax(hvparams)
490 f48148c3 Iustin Pop
    # boot order verification
491 f48148c3 Iustin Pop
    boot_order = hvparams[constants.HV_BOOT_ORDER]
492 f48148c3 Iustin Pop
    if len(boot_order.strip("acdn")) != 0:
493 f48148c3 Iustin Pop
      raise errors.HypervisorError("Invalid boot order '%s' specified,"
494 f48148c3 Iustin Pop
                                   " must be one or more of [acdn]" %
495 f48148c3 Iustin Pop
                                   boot_order)
496 f48148c3 Iustin Pop
    # device type checks
497 f48148c3 Iustin Pop
    nic_type = hvparams[constants.HV_NIC_TYPE]
498 f48148c3 Iustin Pop
    if nic_type not in constants.HT_HVM_VALID_NIC_TYPES:
499 f48148c3 Iustin Pop
      raise errors.HypervisorError("Invalid NIC type %s specified for Xen HVM"
500 f48148c3 Iustin Pop
                                   " hypervisor" % nic_type)
501 f48148c3 Iustin Pop
    disk_type = hvparams[constants.HV_DISK_TYPE]
502 f48148c3 Iustin Pop
    if disk_type not in constants.HT_HVM_VALID_DISK_TYPES:
503 f48148c3 Iustin Pop
      raise errors.HypervisorError("Invalid disk type %s specified for Xen HVM"
504 f48148c3 Iustin Pop
                                   " hypervisor" % disk_type)
505 f48148c3 Iustin Pop
    # vnc_bind_address verification
506 f48148c3 Iustin Pop
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
507 f48148c3 Iustin Pop
    if vnc_bind_address is not None:
508 f48148c3 Iustin Pop
      if not utils.IsValidIP(vnc_bind_address):
509 f48148c3 Iustin Pop
        raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
510 f48148c3 Iustin Pop
                                   " like a valid IP address" %
511 f48148c3 Iustin Pop
                                   vnc_bind_address)
512 f48148c3 Iustin Pop
513 f48148c3 Iustin Pop
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
514 f48148c3 Iustin Pop
    if iso_path and not os.path.isabs(iso_path):
515 5661b908 Iustin Pop
      raise errors.HypervisorError("The path to the HVM CDROM image must"
516 5661b908 Iustin Pop
                                   " be an absolute path or None, not %s" %
517 5661b908 Iustin Pop
                                   iso_path)
518 f48148c3 Iustin Pop
519 f48148c3 Iustin Pop
  def ValidateParameters(self, hvparams):
520 f48148c3 Iustin Pop
    """Check the given parameters for validity.
521 f48148c3 Iustin Pop

522 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
523 f48148c3 Iustin Pop
    kernel.
524 f48148c3 Iustin Pop

525 f48148c3 Iustin Pop
    @type hvparams:  dict
526 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
527 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
528 f48148c3 Iustin Pop

529 f48148c3 Iustin Pop
    """
530 f48148c3 Iustin Pop
    super(XenHvmHypervisor, self).ValidateParameters(hvparams)
531 f48148c3 Iustin Pop
532 f48148c3 Iustin Pop
    # hvm_cdrom_image_path verification
533 f48148c3 Iustin Pop
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
534 f48148c3 Iustin Pop
    if iso_path and not os.path.isfile(iso_path):
535 e09fdcfa Iustin Pop
      raise errors.HypervisorError("The HVM CDROM image must either be a"
536 e09fdcfa Iustin Pop
                                   " regular file or a symlink pointing to"
537 e09fdcfa Iustin Pop
                                   " an existing regular file, not %s" %
538 e09fdcfa Iustin Pop
                                   iso_path)
539 f48148c3 Iustin Pop
540 65a6f9b7 Michael Hanselmann
  @classmethod
541 65a6f9b7 Michael Hanselmann
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
542 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
543 65a6f9b7 Michael Hanselmann

544 65a6f9b7 Michael Hanselmann
    """
545 65a6f9b7 Michael Hanselmann
    config = StringIO()
546 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
547 65a6f9b7 Michael Hanselmann
    config.write("kernel = '/usr/lib/xen/boot/hvmloader'\n")
548 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
549 8b3fd458 Iustin Pop
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
550 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
551 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
552 f48148c3 Iustin Pop
    if instance.hvparams[constants.HV_PAE]:
553 a21dda8b Iustin Pop
      config.write("pae = 1\n")
554 a21dda8b Iustin Pop
    else:
555 a21dda8b Iustin Pop
      config.write("pae = 0\n")
556 f48148c3 Iustin Pop
    if instance.hvparams[constants.HV_ACPI]:
557 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
558 a21dda8b Iustin Pop
    else:
559 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
560 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
561 65a6f9b7 Michael Hanselmann
    arch = os.uname()[4]
562 65a6f9b7 Michael Hanselmann
    if '64' in arch:
563 65a6f9b7 Michael Hanselmann
      config.write("device_model = '/usr/lib64/xen/bin/qemu-dm'\n")
564 65a6f9b7 Michael Hanselmann
    else:
565 65a6f9b7 Michael Hanselmann
      config.write("device_model = '/usr/lib/xen/bin/qemu-dm'\n")
566 f48148c3 Iustin Pop
    if instance.hvparams[constants.HV_BOOT_ORDER] is None:
567 65a6f9b7 Michael Hanselmann
      config.write("boot = '%s'\n" % constants.HT_HVM_DEFAULT_BOOT_ORDER)
568 65a6f9b7 Michael Hanselmann
    else:
569 f48148c3 Iustin Pop
      config.write("boot = '%s'\n" % instance.hvparams["boot_order"])
570 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
571 97efde45 Guido Trotter
    config.write("usb = 1\n")
572 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
573 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
574 f48148c3 Iustin Pop
    if instance.hvparams[constants.HV_VNC_BIND_ADDRESS] is None:
575 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
576 d0c11cf7 Alexander Schreiber
    else:
577 f48148c3 Iustin Pop
      config.write("vnclisten = '%s'\n" %
578 f48148c3 Iustin Pop
                   instance.hvparams["vnc_bind_address"])
579 65a6f9b7 Michael Hanselmann
580 65a6f9b7 Michael Hanselmann
    if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
581 65a6f9b7 Michael Hanselmann
      display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
582 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
583 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
584 65a6f9b7 Michael Hanselmann
    else:
585 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
586 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
587 65a6f9b7 Michael Hanselmann
588 65a6f9b7 Michael Hanselmann
    try:
589 78f66a17 Guido Trotter
      password = utils.ReadFile(constants.VNC_PASSWORD_FILE)
590 78f66a17 Guido Trotter
    except EnvironmentError, err:
591 78f66a17 Guido Trotter
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
592 78f66a17 Guido Trotter
                                   (constants.VNC_PASSWORD_FILE, err))
593 65a6f9b7 Michael Hanselmann
594 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
595 65a6f9b7 Michael Hanselmann
596 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
597 65a6f9b7 Michael Hanselmann
    config.write("localtime = 1\n")
598 65a6f9b7 Michael Hanselmann
599 65a6f9b7 Michael Hanselmann
    vif_data = []
600 f48148c3 Iustin Pop
    nic_type = instance.hvparams[constants.HV_NIC_TYPE]
601 f48148c3 Iustin Pop
    if nic_type is None:
602 f48148c3 Iustin Pop
      # ensure old instances don't change
603 f48148c3 Iustin Pop
      nic_type_str = ", type=ioemu"
604 f48148c3 Iustin Pop
    elif nic_type == constants.HT_HVM_DEV_PARAVIRTUAL:
605 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
606 f48148c3 Iustin Pop
    else:
607 f48148c3 Iustin Pop
      nic_type_str = ", model=%s, type=ioemu" % nic_type
608 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
609 f48148c3 Iustin Pop
      nic_str = "mac=%s, bridge=%s%s" % (nic.mac, nic.bridge, nic_type_str)
610 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
611 65a6f9b7 Michael Hanselmann
      if ip is not None:
612 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
613 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
614 65a6f9b7 Michael Hanselmann
615 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
616 a21dda8b Iustin Pop
    disk_data = cls._GetConfigFileDiskData(instance.disk_template,
617 a21dda8b Iustin Pop
                                            block_devices)
618 f48148c3 Iustin Pop
    disk_type = instance.hvparams[constants.HV_DISK_TYPE]
619 f48148c3 Iustin Pop
    if disk_type in (None, constants.HT_HVM_DEV_IOEMU):
620 5397e0b7 Alexander Schreiber
      replacement = ",ioemu:hd"
621 5397e0b7 Alexander Schreiber
    else:
622 5397e0b7 Alexander Schreiber
      replacement = ",hd"
623 5397e0b7 Alexander Schreiber
    disk_data = [line.replace(",sd", replacement) for line in disk_data]
624 f48148c3 Iustin Pop
    iso_path = instance.hvparams[constants.HV_CDROM_IMAGE_PATH]
625 f48148c3 Iustin Pop
    if iso_path:
626 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
627 a21dda8b Iustin Pop
      disk_data.append(iso)
628 a21dda8b Iustin Pop
629 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
630 a21dda8b Iustin Pop
631 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
632 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
633 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
634 65a6f9b7 Michael Hanselmann
    if extra_args:
635 65a6f9b7 Michael Hanselmann
      config.write("extra = '%s'\n" % extra_args)
636 65a6f9b7 Michael Hanselmann
    # just in case it exists
637 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
638 65a6f9b7 Michael Hanselmann
    try:
639 73cd67f4 Guido Trotter
      utils.WriteFile("/etc/xen/%s" % instance.name,
640 73cd67f4 Guido Trotter
                      data=config.getvalue())
641 73cd67f4 Guido Trotter
    except EnvironmentError, err:
642 73cd67f4 Guido Trotter
      raise errors.HypervisorError("Cannot write Xen instance confile"
643 73cd67f4 Guido Trotter
                                   " file /etc/xen/%s: %s" %
644 73cd67f4 Guido Trotter
                                   (instance.name, err))
645 73cd67f4 Guido Trotter
646 65a6f9b7 Michael Hanselmann
    return True