Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_lxc.py @ 653bc0f1

History | View | Annotate | Download (15.8 kB)

1 4b5e40a5 Iustin Pop
#
2 4b5e40a5 Iustin Pop
#
3 4b5e40a5 Iustin Pop
4 0628a50a Iustin Pop
# Copyright (C) 2010, 2013 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
  TODO:
44 4b5e40a5 Iustin Pop
    - move hardcoded parameters into hypervisor parameters, once we
45 4b5e40a5 Iustin Pop
      have the container-parameter support
46 4b5e40a5 Iustin Pop

47 4b5e40a5 Iustin Pop
  Problems/issues:
48 4b5e40a5 Iustin Pop
    - LXC is very temperamental; in daemon mode, it succeeds or fails
49 4b5e40a5 Iustin Pop
      in launching the instance silently, without any error
50 4b5e40a5 Iustin Pop
      indication, and when failing it can leave network interfaces
51 4b5e40a5 Iustin Pop
      around, and future successful startups will list the instance
52 4b5e40a5 Iustin Pop
      twice
53 4b5e40a5 Iustin Pop

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

90 4b5e40a5 Iustin Pop
    """
91 a188f1ef Balazs Lecz
    result = []
92 a188f1ef Balazs Lecz
    for _, mountpoint, _, _ in utils.GetMounts():
93 a188f1ef Balazs Lecz
      if (mountpoint.startswith(path) and
94 a188f1ef Balazs Lecz
          mountpoint != path):
95 a188f1ef Balazs Lecz
        result.append(mountpoint)
96 a188f1ef Balazs Lecz
97 a188f1ef Balazs Lecz
    result.sort(key=lambda x: x.count("/"), reverse=True)
98 a188f1ef Balazs Lecz
    return result
99 4b5e40a5 Iustin Pop
100 4b5e40a5 Iustin Pop
  @classmethod
101 4b5e40a5 Iustin Pop
  def _InstanceDir(cls, instance_name):
102 4b5e40a5 Iustin Pop
    """Return the root directory for an instance.
103 4b5e40a5 Iustin Pop

104 4b5e40a5 Iustin Pop
    """
105 4b5e40a5 Iustin Pop
    return utils.PathJoin(cls._ROOT_DIR, instance_name)
106 4b5e40a5 Iustin Pop
107 4b5e40a5 Iustin Pop
  @classmethod
108 4b5e40a5 Iustin Pop
  def _InstanceConfFile(cls, instance_name):
109 4b5e40a5 Iustin Pop
    """Return the configuration file for an instance.
110 4b5e40a5 Iustin Pop

111 4b5e40a5 Iustin Pop
    """
112 4b5e40a5 Iustin Pop
    return utils.PathJoin(cls._ROOT_DIR, instance_name + ".conf")
113 4b5e40a5 Iustin Pop
114 c4d3e57f Balazs Lecz
  @classmethod
115 13c564e7 Balazs Lecz
  def _InstanceLogFile(cls, instance_name):
116 13c564e7 Balazs Lecz
    """Return the log file for an instance.
117 13c564e7 Balazs Lecz

118 13c564e7 Balazs Lecz
    """
119 13c564e7 Balazs Lecz
    return utils.PathJoin(cls._ROOT_DIR, instance_name + ".log")
120 13c564e7 Balazs Lecz
121 13c564e7 Balazs Lecz
  @classmethod
122 c4d3e57f Balazs Lecz
  def _GetCgroupMountPoint(cls):
123 c4d3e57f Balazs Lecz
    for _, mountpoint, fstype, _ in utils.GetMounts():
124 c4d3e57f Balazs Lecz
      if fstype == "cgroup":
125 c4d3e57f Balazs Lecz
        return mountpoint
126 c4d3e57f Balazs Lecz
    raise errors.HypervisorError("The cgroup filesystem is not mounted")
127 c4d3e57f Balazs Lecz
128 c4d3e57f Balazs Lecz
  @classmethod
129 c4d3e57f Balazs Lecz
  def _GetCgroupCpuList(cls, instance_name):
130 c4d3e57f Balazs Lecz
    """Return the list of CPU ids for an instance.
131 c4d3e57f Balazs Lecz

132 c4d3e57f Balazs Lecz
    """
133 c4d3e57f Balazs Lecz
    cgroup = cls._GetCgroupMountPoint()
134 c4d3e57f Balazs Lecz
    try:
135 2e5a6203 Faidon Liambotis
      cpus = utils.ReadFile(utils.PathJoin(cgroup, 'lxc',
136 c4d3e57f Balazs Lecz
                                           instance_name,
137 c4d3e57f Balazs Lecz
                                           "cpuset.cpus"))
138 c4d3e57f Balazs Lecz
    except EnvironmentError, err:
139 c4d3e57f Balazs Lecz
      raise errors.HypervisorError("Getting CPU list for instance"
140 c4d3e57f Balazs Lecz
                                   " %s failed: %s" % (instance_name, err))
141 e3ed5316 Balazs Lecz
142 e3ed5316 Balazs Lecz
    return utils.ParseCpuMask(cpus)
143 c4d3e57f Balazs Lecz
144 f078c799 Faidon Liambotis
  @classmethod
145 f078c799 Faidon Liambotis
  def _GetCgroupMemoryLimit(cls, instance_name):
146 f078c799 Faidon Liambotis
    """Return the memory limit for an instance
147 f078c799 Faidon Liambotis

148 f078c799 Faidon Liambotis
    """
149 f078c799 Faidon Liambotis
    cgroup = cls._GetCgroupMountPoint()
150 f078c799 Faidon Liambotis
    try:
151 f078c799 Faidon Liambotis
      memory = int(utils.ReadFile(utils.PathJoin(cgroup, 'lxc',
152 e4157912 Guido Trotter
                                                 instance_name,
153 e4157912 Guido Trotter
                                                 "memory.limit_in_bytes")))
154 f078c799 Faidon Liambotis
    except EnvironmentError:
155 f078c799 Faidon Liambotis
      # memory resource controller may be disabled, ignore
156 f078c799 Faidon Liambotis
      memory = 0
157 f078c799 Faidon Liambotis
158 f078c799 Faidon Liambotis
    return memory
159 f078c799 Faidon Liambotis
160 58e356a9 Helga Velroyen
  def ListInstances(self, hvparams=None):
161 4b5e40a5 Iustin Pop
    """Get the list of running instances.
162 4b5e40a5 Iustin Pop

163 4b5e40a5 Iustin Pop
    """
164 e4157912 Guido Trotter
    return [iinfo[0] for iinfo in self.GetAllInstancesInfo()]
165 4b5e40a5 Iustin Pop
166 0bbec3af Helga Velroyen
  def GetInstanceInfo(self, instance_name, hvparams=None):
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 0bbec3af Helga Velroyen
    @type hvparams: dict of strings
172 0bbec3af Helga Velroyen
    @param hvparams: hvparams to be used with this instance
173 f078c799 Faidon Liambotis
    @rtype: tuple of strings
174 4b5e40a5 Iustin Pop
    @return: (name, id, memory, vcpus, stat, times)
175 4b5e40a5 Iustin Pop

176 4b5e40a5 Iustin Pop
    """
177 4b5e40a5 Iustin Pop
    # TODO: read container info from the cgroup mountpoint
178 d01baf53 Balazs Lecz
179 2e5a6203 Faidon Liambotis
    result = utils.RunCmd(["lxc-info", "-s", "-n", instance_name])
180 d01baf53 Balazs Lecz
    if result.failed:
181 c83864fe Balazs Lecz
      raise errors.HypervisorError("Running lxc-info failed: %s" %
182 c83864fe Balazs Lecz
                                   result.output)
183 d01baf53 Balazs Lecz
    # lxc-info output examples:
184 2e5a6203 Faidon Liambotis
    # 'state: STOPPED
185 2e5a6203 Faidon Liambotis
    # 'state: RUNNING
186 d01baf53 Balazs Lecz
    _, state = result.stdout.rsplit(None, 1)
187 b8aa46ed Balazs Lecz
    if state != "RUNNING":
188 b8aa46ed Balazs Lecz
      return None
189 c4d3e57f Balazs Lecz
190 c4d3e57f Balazs Lecz
    cpu_list = self._GetCgroupCpuList(instance_name)
191 f078c799 Faidon Liambotis
    memory = self._GetCgroupMemoryLimit(instance_name) / (1024 ** 2)
192 a3f0f306 Jose A. Lopes
    return (instance_name, 0, memory, len(cpu_list),
193 a3f0f306 Jose A. Lopes
            hv_base.HvInstanceState.RUNNING, 0)
194 4b5e40a5 Iustin Pop
195 0200a1af Helga Velroyen
  def GetAllInstancesInfo(self, hvparams=None):
196 4b5e40a5 Iustin Pop
    """Get properties of all instances.
197 4b5e40a5 Iustin Pop

198 0200a1af Helga Velroyen
    @type hvparams: dict of strings
199 0200a1af Helga Velroyen
    @param hvparams: hypervisor parameter
200 4b5e40a5 Iustin Pop
    @return: [(name, id, memory, vcpus, stat, times),...]
201 4b5e40a5 Iustin Pop

202 4b5e40a5 Iustin Pop
    """
203 4b5e40a5 Iustin Pop
    data = []
204 2e5a6203 Faidon Liambotis
    for name in os.listdir(self._ROOT_DIR):
205 2e5a6203 Faidon Liambotis
      try:
206 2e5a6203 Faidon Liambotis
        info = self.GetInstanceInfo(name)
207 2e5a6203 Faidon Liambotis
      except errors.HypervisorError:
208 2e5a6203 Faidon Liambotis
        continue
209 2e5a6203 Faidon Liambotis
      if info:
210 2e5a6203 Faidon Liambotis
        data.append(info)
211 4b5e40a5 Iustin Pop
    return data
212 4b5e40a5 Iustin Pop
213 4b5e40a5 Iustin Pop
  def _CreateConfigFile(self, instance, root_dir):
214 e3ed5316 Balazs Lecz
    """Create an lxc.conf file for an instance.
215 e3ed5316 Balazs Lecz

216 e3ed5316 Balazs Lecz
    """
217 4b5e40a5 Iustin Pop
    out = []
218 4b5e40a5 Iustin Pop
    # hostname
219 4b5e40a5 Iustin Pop
    out.append("lxc.utsname = %s" % instance.name)
220 4b5e40a5 Iustin Pop
221 4b5e40a5 Iustin Pop
    # separate pseudo-TTY instances
222 4b5e40a5 Iustin Pop
    out.append("lxc.pts = 255")
223 637c8ab8 Balazs Lecz
    # standard TTYs
224 4b5e40a5 Iustin Pop
    out.append("lxc.tty = 6")
225 637c8ab8 Balazs Lecz
    # console log file
226 637c8ab8 Balazs Lecz
    console_log = utils.PathJoin(self._ROOT_DIR, instance.name + ".console")
227 637c8ab8 Balazs Lecz
    try:
228 637c8ab8 Balazs Lecz
      utils.WriteFile(console_log, data="", mode=constants.SECURE_FILE_MODE)
229 637c8ab8 Balazs Lecz
    except EnvironmentError, err:
230 637c8ab8 Balazs Lecz
      raise errors.HypervisorError("Creating console log file %s for"
231 637c8ab8 Balazs Lecz
                                   " instance %s failed: %s" %
232 637c8ab8 Balazs Lecz
                                   (console_log, instance.name, err))
233 637c8ab8 Balazs Lecz
    out.append("lxc.console = %s" % console_log)
234 4b5e40a5 Iustin Pop
235 4b5e40a5 Iustin Pop
    # root FS
236 4b5e40a5 Iustin Pop
    out.append("lxc.rootfs = %s" % root_dir)
237 4b5e40a5 Iustin Pop
238 4b5e40a5 Iustin Pop
    # TODO: additional mounts, if we disable CAP_SYS_ADMIN
239 4b5e40a5 Iustin Pop
240 e3ed5316 Balazs Lecz
    # CPUs
241 e3ed5316 Balazs Lecz
    if instance.hvparams[constants.HV_CPU_MASK]:
242 e3ed5316 Balazs Lecz
      cpu_list = utils.ParseCpuMask(instance.hvparams[constants.HV_CPU_MASK])
243 e3ed5316 Balazs Lecz
      cpus_in_mask = len(cpu_list)
244 e3ed5316 Balazs Lecz
      if cpus_in_mask != instance.beparams["vcpus"]:
245 e3ed5316 Balazs Lecz
        raise errors.HypervisorError("Number of VCPUs (%d) doesn't match"
246 e3ed5316 Balazs Lecz
                                     " the number of CPUs in the"
247 e3ed5316 Balazs Lecz
                                     " cpu_mask (%d)" %
248 e3ed5316 Balazs Lecz
                                     (instance.beparams["vcpus"],
249 e3ed5316 Balazs Lecz
                                      cpus_in_mask))
250 e3ed5316 Balazs Lecz
      out.append("lxc.cgroup.cpuset.cpus = %s" %
251 e3ed5316 Balazs Lecz
                 instance.hvparams[constants.HV_CPU_MASK])
252 e3ed5316 Balazs Lecz
253 f078c799 Faidon Liambotis
    # Memory
254 f078c799 Faidon Liambotis
    # Conditionally enable, memory resource controller might be disabled
255 f078c799 Faidon Liambotis
    cgroup = self._GetCgroupMountPoint()
256 f078c799 Faidon Liambotis
    if os.path.exists(utils.PathJoin(cgroup, 'memory.limit_in_bytes')):
257 e4157912 Guido Trotter
      out.append("lxc.cgroup.memory.limit_in_bytes = %dM" %
258 e4157912 Guido Trotter
                 instance.beparams[constants.BE_MAXMEM])
259 f078c799 Faidon Liambotis
260 f078c799 Faidon Liambotis
    if os.path.exists(utils.PathJoin(cgroup, 'memory.memsw.limit_in_bytes')):
261 e4157912 Guido Trotter
      out.append("lxc.cgroup.memory.memsw.limit_in_bytes = %dM" %
262 e4157912 Guido Trotter
                 instance.beparams[constants.BE_MAXMEM])
263 f078c799 Faidon Liambotis
264 4b5e40a5 Iustin Pop
    # Device control
265 4b5e40a5 Iustin Pop
    # deny direct device access
266 4b5e40a5 Iustin Pop
    out.append("lxc.cgroup.devices.deny = a")
267 4b5e40a5 Iustin Pop
    for devinfo in self._DEVS:
268 4b5e40a5 Iustin Pop
      out.append("lxc.cgroup.devices.allow = %s rw" % devinfo)
269 4b5e40a5 Iustin Pop
270 4b5e40a5 Iustin Pop
    # Networking
271 4b5e40a5 Iustin Pop
    for idx, nic in enumerate(instance.nics):
272 4b5e40a5 Iustin Pop
      out.append("# NIC %d" % idx)
273 4b5e40a5 Iustin Pop
      mode = nic.nicparams[constants.NIC_MODE]
274 4b5e40a5 Iustin Pop
      link = nic.nicparams[constants.NIC_LINK]
275 4b5e40a5 Iustin Pop
      if mode == constants.NIC_MODE_BRIDGED:
276 4b5e40a5 Iustin Pop
        out.append("lxc.network.type = veth")
277 4b5e40a5 Iustin Pop
        out.append("lxc.network.link = %s" % link)
278 4b5e40a5 Iustin Pop
      else:
279 4b5e40a5 Iustin Pop
        raise errors.HypervisorError("LXC hypervisor only supports"
280 4b5e40a5 Iustin Pop
                                     " bridged mode (NIC %d has mode %s)" %
281 4b5e40a5 Iustin Pop
                                     (idx, mode))
282 4b5e40a5 Iustin Pop
      out.append("lxc.network.hwaddr = %s" % nic.mac)
283 4b5e40a5 Iustin Pop
      out.append("lxc.network.flags = up")
284 4b5e40a5 Iustin Pop
285 4b5e40a5 Iustin Pop
    # Capabilities
286 4b5e40a5 Iustin Pop
    for cap in self._DENIED_CAPABILITIES:
287 4b5e40a5 Iustin Pop
      out.append("lxc.cap.drop = %s" % cap)
288 4b5e40a5 Iustin Pop
289 4b5e40a5 Iustin Pop
    return "\n".join(out) + "\n"
290 4b5e40a5 Iustin Pop
291 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
292 4b5e40a5 Iustin Pop
    """Start an instance.
293 4b5e40a5 Iustin Pop

294 2e5a6203 Faidon Liambotis
    For LXC, we try to mount the block device and execute 'lxc-start'.
295 e3ed5316 Balazs Lecz
    We use volatile containers.
296 4b5e40a5 Iustin Pop

297 4b5e40a5 Iustin Pop
    """
298 4b5e40a5 Iustin Pop
    root_dir = self._InstanceDir(instance.name)
299 4b5e40a5 Iustin Pop
    try:
300 4b5e40a5 Iustin Pop
      utils.EnsureDirs([(root_dir, self._DIR_MODE)])
301 4b5e40a5 Iustin Pop
    except errors.GenericError, err:
302 c83864fe Balazs Lecz
      raise HypervisorError("Creating instance directory failed: %s", str(err))
303 4b5e40a5 Iustin Pop
304 4b5e40a5 Iustin Pop
    conf_file = self._InstanceConfFile(instance.name)
305 4b5e40a5 Iustin Pop
    utils.WriteFile(conf_file, data=self._CreateConfigFile(instance, root_dir))
306 4b5e40a5 Iustin Pop
307 13c564e7 Balazs Lecz
    log_file = self._InstanceLogFile(instance.name)
308 13c564e7 Balazs Lecz
    if not os.path.exists(log_file):
309 13c564e7 Balazs Lecz
      try:
310 13c564e7 Balazs Lecz
        utils.WriteFile(log_file, data="", mode=constants.SECURE_FILE_MODE)
311 13c564e7 Balazs Lecz
      except EnvironmentError, err:
312 13c564e7 Balazs Lecz
        raise errors.HypervisorError("Creating hypervisor log file %s for"
313 13c564e7 Balazs Lecz
                                     " instance %s failed: %s" %
314 13c564e7 Balazs Lecz
                                     (log_file, instance.name, err))
315 13c564e7 Balazs Lecz
316 4b5e40a5 Iustin Pop
    if not os.path.ismount(root_dir):
317 4b5e40a5 Iustin Pop
      if not block_devices:
318 4b5e40a5 Iustin Pop
        raise HypervisorError("LXC needs at least one disk")
319 4b5e40a5 Iustin Pop
320 4b5e40a5 Iustin Pop
      sda_dev_path = block_devices[0][1]
321 4b5e40a5 Iustin Pop
      result = utils.RunCmd(["mount", sda_dev_path, root_dir])
322 4b5e40a5 Iustin Pop
      if result.failed:
323 c83864fe Balazs Lecz
        raise HypervisorError("Mounting the root dir of LXC instance %s"
324 c83864fe Balazs Lecz
                              " failed: %s" % (instance.name, result.output))
325 4b5e40a5 Iustin Pop
    result = utils.RunCmd(["lxc-start", "-n", instance.name,
326 13c564e7 Balazs Lecz
                           "-o", log_file,
327 13c564e7 Balazs Lecz
                           "-l", "DEBUG",
328 4b5e40a5 Iustin Pop
                           "-f", conf_file, "-d"])
329 4b5e40a5 Iustin Pop
    if result.failed:
330 4b5e40a5 Iustin Pop
      raise HypervisorError("Running the lxc-start script failed: %s" %
331 4b5e40a5 Iustin Pop
                            result.output)
332 4b5e40a5 Iustin Pop
333 4b5e40a5 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
334 4b5e40a5 Iustin Pop
    """Stop an instance.
335 4b5e40a5 Iustin Pop

336 4b5e40a5 Iustin Pop
    This method has complicated cleanup tests, as we must:
337 4b5e40a5 Iustin Pop
      - try to kill all leftover processes
338 4b5e40a5 Iustin Pop
      - try to unmount any additional sub-mountpoints
339 4b5e40a5 Iustin Pop
      - finally unmount the instance dir
340 4b5e40a5 Iustin Pop

341 4b5e40a5 Iustin Pop
    """
342 4b5e40a5 Iustin Pop
    if name is None:
343 4b5e40a5 Iustin Pop
      name = instance.name
344 4b5e40a5 Iustin Pop
345 4b5e40a5 Iustin Pop
    root_dir = self._InstanceDir(name)
346 4b5e40a5 Iustin Pop
    if not os.path.exists(root_dir):
347 4b5e40a5 Iustin Pop
      return
348 4b5e40a5 Iustin Pop
349 4b5e40a5 Iustin Pop
    if name in self.ListInstances():
350 4b5e40a5 Iustin Pop
      # Signal init to shutdown; this is a hack
351 4b5e40a5 Iustin Pop
      if not retry and not force:
352 4b5e40a5 Iustin Pop
        result = utils.RunCmd(["chroot", root_dir, "poweroff"])
353 4b5e40a5 Iustin Pop
        if result.failed:
354 c83864fe Balazs Lecz
          raise HypervisorError("Running 'poweroff' on the instance"
355 c83864fe Balazs Lecz
                                " failed: %s" % result.output)
356 4b5e40a5 Iustin Pop
      time.sleep(2)
357 4b5e40a5 Iustin Pop
      result = utils.RunCmd(["lxc-stop", "-n", name])
358 4b5e40a5 Iustin Pop
      if result.failed:
359 4b5e40a5 Iustin Pop
        logging.warning("Error while doing lxc-stop for %s: %s", name,
360 4b5e40a5 Iustin Pop
                        result.output)
361 4b5e40a5 Iustin Pop
362 2e5a6203 Faidon Liambotis
    if not os.path.ismount(root_dir):
363 e4157912 Guido Trotter
      return
364 2e5a6203 Faidon Liambotis
365 4b5e40a5 Iustin Pop
    for mpath in self._GetMountSubdirs(root_dir):
366 4b5e40a5 Iustin Pop
      result = utils.RunCmd(["umount", mpath])
367 4b5e40a5 Iustin Pop
      if result.failed:
368 4b5e40a5 Iustin Pop
        logging.warning("Error while umounting subpath %s for instance %s: %s",
369 4b5e40a5 Iustin Pop
                        mpath, name, result.output)
370 4b5e40a5 Iustin Pop
371 4b5e40a5 Iustin Pop
    result = utils.RunCmd(["umount", root_dir])
372 4b5e40a5 Iustin Pop
    if result.failed and force:
373 4b5e40a5 Iustin Pop
      msg = ("Processes still alive in the chroot: %s" %
374 4b5e40a5 Iustin Pop
             utils.RunCmd("fuser -vm %s" % root_dir).output)
375 4b5e40a5 Iustin Pop
      logging.error(msg)
376 c83864fe Balazs Lecz
      raise HypervisorError("Unmounting the chroot dir failed: %s (%s)" %
377 4b5e40a5 Iustin Pop
                            (result.output, msg))
378 4b5e40a5 Iustin Pop
379 4b5e40a5 Iustin Pop
  def RebootInstance(self, instance):
380 4b5e40a5 Iustin Pop
    """Reboot an instance.
381 4b5e40a5 Iustin Pop

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

384 4b5e40a5 Iustin Pop
    """
385 4b5e40a5 Iustin Pop
    # TODO: implement reboot
386 4b5e40a5 Iustin Pop
    raise HypervisorError("The LXC hypervisor doesn't implement the"
387 4b5e40a5 Iustin Pop
                          " reboot functionality")
388 4b5e40a5 Iustin Pop
389 2e2fb795 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
390 2e2fb795 Guido Trotter
    """Balloon an instance memory to a certain value.
391 2e2fb795 Guido Trotter

392 2e2fb795 Guido Trotter
    @type instance: L{objects.Instance}
393 2e2fb795 Guido Trotter
    @param instance: instance to be accepted
394 2e2fb795 Guido Trotter
    @type mem: int
395 2e2fb795 Guido Trotter
    @param mem: actual memory size to use for instance runtime
396 2e2fb795 Guido Trotter

397 2e2fb795 Guido Trotter
    """
398 2e2fb795 Guido Trotter
    # Currently lxc instances don't have memory limits
399 2e2fb795 Guido Trotter
    pass
400 2e2fb795 Guido Trotter
401 fac489a5 Helga Velroyen
  def GetNodeInfo(self, hvparams=None):
402 4b5e40a5 Iustin Pop
    """Return information about the node.
403 4b5e40a5 Iustin Pop

404 ef14e128 Bernardo Dal Seno
    See L{BaseHypervisor.GetLinuxNodeInfo}.
405 4b5e40a5 Iustin Pop

406 4b5e40a5 Iustin Pop
    """
407 4b5e40a5 Iustin Pop
    return self.GetLinuxNodeInfo()
408 4b5e40a5 Iustin Pop
409 4b5e40a5 Iustin Pop
  @classmethod
410 c42be2c0 Petr Pudlak
  def GetInstanceConsole(cls, instance, primary_node, node_group,
411 c42be2c0 Petr Pudlak
                         hvparams, beparams):
412 4b5e40a5 Iustin Pop
    """Return a command for connecting to the console of an instance.
413 4b5e40a5 Iustin Pop

414 4b5e40a5 Iustin Pop
    """
415 c42be2c0 Petr Pudlak
    ndparams = node_group.FillND(primary_node)
416 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
417 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
418 1c3231aa Thomas Thrainer
                                   host=primary_node.name,
419 c42be2c0 Petr Pudlak
                                   port=ndparams.get(constants.ND_SSH_PORT),
420 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
421 55cc0a44 Michael Hanselmann
                                   command=["lxc-console", "-n", instance.name])
422 4b5e40a5 Iustin Pop
423 75bf3149 Helga Velroyen
  def Verify(self, hvparams=None):
424 4b5e40a5 Iustin Pop
    """Verify the hypervisor.
425 4b5e40a5 Iustin Pop

426 cd04dfd2 Michael Hanselmann
    For the LXC manager, it just checks the existence of the base dir.
427 cd04dfd2 Michael Hanselmann

428 75bf3149 Helga Velroyen
    @type hvparams: dict of strings
429 75bf3149 Helga Velroyen
    @param hvparams: hypervisor parameters to be verified against; not used here
430 75bf3149 Helga Velroyen

431 cd04dfd2 Michael Hanselmann
    @return: Problem description if something is wrong, C{None} otherwise
432 4b5e40a5 Iustin Pop

433 4b5e40a5 Iustin Pop
    """
434 0628a50a Iustin Pop
    msgs = []
435 0628a50a Iustin Pop
436 0628a50a Iustin Pop
    if not os.path.exists(self._ROOT_DIR):
437 0628a50a Iustin Pop
      msgs.append("The required directory '%s' does not exist" %
438 0628a50a Iustin Pop
                  self._ROOT_DIR)
439 0628a50a Iustin Pop
440 0628a50a Iustin Pop
    try:
441 0628a50a Iustin Pop
      self._GetCgroupMountPoint()
442 0628a50a Iustin Pop
    except errors.HypervisorError, err:
443 0628a50a Iustin Pop
      msgs.append(str(err))
444 0628a50a Iustin Pop
445 0628a50a Iustin Pop
    return self._FormatVerifyResults(msgs)
446 4b5e40a5 Iustin Pop
447 4b5e40a5 Iustin Pop
  @classmethod
448 8ef418bb Helga Velroyen
  def PowercycleNode(cls, hvparams=None):
449 4b5e40a5 Iustin Pop
    """LXC powercycle, just a wrapper over Linux powercycle.
450 4b5e40a5 Iustin Pop

451 8ef418bb Helga Velroyen
    @type hvparams: dict of strings
452 8ef418bb Helga Velroyen
    @param hvparams: hypervisor params to be used on this node
453 8ef418bb Helga Velroyen

454 4b5e40a5 Iustin Pop
    """
455 4b5e40a5 Iustin Pop
    cls.LinuxPowercycle()
456 4b5e40a5 Iustin Pop
457 bc0a2284 Helga Velroyen
  def MigrateInstance(self, cluster_name, instance, target, live):
458 4b5e40a5 Iustin Pop
    """Migrate an instance.
459 4b5e40a5 Iustin Pop

460 bc0a2284 Helga Velroyen
    @type cluster_name: string
461 bc0a2284 Helga Velroyen
    @param cluster_name: name of the cluster
462 4b5e40a5 Iustin Pop
    @type instance: L{objects.Instance}
463 4b5e40a5 Iustin Pop
    @param instance: the instance to be migrated
464 4b5e40a5 Iustin Pop
    @type target: string
465 4b5e40a5 Iustin Pop
    @param target: hostname (usually ip) of the target node
466 4b5e40a5 Iustin Pop
    @type live: boolean
467 4b5e40a5 Iustin Pop
    @param live: whether to do a live or non-live migration
468 4b5e40a5 Iustin Pop

469 4b5e40a5 Iustin Pop
    """
470 c83864fe Balazs Lecz
    raise HypervisorError("Migration is not supported by the LXC hypervisor")
471 60af751d Andrea Spadaccini
472 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
473 60af751d Andrea Spadaccini
    """Get the migration status
474 60af751d Andrea Spadaccini

475 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
476 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
477 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
478 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
479 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
480 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
481 60af751d Andrea Spadaccini

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