Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_lxc.py @ 82599b3e

History | View | Annotate | Download (13.8 kB)

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

24 4b5e40a5 Iustin Pop
"""
25 4b5e40a5 Iustin Pop
26 4b5e40a5 Iustin Pop
import os
27 4b5e40a5 Iustin Pop
import os.path
28 4b5e40a5 Iustin Pop
import time
29 4b5e40a5 Iustin Pop
import logging
30 4b5e40a5 Iustin Pop
31 4b5e40a5 Iustin Pop
from ganeti import constants
32 4b5e40a5 Iustin Pop
from ganeti import errors # pylint: disable-msg=W0611
33 4b5e40a5 Iustin Pop
from ganeti import utils
34 55cc0a44 Michael Hanselmann
from ganeti import objects
35 4b5e40a5 Iustin Pop
from ganeti.hypervisor import hv_base
36 4b5e40a5 Iustin Pop
from ganeti.errors import HypervisorError
37 4b5e40a5 Iustin Pop
38 4b5e40a5 Iustin Pop
39 4b5e40a5 Iustin Pop
class LXCHypervisor(hv_base.BaseHypervisor):
40 4b5e40a5 Iustin Pop
  """LXC-based virtualization.
41 4b5e40a5 Iustin Pop

42 4b5e40a5 Iustin Pop
  Since current (Spring 2010) distributions are not yet ready for
43 4b5e40a5 Iustin Pop
  running under a container, the following changes must be done
44 4b5e40a5 Iustin Pop
  manually:
45 4b5e40a5 Iustin Pop
    - remove udev
46 4b5e40a5 Iustin Pop
    - disable the kernel log component of sysklogd/rsyslog/etc.,
47 4b5e40a5 Iustin Pop
      otherwise they will fail to read the log, and at least rsyslog
48 4b5e40a5 Iustin Pop
      will fill the filesystem with error messages
49 4b5e40a5 Iustin Pop

50 4b5e40a5 Iustin Pop
  TODO:
51 4b5e40a5 Iustin Pop
    - move hardcoded parameters into hypervisor parameters, once we
52 4b5e40a5 Iustin Pop
      have the container-parameter support
53 4b5e40a5 Iustin Pop
    - implement memory limits, but only optionally, depending on host
54 4b5e40a5 Iustin Pop
      kernel support
55 4b5e40a5 Iustin Pop

56 4b5e40a5 Iustin Pop
  Problems/issues:
57 4b5e40a5 Iustin Pop
    - LXC is very temperamental; in daemon mode, it succeeds or fails
58 4b5e40a5 Iustin Pop
      in launching the instance silently, without any error
59 4b5e40a5 Iustin Pop
      indication, and when failing it can leave network interfaces
60 4b5e40a5 Iustin Pop
      around, and future successful startups will list the instance
61 4b5e40a5 Iustin Pop
      twice
62 4b5e40a5 Iustin Pop
    - shutdown sequence of containers leaves the init 'dead', and the
63 4b5e40a5 Iustin Pop
      container effectively stopped, but LXC still believes the
64 4b5e40a5 Iustin Pop
      container to be running; need to investigate using the
65 4b5e40a5 Iustin Pop
      notify_on_release and release_agent feature of cgroups
66 4b5e40a5 Iustin Pop

67 4b5e40a5 Iustin Pop
  """
68 4b5e40a5 Iustin Pop
  _ROOT_DIR = constants.RUN_GANETI_DIR + "/lxc"
69 4b5e40a5 Iustin Pop
  _DEVS = [
70 4b5e40a5 Iustin Pop
    "c 1:3",   # /dev/null
71 4b5e40a5 Iustin Pop
    "c 1:5",   # /dev/zero
72 4b5e40a5 Iustin Pop
    "c 1:7",   # /dev/full
73 4b5e40a5 Iustin Pop
    "c 1:8",   # /dev/random
74 4b5e40a5 Iustin Pop
    "c 1:9",   # /dev/urandom
75 4b5e40a5 Iustin Pop
    "c 1:10",  # /dev/aio
76 4b5e40a5 Iustin Pop
    "c 5:0",   # /dev/tty
77 4b5e40a5 Iustin Pop
    "c 5:1",   # /dev/console
78 4b5e40a5 Iustin Pop
    "c 5:2",   # /dev/ptmx
79 4b5e40a5 Iustin Pop
    "c 136:*", # first block of Unix98 PTY slaves
80 4b5e40a5 Iustin Pop
    ]
81 4b5e40a5 Iustin Pop
  _DENIED_CAPABILITIES = [
82 4b5e40a5 Iustin Pop
    "mac_override",    # Allow MAC configuration or state changes
83 4b5e40a5 Iustin Pop
    # TODO: remove sys_admin too, for safety
84 4b5e40a5 Iustin Pop
    #"sys_admin",       # Perform  a range of system administration operations
85 4b5e40a5 Iustin Pop
    "sys_boot",        # Use reboot(2) and kexec_load(2)
86 4b5e40a5 Iustin Pop
    "sys_module",      # Load  and  unload kernel modules
87 4b5e40a5 Iustin Pop
    "sys_time",        # Set  system  clock, set real-time (hardware) clock
88 4b5e40a5 Iustin Pop
    ]
89 4b5e40a5 Iustin Pop
  _DIR_MODE = 0755
90 4b5e40a5 Iustin Pop
91 4b5e40a5 Iustin Pop
  PARAMETERS = {
92 e3ed5316 Balazs Lecz
    constants.HV_CPU_MASK: hv_base.OPT_CPU_MASK_CHECK,
93 4b5e40a5 Iustin Pop
    }
94 4b5e40a5 Iustin Pop
95 4b5e40a5 Iustin Pop
  def __init__(self):
96 4b5e40a5 Iustin Pop
    hv_base.BaseHypervisor.__init__(self)
97 4b5e40a5 Iustin Pop
    utils.EnsureDirs([(self._ROOT_DIR, self._DIR_MODE)])
98 4b5e40a5 Iustin Pop
99 4b5e40a5 Iustin Pop
  @staticmethod
100 4b5e40a5 Iustin Pop
  def _GetMountSubdirs(path):
101 4b5e40a5 Iustin Pop
    """Return the list of mountpoints under a given path.
102 4b5e40a5 Iustin Pop

103 4b5e40a5 Iustin Pop
    """
104 a188f1ef Balazs Lecz
    result = []
105 a188f1ef Balazs Lecz
    for _, mountpoint, _, _ in utils.GetMounts():
106 a188f1ef Balazs Lecz
      if (mountpoint.startswith(path) and
107 a188f1ef Balazs Lecz
          mountpoint != path):
108 a188f1ef Balazs Lecz
        result.append(mountpoint)
109 a188f1ef Balazs Lecz
110 a188f1ef Balazs Lecz
    result.sort(key=lambda x: x.count("/"), reverse=True)
111 a188f1ef Balazs Lecz
    return result
112 4b5e40a5 Iustin Pop
113 4b5e40a5 Iustin Pop
  @classmethod
114 4b5e40a5 Iustin Pop
  def _InstanceDir(cls, instance_name):
115 4b5e40a5 Iustin Pop
    """Return the root directory for an instance.
116 4b5e40a5 Iustin Pop

117 4b5e40a5 Iustin Pop
    """
118 4b5e40a5 Iustin Pop
    return utils.PathJoin(cls._ROOT_DIR, instance_name)
119 4b5e40a5 Iustin Pop
120 4b5e40a5 Iustin Pop
  @classmethod
121 4b5e40a5 Iustin Pop
  def _InstanceConfFile(cls, instance_name):
122 4b5e40a5 Iustin Pop
    """Return the configuration file for an instance.
123 4b5e40a5 Iustin Pop

124 4b5e40a5 Iustin Pop
    """
125 4b5e40a5 Iustin Pop
    return utils.PathJoin(cls._ROOT_DIR, instance_name + ".conf")
126 4b5e40a5 Iustin Pop
127 c4d3e57f Balazs Lecz
  @classmethod
128 13c564e7 Balazs Lecz
  def _InstanceLogFile(cls, instance_name):
129 13c564e7 Balazs Lecz
    """Return the log file for an instance.
130 13c564e7 Balazs Lecz

131 13c564e7 Balazs Lecz
    """
132 13c564e7 Balazs Lecz
    return utils.PathJoin(cls._ROOT_DIR, instance_name + ".log")
133 13c564e7 Balazs Lecz
134 13c564e7 Balazs Lecz
  @classmethod
135 c4d3e57f Balazs Lecz
  def _GetCgroupMountPoint(cls):
136 c4d3e57f Balazs Lecz
    for _, mountpoint, fstype, _ in utils.GetMounts():
137 c4d3e57f Balazs Lecz
      if fstype == "cgroup":
138 c4d3e57f Balazs Lecz
        return mountpoint
139 c4d3e57f Balazs Lecz
    raise errors.HypervisorError("The cgroup filesystem is not mounted")
140 c4d3e57f Balazs Lecz
141 c4d3e57f Balazs Lecz
  @classmethod
142 c4d3e57f Balazs Lecz
  def _GetCgroupCpuList(cls, instance_name):
143 c4d3e57f Balazs Lecz
    """Return the list of CPU ids for an instance.
144 c4d3e57f Balazs Lecz

145 c4d3e57f Balazs Lecz
    """
146 c4d3e57f Balazs Lecz
    cgroup = cls._GetCgroupMountPoint()
147 c4d3e57f Balazs Lecz
    try:
148 c4d3e57f Balazs Lecz
      cpus = utils.ReadFile(utils.PathJoin(cgroup,
149 c4d3e57f Balazs Lecz
                                           instance_name,
150 c4d3e57f Balazs Lecz
                                           "cpuset.cpus"))
151 c4d3e57f Balazs Lecz
    except EnvironmentError, err:
152 c4d3e57f Balazs Lecz
      raise errors.HypervisorError("Getting CPU list for instance"
153 c4d3e57f Balazs Lecz
                                   " %s failed: %s" % (instance_name, err))
154 e3ed5316 Balazs Lecz
155 e3ed5316 Balazs Lecz
    return utils.ParseCpuMask(cpus)
156 c4d3e57f Balazs Lecz
157 4b5e40a5 Iustin Pop
  def ListInstances(self):
158 4b5e40a5 Iustin Pop
    """Get the list of running instances.
159 4b5e40a5 Iustin Pop

160 4b5e40a5 Iustin Pop
    """
161 4b5e40a5 Iustin Pop
    result = utils.RunCmd(["lxc-ls"])
162 4b5e40a5 Iustin Pop
    if result.failed:
163 c83864fe Balazs Lecz
      raise errors.HypervisorError("Running lxc-ls failed: %s" % result.output)
164 4b5e40a5 Iustin Pop
    return result.stdout.splitlines()
165 4b5e40a5 Iustin Pop
166 4b5e40a5 Iustin Pop
  def GetInstanceInfo(self, instance_name):
167 4b5e40a5 Iustin Pop
    """Get instance properties.
168 4b5e40a5 Iustin Pop

169 4b5e40a5 Iustin Pop
    @type instance_name: string
170 4b5e40a5 Iustin Pop
    @param instance_name: the instance name
171 4b5e40a5 Iustin Pop

172 4b5e40a5 Iustin Pop
    @return: (name, id, memory, vcpus, stat, times)
173 4b5e40a5 Iustin Pop

174 4b5e40a5 Iustin Pop
    """
175 4b5e40a5 Iustin Pop
    # TODO: read container info from the cgroup mountpoint
176 d01baf53 Balazs Lecz
177 d01baf53 Balazs Lecz
    result = utils.RunCmd(["lxc-info", "-n", instance_name])
178 d01baf53 Balazs Lecz
    if result.failed:
179 c83864fe Balazs Lecz
      raise errors.HypervisorError("Running lxc-info failed: %s" %
180 c83864fe Balazs Lecz
                                   result.output)
181 d01baf53 Balazs Lecz
    # lxc-info output examples:
182 d01baf53 Balazs Lecz
    # 'ganeti-lxc-test1' is STOPPED
183 d01baf53 Balazs Lecz
    # 'ganeti-lxc-test1' is RUNNING
184 d01baf53 Balazs Lecz
    _, state = result.stdout.rsplit(None, 1)
185 b8aa46ed Balazs Lecz
    if state != "RUNNING":
186 b8aa46ed Balazs Lecz
      return None
187 c4d3e57f Balazs Lecz
188 c4d3e57f Balazs Lecz
    cpu_list = self._GetCgroupCpuList(instance_name)
189 b8aa46ed Balazs Lecz
    return (instance_name, 0, 0, len(cpu_list), 0, 0)
190 4b5e40a5 Iustin Pop
191 4b5e40a5 Iustin Pop
  def GetAllInstancesInfo(self):
192 4b5e40a5 Iustin Pop
    """Get properties of all instances.
193 4b5e40a5 Iustin Pop

194 4b5e40a5 Iustin Pop
    @return: [(name, id, memory, vcpus, stat, times),...]
195 4b5e40a5 Iustin Pop

196 4b5e40a5 Iustin Pop
    """
197 4b5e40a5 Iustin Pop
    data = []
198 4b5e40a5 Iustin Pop
    for name in self.ListInstances():
199 63cef6c3 Balazs Lecz
      data.append(self.GetInstanceInfo(name))
200 4b5e40a5 Iustin Pop
    return data
201 4b5e40a5 Iustin Pop
202 4b5e40a5 Iustin Pop
  def _CreateConfigFile(self, instance, root_dir):
203 e3ed5316 Balazs Lecz
    """Create an lxc.conf file for an instance.
204 e3ed5316 Balazs Lecz

205 e3ed5316 Balazs Lecz
    """
206 4b5e40a5 Iustin Pop
    out = []
207 4b5e40a5 Iustin Pop
    # hostname
208 4b5e40a5 Iustin Pop
    out.append("lxc.utsname = %s" % instance.name)
209 4b5e40a5 Iustin Pop
210 4b5e40a5 Iustin Pop
    # separate pseudo-TTY instances
211 4b5e40a5 Iustin Pop
    out.append("lxc.pts = 255")
212 637c8ab8 Balazs Lecz
    # standard TTYs
213 4b5e40a5 Iustin Pop
    out.append("lxc.tty = 6")
214 637c8ab8 Balazs Lecz
    # console log file
215 637c8ab8 Balazs Lecz
    console_log = utils.PathJoin(self._ROOT_DIR, instance.name + ".console")
216 637c8ab8 Balazs Lecz
    try:
217 637c8ab8 Balazs Lecz
      utils.WriteFile(console_log, data="", mode=constants.SECURE_FILE_MODE)
218 637c8ab8 Balazs Lecz
    except EnvironmentError, err:
219 637c8ab8 Balazs Lecz
      raise errors.HypervisorError("Creating console log file %s for"
220 637c8ab8 Balazs Lecz
                                   " instance %s failed: %s" %
221 637c8ab8 Balazs Lecz
                                   (console_log, instance.name, err))
222 637c8ab8 Balazs Lecz
    out.append("lxc.console = %s" % console_log)
223 4b5e40a5 Iustin Pop
224 4b5e40a5 Iustin Pop
    # root FS
225 4b5e40a5 Iustin Pop
    out.append("lxc.rootfs = %s" % root_dir)
226 4b5e40a5 Iustin Pop
227 4b5e40a5 Iustin Pop
    # TODO: additional mounts, if we disable CAP_SYS_ADMIN
228 4b5e40a5 Iustin Pop
229 e3ed5316 Balazs Lecz
    # CPUs
230 e3ed5316 Balazs Lecz
    if instance.hvparams[constants.HV_CPU_MASK]:
231 e3ed5316 Balazs Lecz
      cpu_list = utils.ParseCpuMask(instance.hvparams[constants.HV_CPU_MASK])
232 e3ed5316 Balazs Lecz
      cpus_in_mask = len(cpu_list)
233 e3ed5316 Balazs Lecz
      if cpus_in_mask != instance.beparams["vcpus"]:
234 e3ed5316 Balazs Lecz
        raise errors.HypervisorError("Number of VCPUs (%d) doesn't match"
235 e3ed5316 Balazs Lecz
                                     " the number of CPUs in the"
236 e3ed5316 Balazs Lecz
                                     " cpu_mask (%d)" %
237 e3ed5316 Balazs Lecz
                                     (instance.beparams["vcpus"],
238 e3ed5316 Balazs Lecz
                                      cpus_in_mask))
239 e3ed5316 Balazs Lecz
      out.append("lxc.cgroup.cpuset.cpus = %s" %
240 e3ed5316 Balazs Lecz
                 instance.hvparams[constants.HV_CPU_MASK])
241 e3ed5316 Balazs Lecz
242 4b5e40a5 Iustin Pop
    # Device control
243 4b5e40a5 Iustin Pop
    # deny direct device access
244 4b5e40a5 Iustin Pop
    out.append("lxc.cgroup.devices.deny = a")
245 4b5e40a5 Iustin Pop
    for devinfo in self._DEVS:
246 4b5e40a5 Iustin Pop
      out.append("lxc.cgroup.devices.allow = %s rw" % devinfo)
247 4b5e40a5 Iustin Pop
248 4b5e40a5 Iustin Pop
    # Networking
249 4b5e40a5 Iustin Pop
    for idx, nic in enumerate(instance.nics):
250 4b5e40a5 Iustin Pop
      out.append("# NIC %d" % idx)
251 4b5e40a5 Iustin Pop
      mode = nic.nicparams[constants.NIC_MODE]
252 4b5e40a5 Iustin Pop
      link = nic.nicparams[constants.NIC_LINK]
253 4b5e40a5 Iustin Pop
      if mode == constants.NIC_MODE_BRIDGED:
254 4b5e40a5 Iustin Pop
        out.append("lxc.network.type = veth")
255 4b5e40a5 Iustin Pop
        out.append("lxc.network.link = %s" % link)
256 4b5e40a5 Iustin Pop
      else:
257 4b5e40a5 Iustin Pop
        raise errors.HypervisorError("LXC hypervisor only supports"
258 4b5e40a5 Iustin Pop
                                     " bridged mode (NIC %d has mode %s)" %
259 4b5e40a5 Iustin Pop
                                     (idx, mode))
260 4b5e40a5 Iustin Pop
      out.append("lxc.network.hwaddr = %s" % nic.mac)
261 4b5e40a5 Iustin Pop
      out.append("lxc.network.flags = up")
262 4b5e40a5 Iustin Pop
263 4b5e40a5 Iustin Pop
    # Capabilities
264 4b5e40a5 Iustin Pop
    for cap in self._DENIED_CAPABILITIES:
265 4b5e40a5 Iustin Pop
      out.append("lxc.cap.drop = %s" % cap)
266 4b5e40a5 Iustin Pop
267 4b5e40a5 Iustin Pop
    return "\n".join(out) + "\n"
268 4b5e40a5 Iustin Pop
269 4b5e40a5 Iustin Pop
  def StartInstance(self, instance, block_devices):
270 4b5e40a5 Iustin Pop
    """Start an instance.
271 4b5e40a5 Iustin Pop

272 e3ed5316 Balazs Lecz
    For LCX, we try to mount the block device and execute 'lxc-start'.
273 e3ed5316 Balazs Lecz
    We use volatile containers.
274 4b5e40a5 Iustin Pop

275 4b5e40a5 Iustin Pop
    """
276 4b5e40a5 Iustin Pop
    root_dir = self._InstanceDir(instance.name)
277 4b5e40a5 Iustin Pop
    try:
278 4b5e40a5 Iustin Pop
      utils.EnsureDirs([(root_dir, self._DIR_MODE)])
279 4b5e40a5 Iustin Pop
    except errors.GenericError, err:
280 c83864fe Balazs Lecz
      raise HypervisorError("Creating instance directory failed: %s", str(err))
281 4b5e40a5 Iustin Pop
282 4b5e40a5 Iustin Pop
    conf_file = self._InstanceConfFile(instance.name)
283 4b5e40a5 Iustin Pop
    utils.WriteFile(conf_file, data=self._CreateConfigFile(instance, root_dir))
284 4b5e40a5 Iustin Pop
285 13c564e7 Balazs Lecz
    log_file = self._InstanceLogFile(instance.name)
286 13c564e7 Balazs Lecz
    if not os.path.exists(log_file):
287 13c564e7 Balazs Lecz
      try:
288 13c564e7 Balazs Lecz
        utils.WriteFile(log_file, data="", mode=constants.SECURE_FILE_MODE)
289 13c564e7 Balazs Lecz
      except EnvironmentError, err:
290 13c564e7 Balazs Lecz
        raise errors.HypervisorError("Creating hypervisor log file %s for"
291 13c564e7 Balazs Lecz
                                     " instance %s failed: %s" %
292 13c564e7 Balazs Lecz
                                     (log_file, instance.name, err))
293 13c564e7 Balazs Lecz
294 4b5e40a5 Iustin Pop
    if not os.path.ismount(root_dir):
295 4b5e40a5 Iustin Pop
      if not block_devices:
296 4b5e40a5 Iustin Pop
        raise HypervisorError("LXC needs at least one disk")
297 4b5e40a5 Iustin Pop
298 4b5e40a5 Iustin Pop
      sda_dev_path = block_devices[0][1]
299 4b5e40a5 Iustin Pop
      result = utils.RunCmd(["mount", sda_dev_path, root_dir])
300 4b5e40a5 Iustin Pop
      if result.failed:
301 c83864fe Balazs Lecz
        raise HypervisorError("Mounting the root dir of LXC instance %s"
302 c83864fe Balazs Lecz
                              " failed: %s" % (instance.name, result.output))
303 4b5e40a5 Iustin Pop
    result = utils.RunCmd(["lxc-start", "-n", instance.name,
304 13c564e7 Balazs Lecz
                           "-o", log_file,
305 13c564e7 Balazs Lecz
                           "-l", "DEBUG",
306 4b5e40a5 Iustin Pop
                           "-f", conf_file, "-d"])
307 4b5e40a5 Iustin Pop
    if result.failed:
308 4b5e40a5 Iustin Pop
      raise HypervisorError("Running the lxc-start script failed: %s" %
309 4b5e40a5 Iustin Pop
                            result.output)
310 4b5e40a5 Iustin Pop
311 4b5e40a5 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
312 4b5e40a5 Iustin Pop
    """Stop an instance.
313 4b5e40a5 Iustin Pop

314 4b5e40a5 Iustin Pop
    This method has complicated cleanup tests, as we must:
315 4b5e40a5 Iustin Pop
      - try to kill all leftover processes
316 4b5e40a5 Iustin Pop
      - try to unmount any additional sub-mountpoints
317 4b5e40a5 Iustin Pop
      - finally unmount the instance dir
318 4b5e40a5 Iustin Pop

319 4b5e40a5 Iustin Pop
    """
320 4b5e40a5 Iustin Pop
    if name is None:
321 4b5e40a5 Iustin Pop
      name = instance.name
322 4b5e40a5 Iustin Pop
323 4b5e40a5 Iustin Pop
    root_dir = self._InstanceDir(name)
324 4b5e40a5 Iustin Pop
    if not os.path.exists(root_dir):
325 4b5e40a5 Iustin Pop
      return
326 4b5e40a5 Iustin Pop
327 4b5e40a5 Iustin Pop
    if name in self.ListInstances():
328 4b5e40a5 Iustin Pop
      # Signal init to shutdown; this is a hack
329 4b5e40a5 Iustin Pop
      if not retry and not force:
330 4b5e40a5 Iustin Pop
        result = utils.RunCmd(["chroot", root_dir, "poweroff"])
331 4b5e40a5 Iustin Pop
        if result.failed:
332 c83864fe Balazs Lecz
          raise HypervisorError("Running 'poweroff' on the instance"
333 c83864fe Balazs Lecz
                                " failed: %s" % result.output)
334 4b5e40a5 Iustin Pop
      time.sleep(2)
335 4b5e40a5 Iustin Pop
      result = utils.RunCmd(["lxc-stop", "-n", name])
336 4b5e40a5 Iustin Pop
      if result.failed:
337 4b5e40a5 Iustin Pop
        logging.warning("Error while doing lxc-stop for %s: %s", name,
338 4b5e40a5 Iustin Pop
                        result.output)
339 4b5e40a5 Iustin Pop
340 4b5e40a5 Iustin Pop
    for mpath in self._GetMountSubdirs(root_dir):
341 4b5e40a5 Iustin Pop
      result = utils.RunCmd(["umount", mpath])
342 4b5e40a5 Iustin Pop
      if result.failed:
343 4b5e40a5 Iustin Pop
        logging.warning("Error while umounting subpath %s for instance %s: %s",
344 4b5e40a5 Iustin Pop
                        mpath, name, result.output)
345 4b5e40a5 Iustin Pop
346 4b5e40a5 Iustin Pop
    result = utils.RunCmd(["umount", root_dir])
347 4b5e40a5 Iustin Pop
    if result.failed and force:
348 4b5e40a5 Iustin Pop
      msg = ("Processes still alive in the chroot: %s" %
349 4b5e40a5 Iustin Pop
             utils.RunCmd("fuser -vm %s" % root_dir).output)
350 4b5e40a5 Iustin Pop
      logging.error(msg)
351 c83864fe Balazs Lecz
      raise HypervisorError("Unmounting the chroot dir failed: %s (%s)" %
352 4b5e40a5 Iustin Pop
                            (result.output, msg))
353 4b5e40a5 Iustin Pop
354 4b5e40a5 Iustin Pop
  def RebootInstance(self, instance):
355 4b5e40a5 Iustin Pop
    """Reboot an instance.
356 4b5e40a5 Iustin Pop

357 4b5e40a5 Iustin Pop
    This is not (yet) implemented (in Ganeti) for the LXC hypervisor.
358 4b5e40a5 Iustin Pop

359 4b5e40a5 Iustin Pop
    """
360 4b5e40a5 Iustin Pop
    # TODO: implement reboot
361 4b5e40a5 Iustin Pop
    raise HypervisorError("The LXC hypervisor doesn't implement the"
362 4b5e40a5 Iustin Pop
                          " reboot functionality")
363 4b5e40a5 Iustin Pop
364 4b5e40a5 Iustin Pop
  def GetNodeInfo(self):
365 4b5e40a5 Iustin Pop
    """Return information about the node.
366 4b5e40a5 Iustin Pop

367 4b5e40a5 Iustin Pop
    This is just a wrapper over the base GetLinuxNodeInfo method.
368 4b5e40a5 Iustin Pop

369 4b5e40a5 Iustin Pop
    @return: a dict with the following keys (values in MiB):
370 4b5e40a5 Iustin Pop
          - memory_total: the total memory size on the node
371 4b5e40a5 Iustin Pop
          - memory_free: the available memory on the node for instances
372 4b5e40a5 Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
373 4b5e40a5 Iustin Pop

374 4b5e40a5 Iustin Pop
    """
375 4b5e40a5 Iustin Pop
    return self.GetLinuxNodeInfo()
376 4b5e40a5 Iustin Pop
377 4b5e40a5 Iustin Pop
  @classmethod
378 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
379 4b5e40a5 Iustin Pop
    """Return a command for connecting to the console of an instance.
380 4b5e40a5 Iustin Pop

381 4b5e40a5 Iustin Pop
    """
382 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
383 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
384 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
385 55cc0a44 Michael Hanselmann
                                   user=constants.GANETI_RUNAS,
386 55cc0a44 Michael Hanselmann
                                   command=["lxc-console", "-n", instance.name])
387 4b5e40a5 Iustin Pop
388 4b5e40a5 Iustin Pop
  def Verify(self):
389 4b5e40a5 Iustin Pop
    """Verify the hypervisor.
390 4b5e40a5 Iustin Pop

391 4b5e40a5 Iustin Pop
    For the chroot manager, it just checks the existence of the base dir.
392 4b5e40a5 Iustin Pop

393 4b5e40a5 Iustin Pop
    """
394 4b5e40a5 Iustin Pop
    if not os.path.exists(self._ROOT_DIR):
395 4b5e40a5 Iustin Pop
      return "The required directory '%s' does not exist." % self._ROOT_DIR
396 4b5e40a5 Iustin Pop
397 4b5e40a5 Iustin Pop
  @classmethod
398 4b5e40a5 Iustin Pop
  def PowercycleNode(cls):
399 4b5e40a5 Iustin Pop
    """LXC powercycle, just a wrapper over Linux powercycle.
400 4b5e40a5 Iustin Pop

401 4b5e40a5 Iustin Pop
    """
402 4b5e40a5 Iustin Pop
    cls.LinuxPowercycle()
403 4b5e40a5 Iustin Pop
404 4b5e40a5 Iustin Pop
  def MigrateInstance(self, instance, target, live):
405 4b5e40a5 Iustin Pop
    """Migrate an instance.
406 4b5e40a5 Iustin Pop

407 4b5e40a5 Iustin Pop
    @type instance: L{objects.Instance}
408 4b5e40a5 Iustin Pop
    @param instance: the instance to be migrated
409 4b5e40a5 Iustin Pop
    @type target: string
410 4b5e40a5 Iustin Pop
    @param target: hostname (usually ip) of the target node
411 4b5e40a5 Iustin Pop
    @type live: boolean
412 4b5e40a5 Iustin Pop
    @param live: whether to do a live or non-live migration
413 4b5e40a5 Iustin Pop

414 4b5e40a5 Iustin Pop
    """
415 c83864fe Balazs Lecz
    raise HypervisorError("Migration is not supported by the LXC hypervisor")