1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-01-31 02:00:45 +00:00

module/cgroups2: Added utilisation of the 'LinuxTarget' interface.

Replaced all references to devlib.Target with devlib.LinuxTarget to correctly
utilise appropriate interface.
Also added relevant functionality to corectly
create the root directories of the CGroup hierarchies, handling any error that
occurs in that case.
This commit is contained in:
Ibrahim Hassan 2022-12-17 18:37:31 +00:00 committed by Marc Bonnici
parent 5ea63490a9
commit e012b175c6

View File

@ -26,17 +26,17 @@ It also handles the cgroup delegation API of systemd.
.. code-block:: python .. code-block:: python
# Necessary Imports # Necessary Imports
from devlib import Target from devlib import LinuxTarget
from devlib.module.cgroups2 import RequestTree from devlib.module.cgroups2 import RequestTree
# Connecting to target device. Configure appropriately. # Connecting to target device. Configure appropriately.
my_target = Target(name="target", my_target = LinuxTarget(connection_settings={
host="127.0.0.1", "host":"127.0.0.1",
port="0000", "port":"0000",
username="root", "username":"root",
password="root", "password":"root"
kind="linux") })
# Instantiating the RequestTree object, # Instantiating the RequestTree object,
# representing a hierarchical CGroup structure consisting # representing a hierarchical CGroup structure consisting
@ -104,7 +104,7 @@ from shlex import quote
from typing import Dict, Set, List, Union, Any from typing import Dict, Set, List, Union, Any
from uuid import uuid4 from uuid import uuid4
from devlib import Target from devlib import LinuxTarget
from devlib.exception import ( from devlib.exception import (
TargetStableCalledProcessError, TargetStableCalledProcessError,
TargetStableError, TargetStableError,
@ -113,7 +113,7 @@ from devlib.target import FstabEntry
from devlib.utils.misc import memoized from devlib.utils.misc import memoized
def _is_systemd_online(target: Target): def _is_systemd_online(target: LinuxTarget):
""" """
Determines if systemd is activated on the target system. Determines if systemd is activated on the target system.
@ -132,7 +132,7 @@ def _is_systemd_online(target: Target):
return True return True
def _read_lines(target: Target, path: str): def _read_lines(target: LinuxTarget, path: str):
""" """
Reads the lines of a file stored on the target device. Reads the lines of a file stored on the target device.
@ -228,13 +228,17 @@ def _add_controller_mounts(
return { return {
controller: {**config, "mount_point": path if path is not None else config} controller: {**config, "mount_point": path if path is not None else config}
for (controller, config, path) in ( for (controller, config, path) in (
(controller, config, _infer_mount(controller=controller,configuration=config)) (
controller,
config,
_infer_mount(controller=controller, configuration=config),
)
for (controller, config) in controllers.items() for (controller, config) in controllers.items()
) )
} }
def _get_cgroup_controllers(target: Target): def _get_cgroup_controllers(target: LinuxTarget):
""" """
Returns the CGroup controllers that are currently enabled on the target device, alongside their appropriate configurations. Returns the CGroup controllers that are currently enabled on the target device, alongside their appropriate configurations.
@ -287,7 +291,7 @@ def _get_cgroup_controllers(target: Target):
@contextmanager @contextmanager
def _request_delegation(target: Target): def _request_delegation(target: LinuxTarget):
""" """
Requests systemd to delegate a subtree CGroup hierarchy to our transient service unit. Requests systemd to delegate a subtree CGroup hierarchy to our transient service unit.
@ -322,7 +326,7 @@ def _request_delegation(target: Target):
@contextmanager @contextmanager
def _mount_v2_controllers(target: Target): def _mount_v2_controllers(target: LinuxTarget):
""" """
Mounts the V2 unified CGroup controller hierarchy. Mounts the V2 unified CGroup controller hierarchy.
@ -331,22 +335,27 @@ def _mount_v2_controllers(target: Target):
:yield: The path to the root of the mounted V2 controller hierarchy. :yield: The path to the root of the mounted V2 controller hierarchy.
:rtype: str :rtype: str
:raises TargetStableError: Occurs in the case where the root directory of the requested CGroup V2 Controller hierarchy
is unable to be created up on the target system.
""" """
try: path = target.tempfile()
path = target.execute(
"{busybox} mktemp -d".format(busybox=quote(target.busybox)), as_root=True
).strip()
try:
target.makedirs(path, as_root=True)
except TargetStableCalledProcessError:
raise TargetStableError("Un-able to create the root directory of the requested CGroup V2 hierarchy")
try:
target.execute( target.execute(
"{busybox} mount -t cgroup2 none {path}".format( "{busybox} mount -t cgroup2 none {path}".format(
busybox=quote(target.busybox), path=quote(path) busybox=quote(target.busybox), path=quote(path)
), ),
as_root=True, as_root=True,
) )
yield path yield path
finally: finally:
target.execute( target.execute(
"{busybox} umount {path} && {busybox} rmdir -- {path}".format( "{busybox} umount {path} && {busybox} rmdir -- {path}".format(
@ -358,7 +367,7 @@ def _mount_v2_controllers(target: Target):
@contextmanager @contextmanager
def _mount_v1_controllers(target: Target, controllers: Set[str]): def _mount_v1_controllers(target: LinuxTarget, controllers: Set[str]):
""" """
Mounts the V1 split CGroup controller hierarchies. Mounts the V1 split CGroup controller hierarchies.
@ -370,18 +379,24 @@ def _mount_v1_controllers(target: Target, controllers: Set[str]):
:yield: A dictionary mapping CGroup controller names to the paths that they're currently mounted at. :yield: A dictionary mapping CGroup controller names to the paths that they're currently mounted at.
:rtype: Dict[str,str] :rtype: Dict[str,str]
:raises TargetStableError: Occurs in the case where the root directory of a requested CGroup V1 Controller hierarchy
is unable to be created up on the target system.
""" """
# Internal helper function which mounts a single V1 controller hierarchy and returns # Internal helper function which mounts a single V1 controller hierarchy and returns
# its mount path. # its mount path.
@contextmanager @contextmanager
def _mount_controller(controller): def _mount_controller(controller):
try:
path = target.execute(
"{busybox} mktemp -d".format(busybox=quote(target.busybox)),
as_root=True,
).strip()
path = target.tempfile()
try:
target.makedirs(path, as_root=True)
except TargetStableCalledProcessError as err:
raise TargetStableError("Un-able to create the root directory of the {controller} CGroup V1 hierarchy".format(controller = controller))
try:
target.execute( target.execute(
"{busybox} mount -t cgroup -o {controller} none {path}".format( "{busybox} mount -t cgroup -o {controller} none {path}".format(
busybox=quote(target.busybox), busybox=quote(target.busybox),
@ -389,6 +404,7 @@ def _mount_v1_controllers(target: Target, controllers: Set[str]):
path=quote(path), path=quote(path),
), ),
) )
yield path yield path
finally: finally:
@ -459,7 +475,7 @@ class _CGroupBase(ABC):
name: str, name: str,
parent_path: str, parent_path: str,
active_controllers: Dict[str, Dict[str, str]], active_controllers: Dict[str, Dict[str, str]],
target: Target, target: LinuxTarget,
): ):
self.name = name self.name = name
self.active_controllers = active_controllers self.active_controllers = active_controllers
@ -551,8 +567,9 @@ class _CGroupBase(ABC):
path=self.target.path.join(self.group_path, "cgroup.procs"), path=self.target.path.join(self.group_path, "cgroup.procs"),
target=self.target, target=self.target,
) )
except TargetStableCalledProcessError: except TargetStableError:
self._set_controller_attribute("cgroup", "procs", pid) self._set_controller_attribute("cgroup", "procs", pid)
else: else:
if str(pid) not in member_processes: if str(pid) not in member_processes:
self._set_controller_attribute("cgroup", "procs", pid) self._set_controller_attribute("cgroup", "procs", pid)
@ -648,7 +665,7 @@ class _CGroupV2(_CGroupBase):
active_controllers: Dict[str, Dict[str, str]], active_controllers: Dict[str, Dict[str, str]],
subtree_controllers: set, subtree_controllers: set,
is_threaded: bool, is_threaded: bool,
target: Target, target: LinuxTarget,
): ):
super().__init__( super().__init__(
@ -705,7 +722,7 @@ class _CGroupV2(_CGroupBase):
self._set_controller_attribute( self._set_controller_attribute(
"cgroup", "type", "threaded", verify=True "cgroup", "type", "threaded", verify=True
) )
except TargetStableCalledProcessError: except TargetStableError:
raise TargetStableError( raise TargetStableError(
"Domain CGroup controllers are enabled within a threaded CGroup subtree. Ensure only threaded controllers are enabled in threaded CGroups." "Domain CGroup controllers are enabled within a threaded CGroup subtree. Ensure only threaded controllers are enabled in threaded CGroups."
) )
@ -822,7 +839,7 @@ class _CGroupV2Root(_CGroupV2):
} }
@classmethod @classmethod
def _get_delegated_sub_path(cls, delegated_pid: int, target: Target): def _get_delegated_sub_path(cls, delegated_pid: int, target: LinuxTarget):
""" """
Returns the relative sub-path the delegated root of the V2 hierarchy is mounted on, via the parsing Returns the relative sub-path the delegated root of the V2 hierarchy is mounted on, via the parsing
of the /proc/<PID>/cgroup file of the delegated process associated with ``delegated_pid``. of the /proc/<PID>/cgroup file of the delegated process associated with ``delegated_pid``.
@ -939,7 +956,7 @@ class _CGroupV2Root(_CGroupV2):
@contextmanager @contextmanager
def _systemd_offline_mount( def _systemd_offline_mount(
cls, cls,
target: Target, target: LinuxTarget,
all_controllers: Dict[str, Dict[str, Union[str, int]]], all_controllers: Dict[str, Dict[str, Union[str, int]]],
requested_controllers: Set[str], requested_controllers: Set[str],
): ):
@ -976,7 +993,7 @@ class _CGroupV2Root(_CGroupV2):
@contextmanager @contextmanager
def _systemd_online_setup( def _systemd_online_setup(
cls, cls,
target: Target, target: LinuxTarget,
all_controllers: Dict[str, Dict[str, int]], all_controllers: Dict[str, Dict[str, int]],
requested_controllers: Set[str], requested_controllers: Set[str],
): ):
@ -1031,7 +1048,7 @@ class _CGroupV2Root(_CGroupV2):
@classmethod @classmethod
@contextmanager @contextmanager
def _mount_filesystem(cls, target: Target, requested_controllers: Set[str]): def _mount_filesystem(cls, target: LinuxTarget, requested_controllers: Set[str]):
""" """
Mounts/Sets-up a V2 hierarchy on the target device, covering contexts where Mounts/Sets-up a V2 hierarchy on the target device, covering contexts where
systemd is both present and absent. systemd is both present and absent.
@ -1073,7 +1090,7 @@ class _CGroupV2Root(_CGroupV2):
self, self,
mount_point: str, mount_point: str,
subtree_controllers: set, subtree_controllers: set,
target: Target, target: LinuxTarget,
): ):
super().__init__( super().__init__(
@ -1250,9 +1267,9 @@ class _CGroupV1Root(_CGroupV1):
@classmethod @classmethod
def _get_delegated_paths( def _get_delegated_paths(
cls, cls,
controllers: Dict[str, Dict[str,Union[str, int]]], controllers: Dict[str, Dict[str, Union[str, int]]],
delegated_pid: int, delegated_pid: int,
target: Target, target: LinuxTarget,
): ):
""" """
Returns the relative sub-paths the delegated roots of the V1 hierarchies, via the parsing Returns the relative sub-paths the delegated roots of the V1 hierarchies, via the parsing
@ -1322,7 +1339,7 @@ class _CGroupV1Root(_CGroupV1):
cls, cls,
requested_controllers: Set[str], requested_controllers: Set[str],
all_controllers: Dict[str, Dict[str, Union[str, int]]], all_controllers: Dict[str, Dict[str, Union[str, int]]],
target: Target, target: LinuxTarget,
): ):
""" """
Manually mounts the V1 split hierarchy on the target device. Occurs in the absence of systemd. Manually mounts the V1 split hierarchy on the target device. Occurs in the absence of systemd.
@ -1355,7 +1372,9 @@ class _CGroupV1Root(_CGroupV1):
yield mounted yield mounted
@classmethod @classmethod
def _get_available_v1_controllers(cls, controllers: Dict[str, Dict[str, Union[int,str]]]): def _get_available_v1_controllers(
cls, controllers: Dict[str, Dict[str, Union[int, str]]]
):
unused_controllers = { unused_controllers = {
controller: configuration controller: configuration
@ -1372,7 +1391,7 @@ class _CGroupV1Root(_CGroupV1):
@contextmanager @contextmanager
def _systemd_online_setup( def _systemd_online_setup(
cls, cls,
target: Target, target: LinuxTarget,
requested_controllers: Set[str], requested_controllers: Set[str],
all_controllers: Dict[str, Dict[str, str]], all_controllers: Dict[str, Dict[str, str]],
): ):
@ -1409,7 +1428,7 @@ class _CGroupV1Root(_CGroupV1):
@classmethod @classmethod
@contextmanager @contextmanager
def _mount_filesystem(cls, target: Target, requested_controllers: Set[str]): def _mount_filesystem(cls, target: LinuxTarget, requested_controllers: Set[str]):
""" """
A context manager which Mounts/Sets-up a V1 split hierarchy on the target device, covering contexts where A context manager which Mounts/Sets-up a V1 split hierarchy on the target device, covering contexts where
systemd is both present and absent. This context manager Mounts/Sets-up a split V1 hierarchy (if possible) systemd is both present and absent. This context manager Mounts/Sets-up a split V1 hierarchy (if possible)
@ -1447,7 +1466,7 @@ class _CGroupV1Root(_CGroupV1):
with cm as controllers: with cm as controllers:
yield controllers yield controllers
def __init__(self, mount_point: str, target: Target): def __init__(self, mount_point: str, target: LinuxTarget):
super().__init__( super().__init__(
# Root name is null. Isn't required. # Root name is null. Isn't required.
@ -1592,8 +1611,8 @@ class RequestTree(_TreeBase):
their respective to be assigned values, , defaults to ``None``. their respective to be assigned values, , defaults to ``None``.
:type controllers: Dict[str, Dict[str, Union[str,int]]], optional :type controllers: Dict[str, Dict[str, Union[str,int]]], optional
:param is_threaded: defines whether the object will represent a CGroup capable of managing threads, defaults to ``False``. :param threaded: defines whether the object will represent a CGroup capable of managing threads, defaults to ``False``.
:type is_threaded: bool, optional :type threaded: bool, optional
""" """
def __init__( def __init__(
@ -1648,7 +1667,7 @@ class RequestTree(_TreeBase):
return list(self.children) return list(self.children)
@contextmanager @contextmanager
def setup_hierarchy(self, version: int, target: Target): def setup_hierarchy(self, version: int, target: LinuxTarget):
""" """
A context manager which processes the user defined hierarchy and sets-up said hierarchy on the ``target`` device. A context manager which processes the user defined hierarchy and sets-up said hierarchy on the ``target`` device.
Uses an internal exit stack to the handle the entering and safe exiting of the lower level Uses an internal exit stack to the handle the entering and safe exiting of the lower level