Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 5023934a

History | View | Annotate | Download (15.4 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 65a6f9b7 Michael Hanselmann
from cStringIO import StringIO
30 65a6f9b7 Michael Hanselmann
31 65a6f9b7 Michael Hanselmann
from ganeti import constants
32 65a6f9b7 Michael Hanselmann
from ganeti import errors
33 65a6f9b7 Michael Hanselmann
from ganeti import logger
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 65a6f9b7 Michael Hanselmann
  @staticmethod
47 65a6f9b7 Michael Hanselmann
  def _WriteConfigFile(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 65a6f9b7 Michael Hanselmann
  def _RemoveConfigFile(instance):
55 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
56 65a6f9b7 Michael Hanselmann

57 65a6f9b7 Michael Hanselmann
    """
58 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/%s" % instance.name)
59 65a6f9b7 Michael Hanselmann
60 65a6f9b7 Michael Hanselmann
  @staticmethod
61 65a6f9b7 Michael Hanselmann
  def _GetXMList(include_node):
62 65a6f9b7 Michael Hanselmann
    """Return the list of running instances.
63 65a6f9b7 Michael Hanselmann

64 65a6f9b7 Michael Hanselmann
    If the `include_node` argument is True, then we return information
65 65a6f9b7 Michael Hanselmann
    for dom0 also, otherwise we filter that from the return value.
66 65a6f9b7 Michael Hanselmann

67 65a6f9b7 Michael Hanselmann
    The return value is a list of (name, id, memory, vcpus, state, time spent)
68 65a6f9b7 Michael Hanselmann

69 65a6f9b7 Michael Hanselmann
    """
70 65a6f9b7 Michael Hanselmann
    for dummy in range(5):
71 65a6f9b7 Michael Hanselmann
      result = utils.RunCmd(["xm", "list"])
72 65a6f9b7 Michael Hanselmann
      if not result.failed:
73 65a6f9b7 Michael Hanselmann
        break
74 65a6f9b7 Michael Hanselmann
      logger.Error("xm list failed (%s): %s" % (result.fail_reason,
75 65a6f9b7 Michael Hanselmann
                                                result.output))
76 65a6f9b7 Michael Hanselmann
      time.sleep(1)
77 65a6f9b7 Michael Hanselmann
78 65a6f9b7 Michael Hanselmann
    if result.failed:
79 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("xm list failed, retries"
80 65a6f9b7 Michael Hanselmann
                                   " exceeded (%s): %s" %
81 65a6f9b7 Michael Hanselmann
                                   (result.fail_reason, result.stderr))
82 65a6f9b7 Michael Hanselmann
83 65a6f9b7 Michael Hanselmann
    # skip over the heading
84 65a6f9b7 Michael Hanselmann
    lines = result.stdout.splitlines()[1:]
85 65a6f9b7 Michael Hanselmann
    result = []
86 65a6f9b7 Michael Hanselmann
    for line in lines:
87 65a6f9b7 Michael Hanselmann
      # The format of lines is:
88 65a6f9b7 Michael Hanselmann
      # Name      ID Mem(MiB) VCPUs State  Time(s)
89 65a6f9b7 Michael Hanselmann
      # Domain-0   0  3418     4 r-----    266.2
90 65a6f9b7 Michael Hanselmann
      data = line.split()
91 65a6f9b7 Michael Hanselmann
      if len(data) != 6:
92 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
93 65a6f9b7 Michael Hanselmann
                                     " line: %s" % line)
94 65a6f9b7 Michael Hanselmann
      try:
95 65a6f9b7 Michael Hanselmann
        data[1] = int(data[1])
96 65a6f9b7 Michael Hanselmann
        data[2] = int(data[2])
97 65a6f9b7 Michael Hanselmann
        data[3] = int(data[3])
98 65a6f9b7 Michael Hanselmann
        data[5] = float(data[5])
99 65a6f9b7 Michael Hanselmann
      except ValueError, err:
100 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
101 65a6f9b7 Michael Hanselmann
                                     " line: %s, error: %s" % (line, err))
102 65a6f9b7 Michael Hanselmann
103 65a6f9b7 Michael Hanselmann
      # skip the Domain-0 (optional)
104 65a6f9b7 Michael Hanselmann
      if include_node or data[0] != 'Domain-0':
105 65a6f9b7 Michael Hanselmann
        result.append(data)
106 65a6f9b7 Michael Hanselmann
107 65a6f9b7 Michael Hanselmann
    return result
108 65a6f9b7 Michael Hanselmann
109 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
110 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
111 65a6f9b7 Michael Hanselmann

112 65a6f9b7 Michael Hanselmann
    """
113 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
114 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
115 65a6f9b7 Michael Hanselmann
    return names
116 65a6f9b7 Michael Hanselmann
117 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
118 65a6f9b7 Michael Hanselmann
    """Get instance properties.
119 65a6f9b7 Michael Hanselmann

120 65a6f9b7 Michael Hanselmann
    Args:
121 65a6f9b7 Michael Hanselmann
      instance_name: the instance name
122 65a6f9b7 Michael Hanselmann

123 65a6f9b7 Michael Hanselmann
    Returns:
124 65a6f9b7 Michael Hanselmann
      (name, id, memory, vcpus, stat, times)
125 65a6f9b7 Michael Hanselmann
    """
126 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(instance_name=="Domain-0")
127 65a6f9b7 Michael Hanselmann
    result = None
128 65a6f9b7 Michael Hanselmann
    for data in xm_list:
129 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
130 65a6f9b7 Michael Hanselmann
        result = data
131 65a6f9b7 Michael Hanselmann
        break
132 65a6f9b7 Michael Hanselmann
    return result
133 65a6f9b7 Michael Hanselmann
134 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
135 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
136 65a6f9b7 Michael Hanselmann

137 65a6f9b7 Michael Hanselmann
    Returns:
138 65a6f9b7 Michael Hanselmann
      [(name, id, memory, vcpus, stat, times),...]
139 65a6f9b7 Michael Hanselmann
    """
140 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
141 65a6f9b7 Michael Hanselmann
    return xm_list
142 65a6f9b7 Michael Hanselmann
143 65a6f9b7 Michael Hanselmann
  def StartInstance(self, instance, block_devices, extra_args):
144 65a6f9b7 Michael Hanselmann
    """Start an instance."""
145 65a6f9b7 Michael Hanselmann
    self._WriteConfigFile(instance, block_devices, extra_args)
146 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "create", instance.name])
147 65a6f9b7 Michael Hanselmann
148 65a6f9b7 Michael Hanselmann
    if result.failed:
149 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
150 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
151 65a6f9b7 Michael Hanselmann
                                    result.output))
152 65a6f9b7 Michael Hanselmann
153 65a6f9b7 Michael Hanselmann
  def StopInstance(self, instance, force=False):
154 65a6f9b7 Michael Hanselmann
    """Stop an instance."""
155 65a6f9b7 Michael Hanselmann
    self._RemoveConfigFile(instance)
156 65a6f9b7 Michael Hanselmann
    if force:
157 65a6f9b7 Michael Hanselmann
      command = ["xm", "destroy", instance.name]
158 65a6f9b7 Michael Hanselmann
    else:
159 65a6f9b7 Michael Hanselmann
      command = ["xm", "shutdown", instance.name]
160 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
161 65a6f9b7 Michael Hanselmann
162 65a6f9b7 Michael Hanselmann
    if result.failed:
163 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
164 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason))
165 65a6f9b7 Michael Hanselmann
166 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
167 65a6f9b7 Michael Hanselmann
    """Reboot an instance."""
168 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "reboot", instance.name])
169 65a6f9b7 Michael Hanselmann
170 65a6f9b7 Michael Hanselmann
    if result.failed:
171 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to reboot instance %s: %s" %
172 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason))
173 65a6f9b7 Michael Hanselmann
174 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
175 65a6f9b7 Michael Hanselmann
    """Return information about the node.
176 65a6f9b7 Michael Hanselmann

177 65a6f9b7 Michael Hanselmann
    The return value is a dict, which has to have the following items:
178 65a6f9b7 Michael Hanselmann
      (all values in MiB)
179 65a6f9b7 Michael Hanselmann
      - memory_total: the total memory size on the node
180 65a6f9b7 Michael Hanselmann
      - memory_free: the available memory on the node for instances
181 65a6f9b7 Michael Hanselmann
      - memory_dom0: the memory used by the node itself, if available
182 65a6f9b7 Michael Hanselmann

183 65a6f9b7 Michael Hanselmann
    """
184 65a6f9b7 Michael Hanselmann
    # note: in xen 3, memory has changed to total_memory
185 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
186 65a6f9b7 Michael Hanselmann
    if result.failed:
187 65a6f9b7 Michael Hanselmann
      logger.Error("Can't run 'xm info': %s" % result.fail_reason)
188 65a6f9b7 Michael Hanselmann
      return None
189 65a6f9b7 Michael Hanselmann
190 65a6f9b7 Michael Hanselmann
    xmoutput = result.stdout.splitlines()
191 65a6f9b7 Michael Hanselmann
    result = {}
192 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
193 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
194 65a6f9b7 Michael Hanselmann
195 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
196 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
197 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
198 65a6f9b7 Michael Hanselmann
        if key == 'memory' or key == 'total_memory':
199 65a6f9b7 Michael Hanselmann
          result['memory_total'] = int(val)
200 65a6f9b7 Michael Hanselmann
        elif key == 'free_memory':
201 65a6f9b7 Michael Hanselmann
          result['memory_free'] = int(val)
202 e8a4c138 Iustin Pop
        elif key == 'nr_cpus':
203 e8a4c138 Iustin Pop
          result['cpu_total'] = int(val)
204 65a6f9b7 Michael Hanselmann
    dom0_info = self.GetInstanceInfo("Domain-0")
205 65a6f9b7 Michael Hanselmann
    if dom0_info is not None:
206 65a6f9b7 Michael Hanselmann
      result['memory_dom0'] = dom0_info[2]
207 65a6f9b7 Michael Hanselmann
208 65a6f9b7 Michael Hanselmann
    return result
209 65a6f9b7 Michael Hanselmann
210 65a6f9b7 Michael Hanselmann
  @staticmethod
211 65a6f9b7 Michael Hanselmann
  def GetShellCommandForConsole(instance):
212 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
213 65a6f9b7 Michael Hanselmann

214 65a6f9b7 Michael Hanselmann
    """
215 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
216 65a6f9b7 Michael Hanselmann
217 65a6f9b7 Michael Hanselmann
  def Verify(self):
218 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
219 65a6f9b7 Michael Hanselmann

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

222 65a6f9b7 Michael Hanselmann
    """
223 e3e66f02 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
224 e3e66f02 Michael Hanselmann
    if result.failed:
225 e3e66f02 Michael Hanselmann
      return "'xm info' failed: %s" % result.fail_reason
226 65a6f9b7 Michael Hanselmann
227 65a6f9b7 Michael Hanselmann
  @staticmethod
228 65a6f9b7 Michael Hanselmann
  def _GetConfigFileDiskData(disk_template, block_devices):
229 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
230 65a6f9b7 Michael Hanselmann

231 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
232 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
233 65a6f9b7 Michael Hanselmann

234 65a6f9b7 Michael Hanselmann
    Args:
235 65a6f9b7 Michael Hanselmann
      disk_template: String containing instance disk template
236 65a6f9b7 Michael Hanselmann
      block_devices: List[tuple1,tuple2,...]
237 65a6f9b7 Michael Hanselmann
        tuple: (cfdev, rldev)
238 65a6f9b7 Michael Hanselmann
          cfdev: dict containing ganeti config disk part
239 65a6f9b7 Michael Hanselmann
          rldev: ganeti.bdev.BlockDev object
240 65a6f9b7 Michael Hanselmann

241 65a6f9b7 Michael Hanselmann
    Returns:
242 65a6f9b7 Michael Hanselmann
      String containing disk directive for xen instance config file
243 65a6f9b7 Michael Hanselmann

244 65a6f9b7 Michael Hanselmann
    """
245 65a6f9b7 Michael Hanselmann
    FILE_DRIVER_MAP = {
246 65a6f9b7 Michael Hanselmann
      constants.FD_LOOP: "file",
247 65a6f9b7 Michael Hanselmann
      constants.FD_BLKTAP: "tap:aio",
248 65a6f9b7 Michael Hanselmann
      }
249 65a6f9b7 Michael Hanselmann
    disk_data = []
250 65a6f9b7 Michael Hanselmann
    for cfdev, rldev in block_devices:
251 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
252 65a6f9b7 Michael Hanselmann
        line = "'%s:%s,%s,w'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
253 65a6f9b7 Michael Hanselmann
                                 rldev.dev_path, cfdev.iv_name)
254 65a6f9b7 Michael Hanselmann
      else:
255 65a6f9b7 Michael Hanselmann
        line = "'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
256 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
257 65a6f9b7 Michael Hanselmann
258 65a6f9b7 Michael Hanselmann
    return disk_data
259 65a6f9b7 Michael Hanselmann
260 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
261 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
262 6e7275c0 Iustin Pop

263 6e7275c0 Iustin Pop
    Arguments:
264 6e7275c0 Iustin Pop
      - instance: the name of the instance
265 6e7275c0 Iustin Pop
      - target: the ip of the target node
266 6e7275c0 Iustin Pop
      - live: whether to do live migration or not
267 6e7275c0 Iustin Pop

268 6e7275c0 Iustin Pop
    Returns: none, errors will be signaled by exception.
269 6e7275c0 Iustin Pop

270 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
271 6e7275c0 Iustin Pop
    currently running.
272 6e7275c0 Iustin Pop

273 6e7275c0 Iustin Pop
    """
274 6e7275c0 Iustin Pop
    if self.GetInstanceInfo(instance) is None:
275 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
276 6e7275c0 Iustin Pop
    args = ["xm", "migrate"]
277 6e7275c0 Iustin Pop
    if live:
278 6e7275c0 Iustin Pop
      args.append("-l")
279 6e7275c0 Iustin Pop
    args.extend([instance, target])
280 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
281 6e7275c0 Iustin Pop
    if result.failed:
282 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
283 6e7275c0 Iustin Pop
                                   (instance, result.output))
284 6e7275c0 Iustin Pop
285 65a6f9b7 Michael Hanselmann
286 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
287 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
288 65a6f9b7 Michael Hanselmann
289 65a6f9b7 Michael Hanselmann
  @classmethod
290 65a6f9b7 Michael Hanselmann
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
291 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
292 65a6f9b7 Michael Hanselmann

293 65a6f9b7 Michael Hanselmann
    """
294 65a6f9b7 Michael Hanselmann
    config = StringIO()
295 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
296 65a6f9b7 Michael Hanselmann
297 65a6f9b7 Michael Hanselmann
    # kernel handling
298 65a6f9b7 Michael Hanselmann
    if instance.kernel_path in (None, constants.VALUE_DEFAULT):
299 65a6f9b7 Michael Hanselmann
      kpath = constants.XEN_KERNEL
300 65a6f9b7 Michael Hanselmann
    else:
301 65a6f9b7 Michael Hanselmann
      if not os.path.exists(instance.kernel_path):
302 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("The kernel %s for instance %s is"
303 65a6f9b7 Michael Hanselmann
                                     " missing" % (instance.kernel_path,
304 65a6f9b7 Michael Hanselmann
                                                   instance.name))
305 65a6f9b7 Michael Hanselmann
      kpath = instance.kernel_path
306 65a6f9b7 Michael Hanselmann
    config.write("kernel = '%s'\n" % kpath)
307 65a6f9b7 Michael Hanselmann
308 65a6f9b7 Michael Hanselmann
    # initrd handling
309 65a6f9b7 Michael Hanselmann
    if instance.initrd_path in (None, constants.VALUE_DEFAULT):
310 65a6f9b7 Michael Hanselmann
      if os.path.exists(constants.XEN_INITRD):
311 65a6f9b7 Michael Hanselmann
        initrd_path = constants.XEN_INITRD
312 65a6f9b7 Michael Hanselmann
      else:
313 65a6f9b7 Michael Hanselmann
        initrd_path = None
314 65a6f9b7 Michael Hanselmann
    elif instance.initrd_path == constants.VALUE_NONE:
315 65a6f9b7 Michael Hanselmann
      initrd_path = None
316 65a6f9b7 Michael Hanselmann
    else:
317 65a6f9b7 Michael Hanselmann
      if not os.path.exists(instance.initrd_path):
318 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("The initrd %s for instance %s is"
319 65a6f9b7 Michael Hanselmann
                                     " missing" % (instance.initrd_path,
320 65a6f9b7 Michael Hanselmann
                                                   instance.name))
321 65a6f9b7 Michael Hanselmann
      initrd_path = instance.initrd_path
322 65a6f9b7 Michael Hanselmann
323 65a6f9b7 Michael Hanselmann
    if initrd_path:
324 65a6f9b7 Michael Hanselmann
      config.write("ramdisk = '%s'\n" % initrd_path)
325 65a6f9b7 Michael Hanselmann
326 65a6f9b7 Michael Hanselmann
    # rest of the settings
327 65a6f9b7 Michael Hanselmann
    config.write("memory = %d\n" % instance.memory)
328 65a6f9b7 Michael Hanselmann
    config.write("vcpus = %d\n" % instance.vcpus)
329 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
330 65a6f9b7 Michael Hanselmann
331 65a6f9b7 Michael Hanselmann
    vif_data = []
332 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
333 65a6f9b7 Michael Hanselmann
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
334 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
335 65a6f9b7 Michael Hanselmann
      if ip is not None:
336 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
337 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
338 65a6f9b7 Michael Hanselmann
339 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
340 65a6f9b7 Michael Hanselmann
    config.write("disk = [%s]\n" % ",".join(
341 65a6f9b7 Michael Hanselmann
                 cls._GetConfigFileDiskData(instance.disk_template,
342 65a6f9b7 Michael Hanselmann
                                            block_devices)))
343 65a6f9b7 Michael Hanselmann
    config.write("root = '/dev/sda ro'\n")
344 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
345 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
346 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
347 65a6f9b7 Michael Hanselmann
    if extra_args:
348 65a6f9b7 Michael Hanselmann
      config.write("extra = '%s'\n" % extra_args)
349 65a6f9b7 Michael Hanselmann
    # just in case it exists
350 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
351 65a6f9b7 Michael Hanselmann
    try:
352 65a6f9b7 Michael Hanselmann
      f = open("/etc/xen/%s" % instance.name, "w")
353 65a6f9b7 Michael Hanselmann
      try:
354 65a6f9b7 Michael Hanselmann
        f.write(config.getvalue())
355 65a6f9b7 Michael Hanselmann
      finally:
356 65a6f9b7 Michael Hanselmann
        f.close()
357 65a6f9b7 Michael Hanselmann
    except IOError, err:
358 65a6f9b7 Michael Hanselmann
      raise errors.OpExecError("Cannot write Xen instance confile"
359 65a6f9b7 Michael Hanselmann
                               " file /etc/xen/%s: %s" % (instance.name, err))
360 65a6f9b7 Michael Hanselmann
    return True
361 65a6f9b7 Michael Hanselmann
362 65a6f9b7 Michael Hanselmann
  @staticmethod
363 65a6f9b7 Michael Hanselmann
  def GetShellCommandForConsole(instance):
364 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
365 65a6f9b7 Michael Hanselmann

366 65a6f9b7 Michael Hanselmann
    """
367 65a6f9b7 Michael Hanselmann
    return "xm console %s" % instance.name
368 65a6f9b7 Michael Hanselmann
369 65a6f9b7 Michael Hanselmann
370 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
371 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
372 65a6f9b7 Michael Hanselmann
373 65a6f9b7 Michael Hanselmann
  @classmethod
374 65a6f9b7 Michael Hanselmann
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
375 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
376 65a6f9b7 Michael Hanselmann

377 65a6f9b7 Michael Hanselmann
    """
378 65a6f9b7 Michael Hanselmann
    config = StringIO()
379 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
380 65a6f9b7 Michael Hanselmann
    config.write("kernel = '/usr/lib/xen/boot/hvmloader'\n")
381 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
382 65a6f9b7 Michael Hanselmann
    config.write("memory = %d\n" % instance.memory)
383 65a6f9b7 Michael Hanselmann
    config.write("vcpus = %d\n" % instance.vcpus)
384 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
385 a21dda8b Iustin Pop
    if instance.hvm_pae:
386 a21dda8b Iustin Pop
      config.write("pae = 1\n")
387 a21dda8b Iustin Pop
    else:
388 a21dda8b Iustin Pop
      config.write("pae = 0\n")
389 a21dda8b Iustin Pop
    if instance.hvm_acpi:
390 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
391 a21dda8b Iustin Pop
    else:
392 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
393 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
394 65a6f9b7 Michael Hanselmann
    arch = os.uname()[4]
395 65a6f9b7 Michael Hanselmann
    if '64' in arch:
396 65a6f9b7 Michael Hanselmann
      config.write("device_model = '/usr/lib64/xen/bin/qemu-dm'\n")
397 65a6f9b7 Michael Hanselmann
    else:
398 65a6f9b7 Michael Hanselmann
      config.write("device_model = '/usr/lib/xen/bin/qemu-dm'\n")
399 65a6f9b7 Michael Hanselmann
    if instance.hvm_boot_order is None:
400 65a6f9b7 Michael Hanselmann
      config.write("boot = '%s'\n" % constants.HT_HVM_DEFAULT_BOOT_ORDER)
401 65a6f9b7 Michael Hanselmann
    else:
402 65a6f9b7 Michael Hanselmann
      config.write("boot = '%s'\n" % instance.hvm_boot_order)
403 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
404 65a6f9b7 Michael Hanselmann
    config.write("usb = 1\n");
405 65a6f9b7 Michael Hanselmann
    config.write("usbdevice = 'tablet'\n");
406 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
407 a21dda8b Iustin Pop
    config.write("vnclisten = '%s'\n" % instance.vnc_bind_address)
408 65a6f9b7 Michael Hanselmann
409 65a6f9b7 Michael Hanselmann
    if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
410 65a6f9b7 Michael Hanselmann
      display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
411 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
412 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
413 65a6f9b7 Michael Hanselmann
    else:
414 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
415 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
416 65a6f9b7 Michael Hanselmann
417 65a6f9b7 Michael Hanselmann
    try:
418 65a6f9b7 Michael Hanselmann
      password_file = open(constants.VNC_PASSWORD_FILE, "r")
419 65a6f9b7 Michael Hanselmann
      try:
420 65a6f9b7 Michael Hanselmann
        password = password_file.readline()
421 65a6f9b7 Michael Hanselmann
      finally:
422 65a6f9b7 Michael Hanselmann
        password_file.close()
423 65a6f9b7 Michael Hanselmann
    except IOError:
424 65a6f9b7 Michael Hanselmann
      raise errors.OpExecError("failed to open VNC password file %s " %
425 65a6f9b7 Michael Hanselmann
                               constants.VNC_PASSWORD_FILE)
426 65a6f9b7 Michael Hanselmann
427 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
428 65a6f9b7 Michael Hanselmann
429 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
430 65a6f9b7 Michael Hanselmann
    config.write("localtime = 1\n")
431 65a6f9b7 Michael Hanselmann
432 65a6f9b7 Michael Hanselmann
    vif_data = []
433 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
434 65a6f9b7 Michael Hanselmann
      nic_str = "mac=%s, bridge=%s, type=ioemu" % (nic.mac, nic.bridge)
435 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
436 65a6f9b7 Michael Hanselmann
      if ip is not None:
437 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
438 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
439 65a6f9b7 Michael Hanselmann
440 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
441 a21dda8b Iustin Pop
    disk_data = cls._GetConfigFileDiskData(instance.disk_template,
442 a21dda8b Iustin Pop
                                            block_devices)
443 a21dda8b Iustin Pop
    disk_data = [line.replace(",sd", ",ioemu:hd") for line in disk_data]
444 a21dda8b Iustin Pop
    if instance.hvm_cdrom_image_path is not None:
445 a21dda8b Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % (instance.hvm_cdrom_image_path)
446 a21dda8b Iustin Pop
      disk_data.append(iso)
447 a21dda8b Iustin Pop
448 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
449 a21dda8b Iustin Pop
450 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
451 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
452 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
453 65a6f9b7 Michael Hanselmann
    if extra_args:
454 65a6f9b7 Michael Hanselmann
      config.write("extra = '%s'\n" % extra_args)
455 65a6f9b7 Michael Hanselmann
    # just in case it exists
456 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
457 65a6f9b7 Michael Hanselmann
    try:
458 65a6f9b7 Michael Hanselmann
      f = open("/etc/xen/%s" % instance.name, "w")
459 65a6f9b7 Michael Hanselmann
      try:
460 65a6f9b7 Michael Hanselmann
        f.write(config.getvalue())
461 65a6f9b7 Michael Hanselmann
      finally:
462 65a6f9b7 Michael Hanselmann
        f.close()
463 65a6f9b7 Michael Hanselmann
    except IOError, err:
464 65a6f9b7 Michael Hanselmann
      raise errors.OpExecError("Cannot write Xen instance confile"
465 65a6f9b7 Michael Hanselmann
                               " file /etc/xen/%s: %s" % (instance.name, err))
466 65a6f9b7 Michael Hanselmann
    return True
467 65a6f9b7 Michael Hanselmann
468 65a6f9b7 Michael Hanselmann
  @staticmethod
469 65a6f9b7 Michael Hanselmann
  def GetShellCommandForConsole(instance):
470 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
471 65a6f9b7 Michael Hanselmann

472 65a6f9b7 Michael Hanselmann
    """
473 65a6f9b7 Michael Hanselmann
    if instance.network_port is None:
474 65a6f9b7 Michael Hanselmann
      raise errors.OpExecError("no console port defined for %s"
475 65a6f9b7 Michael Hanselmann
                               % instance.name)
476 a21dda8b Iustin Pop
    elif instance.vnc_bind_address == constants.BIND_ADDRESS_GLOBAL:
477 65a6f9b7 Michael Hanselmann
      raise errors.OpExecError("no PTY console, connect to %s:%s via VNC"
478 65a6f9b7 Michael Hanselmann
                               % (instance.primary_node,
479 65a6f9b7 Michael Hanselmann
                                  instance.network_port))
480 a21dda8b Iustin Pop
    else:
481 a21dda8b Iustin Pop
      raise errors.OpExecError("no PTY console, connect to %s:%s via VNC"
482 a21dda8b Iustin Pop
                               % (instance.vnc_bind_address,
483 a21dda8b Iustin Pop
                                  instance.network_port))