Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_lxc.py @ 0e1e0b6a

History | View | Annotate | Download (14.6 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 b459a848 Andrea Spadaccini
from ganeti import errors # pylint: disable=W0611
33 4b5e40a5 Iustin Pop
from ganeti import utils
34 55cc0a44 Michael Hanselmann
from ganeti import objects
35 9d9bded1 Michael Hanselmann
from ganeti import pathutils
36 4b5e40a5 Iustin Pop
from ganeti.hypervisor import hv_base
37 4b5e40a5 Iustin Pop
from ganeti.errors import HypervisorError
38 4b5e40a5 Iustin Pop
39 4b5e40a5 Iustin Pop
40 4b5e40a5 Iustin Pop
class LXCHypervisor(hv_base.BaseHypervisor):
41 4b5e40a5 Iustin Pop
  """LXC-based virtualization.
42 4b5e40a5 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

360 4b5e40a5 Iustin Pop
    """
361 4b5e40a5 Iustin Pop
    # TODO: implement reboot
362 4b5e40a5 Iustin Pop
    raise HypervisorError("The LXC hypervisor doesn't implement the"
363 4b5e40a5 Iustin Pop
                          " reboot functionality")
364 4b5e40a5 Iustin Pop
365 2e2fb795 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
366 2e2fb795 Guido Trotter
    """Balloon an instance memory to a certain value.
367 2e2fb795 Guido Trotter

368 2e2fb795 Guido Trotter
    @type instance: L{objects.Instance}
369 2e2fb795 Guido Trotter
    @param instance: instance to be accepted
370 2e2fb795 Guido Trotter
    @type mem: int
371 2e2fb795 Guido Trotter
    @param mem: actual memory size to use for instance runtime
372 2e2fb795 Guido Trotter

373 2e2fb795 Guido Trotter
    """
374 2e2fb795 Guido Trotter
    # Currently lxc instances don't have memory limits
375 2e2fb795 Guido Trotter
    pass
376 2e2fb795 Guido Trotter
377 4b5e40a5 Iustin Pop
  def GetNodeInfo(self):
378 4b5e40a5 Iustin Pop
    """Return information about the node.
379 4b5e40a5 Iustin Pop

380 4b5e40a5 Iustin Pop
    This is just a wrapper over the base GetLinuxNodeInfo method.
381 4b5e40a5 Iustin Pop

382 4b5e40a5 Iustin Pop
    @return: a dict with the following keys (values in MiB):
383 4b5e40a5 Iustin Pop
          - memory_total: the total memory size on the node
384 4b5e40a5 Iustin Pop
          - memory_free: the available memory on the node for instances
385 4b5e40a5 Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
386 4b5e40a5 Iustin Pop

387 4b5e40a5 Iustin Pop
    """
388 4b5e40a5 Iustin Pop
    return self.GetLinuxNodeInfo()
389 4b5e40a5 Iustin Pop
390 4b5e40a5 Iustin Pop
  @classmethod
391 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
392 4b5e40a5 Iustin Pop
    """Return a command for connecting to the console of an instance.
393 4b5e40a5 Iustin Pop

394 4b5e40a5 Iustin Pop
    """
395 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
396 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
397 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
398 55cc0a44 Michael Hanselmann
                                   user=constants.GANETI_RUNAS,
399 55cc0a44 Michael Hanselmann
                                   command=["lxc-console", "-n", instance.name])
400 4b5e40a5 Iustin Pop
401 4b5e40a5 Iustin Pop
  def Verify(self):
402 4b5e40a5 Iustin Pop
    """Verify the hypervisor.
403 4b5e40a5 Iustin Pop

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

406 4b5e40a5 Iustin Pop
    """
407 4b5e40a5 Iustin Pop
    if not os.path.exists(self._ROOT_DIR):
408 4b5e40a5 Iustin Pop
      return "The required directory '%s' does not exist." % self._ROOT_DIR
409 4b5e40a5 Iustin Pop
410 4b5e40a5 Iustin Pop
  @classmethod
411 4b5e40a5 Iustin Pop
  def PowercycleNode(cls):
412 4b5e40a5 Iustin Pop
    """LXC powercycle, just a wrapper over Linux powercycle.
413 4b5e40a5 Iustin Pop

414 4b5e40a5 Iustin Pop
    """
415 4b5e40a5 Iustin Pop
    cls.LinuxPowercycle()
416 4b5e40a5 Iustin Pop
417 4b5e40a5 Iustin Pop
  def MigrateInstance(self, instance, target, live):
418 4b5e40a5 Iustin Pop
    """Migrate an instance.
419 4b5e40a5 Iustin Pop

420 4b5e40a5 Iustin Pop
    @type instance: L{objects.Instance}
421 4b5e40a5 Iustin Pop
    @param instance: the instance to be migrated
422 4b5e40a5 Iustin Pop
    @type target: string
423 4b5e40a5 Iustin Pop
    @param target: hostname (usually ip) of the target node
424 4b5e40a5 Iustin Pop
    @type live: boolean
425 4b5e40a5 Iustin Pop
    @param live: whether to do a live or non-live migration
426 4b5e40a5 Iustin Pop

427 4b5e40a5 Iustin Pop
    """
428 c83864fe Balazs Lecz
    raise HypervisorError("Migration is not supported by the LXC hypervisor")
429 60af751d Andrea Spadaccini
430 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
431 60af751d Andrea Spadaccini
    """Get the migration status
432 60af751d Andrea Spadaccini

433 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
434 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
435 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
436 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
437 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
438 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
439 60af751d Andrea Spadaccini

440 60af751d Andrea Spadaccini
    """
441 60af751d Andrea Spadaccini
    raise HypervisorError("Migration is not supported by the LXC hypervisor")