Since LXC version >= 1.0.0, the LXC strictly requires all cgroup
subsystems mounted before starting a container.
Users can control the list of desired cgroup subsystems for LXC
containers by specifying lxc.cgroup.use parameter in LXC system
configuration file, its default value is "@kernel" which means all
cgroup kernel subsystems.
The _EnsureCgroupMounts method ensures all cgroup subsystems in the
/proc/cgroups are mounted.
The new lxc_cgroup_use hvparam is added to overwrite the prerequisite
cgroup subsystems list as well as lxc.cgroup.use parameter of the LXC
system configuration.
Also, since _GetCgroupMountPoint was changed to a function which returns
just the constant, calling it in the Verify method is meaningless now.
Instead, calling _EnsureCgroupMounts in the Verify can be used to check
the actual cgroup mount requirements.

Signed-off-by: Yuto KAWAMURA(kawamuray) <[email protected]>
---
 lib/hypervisor/hv_lxc.py                     | 42 +++++++++++++++++++++++++---
 man/gnt-instance.rst                         | 22 +++++++++++++++
 src/Ganeti/Constants.hs                      |  5 ++++
 test/py/ganeti.hypervisor.hv_lxc_unittest.py |  2 +-
 4 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/lib/hypervisor/hv_lxc.py b/lib/hypervisor/hv_lxc.py
index b63342a..6d110fc 100644
--- a/lib/hypervisor/hv_lxc.py
+++ b/lib/hypervisor/hv_lxc.py
@@ -55,7 +55,8 @@ class LXCHypervisor(hv_base.BaseHypervisor):
   """
   _ROOT_DIR = pathutils.RUN_DIR + "/lxc"
   _CGROUP_ROOT_DIR = _ROOT_DIR + "/cgroup"
-  _PROC_CGROUP_FILE = "/proc/self/cgroup"
+  _PROC_CGROUPS_FILE = "/proc/cgroups"
+  _PROC_SELF_CGROUP_FILE = "/proc/self/cgroup"
 
   _DEVS = [
     "c 1:3",   # /dev/null
@@ -83,6 +84,7 @@ class LXCHypervisor(hv_base.BaseHypervisor):
 
   PARAMETERS = {
     constants.HV_CPU_MASK: hv_base.OPT_CPU_MASK_CHECK,
+    constants.HV_LXC_CGROUP_USE: hv_base.NO_CHECK,
     constants.HV_LXC_STARTUP_WAIT: hv_base.OPT_NONNEGATIVE_INT_CHECK,
     }
 
@@ -245,10 +247,10 @@ class LXCHypervisor(hv_base.BaseHypervisor):
 
     """
     try:
-      cgroup_list = utils.ReadFile(cls._PROC_CGROUP_FILE)
+      cgroup_list = utils.ReadFile(cls._PROC_SELF_CGROUP_FILE)
     except EnvironmentError, err:
       raise HypervisorError("Failed to read %s : %s" %
-                            (cls._PROC_CGROUP_FILE, err))
+                            (cls._PROC_SELF_CGROUP_FILE, err))
 
     cgroups = {}
     for line in filter(None, cgroup_list.split("\n")):
@@ -464,6 +466,32 @@ class LXCHypervisor(hv_base.BaseHypervisor):
     return "\n".join(out) + "\n"
 
   @classmethod
+  def _GetCgroupEnabledKernelSubsystems(cls):
+    """Return cgroup subsystems list that are enabled in current kernel.
+
+    """
+    try:
+      subsys_table = utils.ReadFile(cls._PROC_CGROUPS_FILE)
+    except EnvironmentError, err:
+      raise HypervisorError("Failed to read cgroup info from %s: %s"
+                            % (cls._PROC_CGROUPS_FILE, err))
+    return [x.split(None, 1)[0] for x in subsys_table.split("\n")
+            if x and not x.startswith("#")]
+
+  @classmethod
+  def _EnsureCgroupMounts(cls, hvparams=None):
+    """Ensures all cgroup subsystems required to run LXC container are mounted.
+
+    """
+    if hvparams is None or not hvparams[constants.HV_LXC_CGROUP_USE]:
+      enable_subsystems = cls._GetCgroupEnabledKernelSubsystems()
+    else:
+      enable_subsystems = hvparams[constants.HV_LXC_CGROUP_USE].split(",")
+
+    for subsystem in enable_subsystems:
+      cls._GetOrPrepareCgroupSubsysMountPoint(subsystem)
+
+  @classmethod
   def _PrepareInstanceRootFsBdev(cls, storage_path, stash):
     """Return mountable path for storage_path.
 
@@ -544,6 +572,12 @@ class LXCHypervisor(hv_base.BaseHypervisor):
 
     """
     stash = {}
+
+    # Since LXC version >= 1.0.0, the LXC strictly requires all cgroup
+    # subsystems mounted before starting a container.
+    # Try to mount all cgroup subsystems needed to start a LXC container.
+    self._EnsureCgroupMounts(instance.hvparams)
+
     root_dir = self._InstanceDir(instance.name)
     try:
       utils.EnsureDirs([(root_dir, self._DIR_MODE)])
@@ -679,7 +713,7 @@ class LXCHypervisor(hv_base.BaseHypervisor):
                   self._ROOT_DIR)
 
     try:
-      self._GetCgroupMountPoint()
+      self._EnsureCgroupMounts(hvparams)
     except errors.HypervisorError, err:
       msgs.append(str(err))
 
diff --git a/man/gnt-instance.rst b/man/gnt-instance.rst
index 25c7fec..96e2cee 100644
--- a/man/gnt-instance.rst
+++ b/man/gnt-instance.rst
@@ -879,6 +879,28 @@ lxc\_startup\_wait
 
     It is set to ``30`` by default.
 
+lxc\_cgroup\_use
+    Valid for the LXC hypervisor.
+
+    This option specifies the list of cgroup subsystems that need to
+    be mounted before starting LXC containers.
+    Since LXC version >= 1.0.0, the LXC strictly requires all cgroup
+    subsystems mounted before starting a container.
+    Users can control the list of desired cgroup subsystems for LXC
+    containers by specifying lxc.cgroup.use parameter in LXC system
+    configuration file(see: **lxc.system.conf**\(5)), its default value
+    is "@kernel" which means all cgroup kernel subsystems.
+    The LXC hypervisor of Ganeti tries to mount all cgroup subsystems
+    needed to start a LXC container.
+    This parameter can be used to control the list of cgroup
+    subsystems that should be ensured by Ganeti before starting a LXC
+    container.
+    The value of this parameter should be a list of cgroup subsystems
+    separated by a comma(e.g., "cpuset,devices,memory").
+
+    If this parameter is not specified, a list will be built from info
+    in /proc/cgroups.
+
 The ``-O (--os-parameters)`` option allows customisation of the OS
 parameters. The actual parameter names and values depend on the OS being
 used, but the syntax is the same key=value. For example, setting a
diff --git a/src/Ganeti/Constants.hs b/src/Ganeti/Constants.hs
index a7ac94f..178fd3d 100644
--- a/src/Ganeti/Constants.hs
+++ b/src/Ganeti/Constants.hs
@@ -1667,6 +1667,9 @@ hvKvmUserShutdown = "user_shutdown"
 hvLxcStartupWait :: String
 hvLxcStartupWait = "lxc_startup_wait"
 
+hvLxcCgroupUse :: String
+hvLxcCgroupUse = "lxc_cgroup_use"
+
 hvMemPath :: String
 hvMemPath = "mem_path"
 
@@ -1829,6 +1832,7 @@ hvsParameterTypes = Map.fromList
   , (hvKvmSpiceZlibGlzImgCompr,         VTypeString)
   , (hvKvmUseChroot,                    VTypeBool)
   , (hvKvmUserShutdown,                 VTypeBool)
+  , (hvLxcCgroupUse,                    VTypeString)
   , (hvLxcStartupWait,                  VTypeInt)
   , (hvMemPath,                         VTypeString)
   , (hvMigrationBandwidth,              VTypeInt)
@@ -3910,6 +3914,7 @@ hvcDefaults =
   , (Chroot, Map.fromList [(hvInitScript, PyValueEx "/ganeti-chroot")])
   , (Lxc, Map.fromList
           [ (hvCpuMask,        PyValueEx "")
+          , (hvLxcCgroupUse,   PyValueEx "")
           , (hvLxcStartupWait, PyValueEx (30 :: Int))
           ])
   ]
diff --git a/test/py/ganeti.hypervisor.hv_lxc_unittest.py 
b/test/py/ganeti.hypervisor.hv_lxc_unittest.py
index d8fb28a..cc4bb38 100755
--- a/test/py/ganeti.hypervisor.hv_lxc_unittest.py
+++ b/test/py/ganeti.hypervisor.hv_lxc_unittest.py
@@ -137,7 +137,7 @@ class TestCgroupReadData(unittest.TestCase):
   def testGetCgroupMountPoint(self):
     self.assertEqual(self.hv._GetCgroupMountPoint(), self.cgroot)
 
-  @patch_object(LXCHypervisor, "_PROC_CGROUP_FILE",
+  @patch_object(LXCHypervisor, "_PROC_SELF_CGROUP_FILE",
                 testutils.TestDataFilename("proc_cgroup.txt"))
   def testGetCurrentCgroupSubsysGroups(self):
     expected_groups = {
-- 
1.8.5.5

Reply via email to