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
