Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 9b94905f

History | View | Annotate | Download (20.8 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 7dd106d3 Iustin Pop
  REBOOT_RETRY_COUNT = 60
46 7dd106d3 Iustin Pop
  REBOOT_RETRY_INTERVAL = 10
47 65a6f9b7 Michael Hanselmann
48 3680f662 Guido Trotter
  ANCILLARY_FILES = [
49 3680f662 Guido Trotter
    '/etc/xen/xend-config.sxp',
50 3680f662 Guido Trotter
    '/etc/xen/scripts/vif-bridge',
51 3680f662 Guido Trotter
    ]
52 3680f662 Guido Trotter
53 5661b908 Iustin Pop
  @classmethod
54 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
55 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
56 65a6f9b7 Michael Hanselmann

57 65a6f9b7 Michael Hanselmann
    """
58 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
59 65a6f9b7 Michael Hanselmann
60 65a6f9b7 Michael Hanselmann
  @staticmethod
61 4390ccff Guido Trotter
  def _WriteConfigFileStatic(instance_name, data):
62 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
63 4390ccff Guido Trotter

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

66 4390ccff Guido Trotter
    """
67 4390ccff Guido Trotter
    utils.WriteFile("/etc/xen/%s" % instance_name, data=data)
68 4390ccff Guido Trotter
69 4390ccff Guido Trotter
  @staticmethod
70 4390ccff Guido Trotter
  def _ReadConfigFile(instance_name):
71 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
72 4390ccff Guido Trotter

73 4390ccff Guido Trotter
    """
74 4390ccff Guido Trotter
    try:
75 4390ccff Guido Trotter
      file_content = utils.ReadFile("/etc/xen/%s" % instance_name)
76 4390ccff Guido Trotter
    except EnvironmentError, err:
77 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
78 4390ccff Guido Trotter
    return file_content
79 4390ccff Guido Trotter
80 4390ccff Guido Trotter
  @staticmethod
81 53c776b5 Iustin Pop
  def _RemoveConfigFile(instance_name):
82 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
83 65a6f9b7 Michael Hanselmann

84 65a6f9b7 Michael Hanselmann
    """
85 53c776b5 Iustin Pop
    utils.RemoveFile("/etc/xen/%s" % instance_name)
86 65a6f9b7 Michael Hanselmann
87 65a6f9b7 Michael Hanselmann
  @staticmethod
88 65a6f9b7 Michael Hanselmann
  def _GetXMList(include_node):
89 65a6f9b7 Michael Hanselmann
    """Return the list of running instances.
90 65a6f9b7 Michael Hanselmann

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

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

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

139 65a6f9b7 Michael Hanselmann
    """
140 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
141 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
142 65a6f9b7 Michael Hanselmann
    return names
143 65a6f9b7 Michael Hanselmann
144 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
145 65a6f9b7 Michael Hanselmann
    """Get instance properties.
146 65a6f9b7 Michael Hanselmann

147 c41eea6e Iustin Pop
    @param instance_name: the instance name
148 c41eea6e Iustin Pop

149 c41eea6e Iustin Pop
    @return: tuple (name, id, memory, vcpus, stat, times)
150 65a6f9b7 Michael Hanselmann

151 65a6f9b7 Michael Hanselmann
    """
152 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(instance_name=="Domain-0")
153 65a6f9b7 Michael Hanselmann
    result = None
154 65a6f9b7 Michael Hanselmann
    for data in xm_list:
155 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
156 65a6f9b7 Michael Hanselmann
        result = data
157 65a6f9b7 Michael Hanselmann
        break
158 65a6f9b7 Michael Hanselmann
    return result
159 65a6f9b7 Michael Hanselmann
160 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
161 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
162 65a6f9b7 Michael Hanselmann

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

165 65a6f9b7 Michael Hanselmann
    """
166 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
167 65a6f9b7 Michael Hanselmann
    return xm_list
168 65a6f9b7 Michael Hanselmann
169 07813a9e Iustin Pop
  def StartInstance(self, instance, block_devices):
170 c41eea6e Iustin Pop
    """Start an instance.
171 c41eea6e Iustin Pop

172 c41eea6e Iustin Pop
    """
173 07813a9e Iustin Pop
    self._WriteConfigFile(instance, block_devices)
174 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "create", instance.name])
175 65a6f9b7 Michael Hanselmann
176 65a6f9b7 Michael Hanselmann
    if result.failed:
177 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
178 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
179 65a6f9b7 Michael Hanselmann
                                    result.output))
180 65a6f9b7 Michael Hanselmann
181 07b49e41 Guido Trotter
  def StopInstance(self, instance, force=False, retry=False):
182 c41eea6e Iustin Pop
    """Stop an instance.
183 c41eea6e Iustin Pop

184 c41eea6e Iustin Pop
    """
185 53c776b5 Iustin Pop
    self._RemoveConfigFile(instance.name)
186 65a6f9b7 Michael Hanselmann
    if force:
187 65a6f9b7 Michael Hanselmann
      command = ["xm", "destroy", instance.name]
188 65a6f9b7 Michael Hanselmann
    else:
189 65a6f9b7 Michael Hanselmann
      command = ["xm", "shutdown", instance.name]
190 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
191 65a6f9b7 Michael Hanselmann
192 65a6f9b7 Michael Hanselmann
    if result.failed:
193 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
194 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
195 3213d3c8 Iustin Pop
                                    result.output))
196 65a6f9b7 Michael Hanselmann
197 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
198 c41eea6e Iustin Pop
    """Reboot an instance.
199 c41eea6e Iustin Pop

200 c41eea6e Iustin Pop
    """
201 7dd106d3 Iustin Pop
    ini_info = self.GetInstanceInfo(instance.name)
202 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "reboot", instance.name])
203 65a6f9b7 Michael Hanselmann
204 65a6f9b7 Michael Hanselmann
    if result.failed:
205 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
206 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
207 3213d3c8 Iustin Pop
                                    result.output))
208 7dd106d3 Iustin Pop
    done = False
209 7dd106d3 Iustin Pop
    retries = self.REBOOT_RETRY_COUNT
210 7dd106d3 Iustin Pop
    while retries > 0:
211 7dd106d3 Iustin Pop
      new_info = self.GetInstanceInfo(instance.name)
212 7dd106d3 Iustin Pop
      # check if the domain ID has changed or the run time has
213 7dd106d3 Iustin Pop
      # decreased
214 7dd106d3 Iustin Pop
      if new_info[1] != ini_info[1] or new_info[5] < ini_info[5]:
215 7dd106d3 Iustin Pop
        done = True
216 7dd106d3 Iustin Pop
        break
217 7dd106d3 Iustin Pop
      time.sleep(self.REBOOT_RETRY_INTERVAL)
218 7dd106d3 Iustin Pop
      retries -= 1
219 7dd106d3 Iustin Pop
220 7dd106d3 Iustin Pop
    if not done:
221 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
222 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
223 7dd106d3 Iustin Pop
                                   (instance.name, ))
224 65a6f9b7 Michael Hanselmann
225 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
226 65a6f9b7 Michael Hanselmann
    """Return information about the node.
227 65a6f9b7 Michael Hanselmann

228 0105bad3 Iustin Pop
    @return: a dict with the following keys (memory values in MiB):
229 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
230 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
231 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
232 0105bad3 Iustin Pop
          - nr_cpus: total number of CPUs
233 0105bad3 Iustin Pop
          - nr_nodes: in a NUMA system, the number of domains
234 0105bad3 Iustin Pop
          - nr_sockets: the number of physical CPU sockets in the node
235 65a6f9b7 Michael Hanselmann

236 65a6f9b7 Michael Hanselmann
    """
237 65a6f9b7 Michael Hanselmann
    # note: in xen 3, memory has changed to total_memory
238 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
239 65a6f9b7 Michael Hanselmann
    if result.failed:
240 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
241 b48909c8 Iustin Pop
                    result.output)
242 65a6f9b7 Michael Hanselmann
      return None
243 65a6f9b7 Michael Hanselmann
244 65a6f9b7 Michael Hanselmann
    xmoutput = result.stdout.splitlines()
245 65a6f9b7 Michael Hanselmann
    result = {}
246 0105bad3 Iustin Pop
    cores_per_socket = threads_per_core = nr_cpus = None
247 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
248 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
249 65a6f9b7 Michael Hanselmann
250 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
251 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
252 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
253 65a6f9b7 Michael Hanselmann
        if key == 'memory' or key == 'total_memory':
254 65a6f9b7 Michael Hanselmann
          result['memory_total'] = int(val)
255 65a6f9b7 Michael Hanselmann
        elif key == 'free_memory':
256 65a6f9b7 Michael Hanselmann
          result['memory_free'] = int(val)
257 e8a4c138 Iustin Pop
        elif key == 'nr_cpus':
258 0105bad3 Iustin Pop
          nr_cpus = result['cpu_total'] = int(val)
259 0105bad3 Iustin Pop
        elif key == 'nr_nodes':
260 0105bad3 Iustin Pop
          result['cpu_nodes'] = int(val)
261 0105bad3 Iustin Pop
        elif key == 'cores_per_socket':
262 0105bad3 Iustin Pop
          cores_per_socket = int(val)
263 0105bad3 Iustin Pop
        elif key == 'threads_per_core':
264 0105bad3 Iustin Pop
          threads_per_core = int(val)
265 0105bad3 Iustin Pop
266 0105bad3 Iustin Pop
    if (cores_per_socket is not None and
267 0105bad3 Iustin Pop
        threads_per_core is not None and nr_cpus is not None):
268 0105bad3 Iustin Pop
      result['cpu_sockets'] = nr_cpus / (cores_per_socket * threads_per_core)
269 0105bad3 Iustin Pop
270 65a6f9b7 Michael Hanselmann
    dom0_info = self.GetInstanceInfo("Domain-0")
271 65a6f9b7 Michael Hanselmann
    if dom0_info is not None:
272 65a6f9b7 Michael Hanselmann
      result['memory_dom0'] = dom0_info[2]
273 65a6f9b7 Michael Hanselmann
274 65a6f9b7 Michael Hanselmann
    return result
275 65a6f9b7 Michael Hanselmann
276 637ce7f9 Guido Trotter
  @classmethod
277 5431b2e4 Guido Trotter
  def GetShellCommandForConsole(cls, instance, hvparams, beparams):
278 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
279 65a6f9b7 Michael Hanselmann

280 65a6f9b7 Michael Hanselmann
    """
281 04c4330c Alexander Schreiber
    return "xm console %s" % instance.name
282 04c4330c Alexander Schreiber
283 65a6f9b7 Michael Hanselmann
284 65a6f9b7 Michael Hanselmann
  def Verify(self):
285 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
286 65a6f9b7 Michael Hanselmann

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

289 65a6f9b7 Michael Hanselmann
    """
290 e3e66f02 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
291 e3e66f02 Michael Hanselmann
    if result.failed:
292 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
293 65a6f9b7 Michael Hanselmann
294 65a6f9b7 Michael Hanselmann
  @staticmethod
295 65a6f9b7 Michael Hanselmann
  def _GetConfigFileDiskData(disk_template, block_devices):
296 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
297 65a6f9b7 Michael Hanselmann

298 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
299 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
300 65a6f9b7 Michael Hanselmann

301 c41eea6e Iustin Pop
    @param disk_template: string containing instance disk template
302 c41eea6e Iustin Pop
    @param block_devices: list of tuples (cfdev, rldev):
303 c41eea6e Iustin Pop
        - cfdev: dict containing ganeti config disk part
304 c41eea6e Iustin Pop
        - rldev: ganeti.bdev.BlockDev object
305 65a6f9b7 Michael Hanselmann

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

308 65a6f9b7 Michael Hanselmann
    """
309 65a6f9b7 Michael Hanselmann
    FILE_DRIVER_MAP = {
310 65a6f9b7 Michael Hanselmann
      constants.FD_LOOP: "file",
311 65a6f9b7 Michael Hanselmann
      constants.FD_BLKTAP: "tap:aio",
312 65a6f9b7 Michael Hanselmann
      }
313 65a6f9b7 Michael Hanselmann
    disk_data = []
314 2864f2d9 Iustin Pop
    if len(block_devices) > 24:
315 2864f2d9 Iustin Pop
      # 'z' - 'a' = 24
316 2864f2d9 Iustin Pop
      raise errors.HypervisorError("Too many disks")
317 2864f2d9 Iustin Pop
    # FIXME: instead of this hardcoding here, each of PVM/HVM should
318 2864f2d9 Iustin Pop
    # directly export their info (currently HVM will just sed this info)
319 2864f2d9 Iustin Pop
    namespace = ["sd" + chr(i + ord('a')) for i in range(24)]
320 069cfbf1 Iustin Pop
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
321 d34b16d7 Iustin Pop
      if cfdev.mode == constants.DISK_RDWR:
322 d34b16d7 Iustin Pop
        mode = "w"
323 d34b16d7 Iustin Pop
      else:
324 d34b16d7 Iustin Pop
        mode = "r"
325 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
326 d34b16d7 Iustin Pop
        line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
327 d34b16d7 Iustin Pop
                                  dev_path, sd_name, mode)
328 65a6f9b7 Michael Hanselmann
      else:
329 d34b16d7 Iustin Pop
        line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
330 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
331 65a6f9b7 Michael Hanselmann
332 65a6f9b7 Michael Hanselmann
    return disk_data
333 65a6f9b7 Michael Hanselmann
334 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
335 4390ccff Guido Trotter
    """Get instance information to perform a migration.
336 4390ccff Guido Trotter

337 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
338 4390ccff Guido Trotter
    @param instance: instance to be migrated
339 4390ccff Guido Trotter
    @rtype: string
340 4390ccff Guido Trotter
    @return: content of the xen config file
341 4390ccff Guido Trotter

342 4390ccff Guido Trotter
    """
343 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
344 4390ccff Guido Trotter
345 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
346 4390ccff Guido Trotter
    """Prepare to accept an instance.
347 4390ccff Guido Trotter

348 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
349 4390ccff Guido Trotter
    @param instance: instance to be accepted
350 4390ccff Guido Trotter
    @type info: string
351 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
352 4390ccff Guido Trotter
    @type target: string
353 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
354 4390ccff Guido Trotter

355 4390ccff Guido Trotter
    """
356 4390ccff Guido Trotter
    pass
357 4390ccff Guido Trotter
358 4390ccff Guido Trotter
  def FinalizeMigration(self, instance, info, success):
359 4390ccff Guido Trotter
    """Finalize an instance migration.
360 4390ccff Guido Trotter

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

364 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
365 4390ccff Guido Trotter
    @param instance: instance whose migration is being aborted
366 4390ccff Guido Trotter
    @type info: string
367 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
368 4390ccff Guido Trotter
    @type success: boolean
369 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
370 4390ccff Guido Trotter

371 4390ccff Guido Trotter
    """
372 4390ccff Guido Trotter
    if success:
373 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
374 4390ccff Guido Trotter
375 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
376 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
377 6e7275c0 Iustin Pop

378 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
379 6e7275c0 Iustin Pop
    currently running.
380 6e7275c0 Iustin Pop

381 fdf7f055 Guido Trotter
    @type instance: string
382 fdf7f055 Guido Trotter
    @param instance: instance name
383 fdf7f055 Guido Trotter
    @type target: string
384 fdf7f055 Guido Trotter
    @param target: ip address of the target node
385 fdf7f055 Guido Trotter
    @type live: boolean
386 fdf7f055 Guido Trotter
    @param live: perform a live migration
387 fdf7f055 Guido Trotter

388 6e7275c0 Iustin Pop
    """
389 6e7275c0 Iustin Pop
    if self.GetInstanceInfo(instance) is None:
390 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
391 6e7275c0 Iustin Pop
    args = ["xm", "migrate"]
392 6e7275c0 Iustin Pop
    if live:
393 6e7275c0 Iustin Pop
      args.append("-l")
394 6e7275c0 Iustin Pop
    args.extend([instance, target])
395 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
396 6e7275c0 Iustin Pop
    if result.failed:
397 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
398 6e7275c0 Iustin Pop
                                   (instance, result.output))
399 53c776b5 Iustin Pop
    # remove old xen file after migration succeeded
400 53c776b5 Iustin Pop
    try:
401 53c776b5 Iustin Pop
      self._RemoveConfigFile(instance)
402 c979d253 Iustin Pop
    except EnvironmentError:
403 c979d253 Iustin Pop
      logging.exception("Failure while removing instance config file")
404 6e7275c0 Iustin Pop
405 f5118ade Iustin Pop
  @classmethod
406 f5118ade Iustin Pop
  def PowercycleNode(cls):
407 f5118ade Iustin Pop
    """Xen-specific powercycle.
408 f5118ade Iustin Pop

409 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
410 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
411 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
412 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
413 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
414 f5118ade Iustin Pop
    daemon is not working.
415 f5118ade Iustin Pop

416 f5118ade Iustin Pop
    """
417 f5118ade Iustin Pop
    try:
418 f5118ade Iustin Pop
      cls.LinuxPowercycle()
419 f5118ade Iustin Pop
    finally:
420 f5118ade Iustin Pop
      utils.RunCmd(["xm", "debug", "R"])
421 f5118ade Iustin Pop
422 65a6f9b7 Michael Hanselmann
423 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
424 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
425 65a6f9b7 Michael Hanselmann
426 205ab586 Iustin Pop
  PARAMETERS = {
427 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
428 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
429 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
430 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
431 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
432 205ab586 Iustin Pop
    constants.HV_ROOT_PATH: hv_base.REQUIRED_CHECK,
433 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
434 205ab586 Iustin Pop
    }
435 f48148c3 Iustin Pop
436 65a6f9b7 Michael Hanselmann
  @classmethod
437 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
438 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
439 65a6f9b7 Michael Hanselmann

440 65a6f9b7 Michael Hanselmann
    """
441 a985b417 Iustin Pop
    hvp = instance.hvparams
442 65a6f9b7 Michael Hanselmann
    config = StringIO()
443 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
444 65a6f9b7 Michael Hanselmann
445 2f2dbb4b Jun Futagawa
    # if bootloader is True, use bootloader instead of kernel and ramdisk
446 2f2dbb4b Jun Futagawa
    # parameters.
447 2f2dbb4b Jun Futagawa
    if hvp[constants.HV_USE_BOOTLOADER]:
448 2f2dbb4b Jun Futagawa
      # bootloader handling
449 2f2dbb4b Jun Futagawa
      bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
450 2f2dbb4b Jun Futagawa
      if bootloader_path:
451 2f2dbb4b Jun Futagawa
        config.write("bootloader = '%s'\n" % bootloader_path)
452 2f2dbb4b Jun Futagawa
      else:
453 2f2dbb4b Jun Futagawa
        raise errors.HypervisorError("Bootloader enabled, but missing"
454 2f2dbb4b Jun Futagawa
                                     " bootloader path")
455 65a6f9b7 Michael Hanselmann
456 2f2dbb4b Jun Futagawa
      bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
457 2f2dbb4b Jun Futagawa
      if bootloader_args:
458 2f2dbb4b Jun Futagawa
        config.write("bootargs = '%s'\n" % bootloader_args)
459 2f2dbb4b Jun Futagawa
    else:
460 2f2dbb4b Jun Futagawa
      # kernel handling
461 2f2dbb4b Jun Futagawa
      kpath = hvp[constants.HV_KERNEL_PATH]
462 2f2dbb4b Jun Futagawa
      config.write("kernel = '%s'\n" % kpath)
463 2f2dbb4b Jun Futagawa
464 2f2dbb4b Jun Futagawa
      # initrd handling
465 2f2dbb4b Jun Futagawa
      initrd_path = hvp[constants.HV_INITRD_PATH]
466 2f2dbb4b Jun Futagawa
      if initrd_path:
467 2f2dbb4b Jun Futagawa
        config.write("ramdisk = '%s'\n" % initrd_path)
468 65a6f9b7 Michael Hanselmann
469 65a6f9b7 Michael Hanselmann
    # rest of the settings
470 8b3fd458 Iustin Pop
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
471 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
472 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
473 65a6f9b7 Michael Hanselmann
474 65a6f9b7 Michael Hanselmann
    vif_data = []
475 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
476 503b97a9 Guido Trotter
      nic_str = "mac=%s" % (nic.mac)
477 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
478 65a6f9b7 Michael Hanselmann
      if ip is not None:
479 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
480 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
481 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
482 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
483 65a6f9b7 Michael Hanselmann
484 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
485 65a6f9b7 Michael Hanselmann
    config.write("disk = [%s]\n" % ",".join(
486 65a6f9b7 Michael Hanselmann
                 cls._GetConfigFileDiskData(instance.disk_template,
487 65a6f9b7 Michael Hanselmann
                                            block_devices)))
488 074ca009 Guido Trotter
489 07813a9e Iustin Pop
    config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
490 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
491 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
492 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
493 07813a9e Iustin Pop
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
494 65a6f9b7 Michael Hanselmann
    # just in case it exists
495 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
496 65a6f9b7 Michael Hanselmann
    try:
497 a985b417 Iustin Pop
      utils.WriteFile("/etc/xen/%s" % instance.name, data=config.getvalue())
498 73cd67f4 Guido Trotter
    except EnvironmentError, err:
499 73cd67f4 Guido Trotter
      raise errors.HypervisorError("Cannot write Xen instance confile"
500 73cd67f4 Guido Trotter
                                   " file /etc/xen/%s: %s" %
501 73cd67f4 Guido Trotter
                                   (instance.name, err))
502 73cd67f4 Guido Trotter
503 65a6f9b7 Michael Hanselmann
    return True
504 65a6f9b7 Michael Hanselmann
505 65a6f9b7 Michael Hanselmann
506 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
507 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
508 65a6f9b7 Michael Hanselmann
509 69b99987 Michael Hanselmann
  ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
510 69b99987 Michael Hanselmann
    constants.VNC_PASSWORD_FILE,
511 69b99987 Michael Hanselmann
    ]
512 3680f662 Guido Trotter
513 205ab586 Iustin Pop
  PARAMETERS = {
514 205ab586 Iustin Pop
    constants.HV_ACPI: hv_base.NO_CHECK,
515 016d04b3 Michael Hanselmann
    constants.HV_BOOT_ORDER: (True, ) +
516 016d04b3 Michael Hanselmann
      (lambda x: x and len(x.strip("acdn")) == 0,
517 016d04b3 Michael Hanselmann
       "Invalid boot order specified, must be one or more of [acdn]",
518 016d04b3 Michael Hanselmann
       None, None),
519 205ab586 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
520 016d04b3 Michael Hanselmann
    constants.HV_DISK_TYPE:
521 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
522 016d04b3 Michael Hanselmann
    constants.HV_NIC_TYPE:
523 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
524 205ab586 Iustin Pop
    constants.HV_PAE: hv_base.NO_CHECK,
525 016d04b3 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS:
526 016d04b3 Michael Hanselmann
      (False, utils.IsValidIP,
527 016d04b3 Michael Hanselmann
       "VNC bind address is not a valid IP address", None, None),
528 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
529 205ab586 Iustin Pop
    constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
530 6e6bb8d5 Guido Trotter
    constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
531 205ab586 Iustin Pop
    }
532 09ea8710 Iustin Pop
533 65a6f9b7 Michael Hanselmann
  @classmethod
534 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
535 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
536 65a6f9b7 Michael Hanselmann

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