Repository: Azure/WALinuxAgent
Pull request #2145 (2021-01-25 19:07:39)

Move agent to azure slice
This PR moves the agent to the azure slice. The slice hierarchy is described in CGroupConfigurator.__ensure_azure_slices_exist.

It also includes some minor changes in telemetry ti distinguish between info and warning messages.

codecov[bot]: # [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145?src=pr&el=h1) Report
> Merging [#2145](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145?src=pr&el=desc) (de1c0e0) into [develop](https://codecov.io/gh/Azure/WALinuxAgent/commit/c2ebffceeba50434c1495e8f2ef54bef8e8a517f?el=desc) (c2ebffc) will **decrease** coverage by `0.04%`.
> The diff coverage is `77.86%`.

[![Impacted file tree graph](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145/graphs/tree.svg?width=650&height=150&src=pr&token=ae90E2KYCw)](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145?src=pr&el=tree)

```diff
@@             Coverage Diff             @@
##           develop    #2145      +/-   ##
===========================================
- Coverage    70.67%   70.62%   -0.05%     
===========================================
  Files           95       95              
  Lines        12939    12931       -8     
  Branches      1842     1843       +1     
===========================================
- Hits          9144     9133      -11     
- Misses        3387     3390       +3     
  Partials       408      408              
```


| [Impacted Files](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [azurelinuxagent/common/cgroupapi.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi9jZ3JvdXBhcGkucHk=) | `80.64% <ø> (-2.10%)` | :arrow_down: |
| [azurelinuxagent/common/event.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi9ldmVudC5weQ==) | `86.62% <ø> (-0.74%)` | :arrow_down: |
| [azurelinuxagent/ga/update.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2dhL3VwZGF0ZS5weQ==) | `88.20% <ø> (-0.02%)` | :arrow_down: |
| [azurelinuxagent/common/cgroupconfigurator.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi9jZ3JvdXBjb25maWd1cmF0b3IucHk=) | `82.08% <77.86%> (+1.59%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145?src=pr&el=footer). Last update [c2ebffc...de1c0e0](https://codecov.io/gh/Azure/WALinuxAgent/pull/2145?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/azurelinuxagent/common/cgroupapi.py b/azurelinuxagent/common/cgroupapi.py
index 9ce2feb4..0768daec 100644
--- a/azurelinuxagent/common/cgroupapi.py
+++ b/azurelinuxagent/common/cgroupapi.py
@@ -23,10 +23,9 @@ import threading
 import uuid
 
 from azurelinuxagent.common import logger
-from azurelinuxagent.common.cgroup import CpuCgroup, MemoryCgroup
+from azurelinuxagent.common.cgroup import CpuCgroup
 from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry
 from azurelinuxagent.common.conf import get_agent_pid_file_path
-from azurelinuxagent.common.event import add_event, WALAEventOperation
 from azurelinuxagent.common.exception import CGroupsException, ExtensionErrorCodes, ExtensionError, ExtensionOperationError
 from azurelinuxagent.common.future import ustr
 from azurelinuxagent.common.osutil import get_osutil
@@ -38,10 +37,6 @@ from azurelinuxagent.common.version import get_distro
 
 CGROUPS_FILE_SYSTEM_ROOT = '/sys/fs/cgroup'
 CGROUP_CONTROLLERS = ["cpu", "memory"]
-VM_AGENT_CGROUP_NAME = "walinuxagent.service"
-AZURE_CGROUP_NAME = "azure"
-EXTENSIONS_CGROUP_NAME = "vmextensions"
-UNIT_FILES_FILE_SYSTEM_PATH = "/etc/systemd/system"
 SYSTEMD_RUN_PATH = "/run/systemd/system/"
 
 
@@ -152,14 +147,6 @@ class SystemdCgroupsApi(CGroupsApi):
         #
         return shellutil.run_command(['systemctl', '--version'])
 
-    @staticmethod
-    def get_azure_slice():
-        return os.path.join(UNIT_FILES_FILE_SYSTEM_PATH, AZURE_CGROUP_NAME, ".slice")
-
-    @staticmethod
-    def get_extensions_slice():
-        return os.path.join(UNIT_FILES_FILE_SYSTEM_PATH, EXTENSIONS_CGROUP_NAME, ".slice")
-
     def get_systemd_run_commands(self):
         """
         Returns a list of the systemd-run commands currently running (given as PIDs)
@@ -267,46 +254,6 @@ class SystemdCgroupsApi(CGroupsApi):
             raise ValueError("Can't find property {0} of {1}", property_name, unit_name)  # pylint: disable=W0715
         return match.group('value')
 
-    @staticmethod
-    def create_unit_file(unit_filename, unit_contents):
-        try:
-            unit_path = os.path.join(UNIT_FILES_FILE_SYSTEM_PATH, unit_filename)
-            fileutil.write_file(unit_path, unit_contents)
-        except Exception as error:
-            raise CGroupsException("Failed to create and start {0}. Error: {1}".format(unit_filename, ustr(error)))
-
-    @staticmethod
-    def _get_azure_slice_name():
-        return "{0}.slice".format(AZURE_CGROUP_NAME)
-
-    @staticmethod
-    def _get_extensions_root_slice_name():
-        return "{0}-{1}.slice".format(AZURE_CGROUP_NAME, EXTENSIONS_CGROUP_NAME)
-
-    def _get_extension_slice_name(self, extension_name):
-        return "{0}-{1}-{2}.slice".format(AZURE_CGROUP_NAME, EXTENSIONS_CGROUP_NAME, self._get_extension_cgroup_name(extension_name))
-
-    def create_azure_slice(self):
-        unit_contents = """[Unit]
-Description=Slice for Azure VM Agent and Extensions"""
-        unit_filename = self._get_azure_slice_name()
-        self.create_unit_file(unit_filename, unit_contents)
-
-        message = "Created slice for Azure VM Agent and Extensions {0}".format(unit_filename)
-        add_event(op=WALAEventOperation.CGroupsInitialize, is_success=True, log_event=False, message=message)
-        logger.info(message)
-
-    def create_extensions_slice(self):
-        unit_contents = """[Unit]
-Description=Slice for Azure VM Extensions"""
-        unit_filename = self._get_extensions_root_slice_name()
-
-        self.create_unit_file(unit_filename, unit_contents)
-
-        message = "Created slice for Azure VM Extensions {0}".format(unit_filename)
-        add_event(op=WALAEventOperation.CGroupsInitialize, is_success=True, log_event=False, message=message)
-        logger.info(message)
-
     def get_agent_unit_name(self):
         if self._agent_unit_name is None:
             self._agent_unit_name = get_osutil().get_service_name() + ".service"
@@ -324,7 +271,7 @@ Description=Slice for Azure VM Extensions"""
 
         with self._systemd_run_commands_lock:
             process = subprocess.Popen(  # pylint: disable=W1509
-                "systemd-run --unit={0} --scope {1}".format(scope, command),
+                "systemd-run --unit={0} --scope --slice=azure-vmextensions.slice {1}".format(scope, command),
                 shell=shell,
                 cwd=cwd,
                 stdout=stdout,
@@ -339,22 +286,15 @@ Description=Slice for Azure VM Extensions"""
 
         try:
             # systemd-run creates the scope under the system slice by default
-            cgroup_relative_path = os.path.join('system.slice', scope_name)
+            cgroup_relative_path = os.path.join('azure.slice/azure-vmextensions.slice', scope_name)
 
-            cpu_cgroup_mountpoint, memory_cgroup_mountpoint = self.get_cgroup_mount_points()
+            cpu_cgroup_mountpoint, _ = self.get_cgroup_mount_points()
 
             if cpu_cgroup_mountpoint is None:
                 logger.info("The CPU controller is not mounted; will not track resource usage")
             else:
                 cpu_cgroup_path = os.path.join(cpu_cgroup_mountpoint, cgroup_relative_path)
                 CGroupsTelemetry.track_cgroup(CpuCgroup(extension_name, cpu_cgroup_path))
-
-            if memory_cgroup_mountpoint is None:
-                logger.info("The memory controller is not mounted; will not track resource usage")
-            else:
-                memory_cgroup_path = os.path.join(memory_cgroup_mountpoint, cgroup_relative_path)
-                CGroupsTelemetry.track_cgroup(MemoryCgroup(extension_name, memory_cgroup_path))
-
         except IOError as e:
             if e.errno == 2:  # 'No such file or directory'
                 logger.info("The extension command already completed; will not track resource usage")
diff --git a/azurelinuxagent/common/cgroupconfigurator.py b/azurelinuxagent/common/cgroupconfigurator.py
index 540c16a3..28695145 100644
--- a/azurelinuxagent/common/cgroupconfigurator.py
+++ b/azurelinuxagent/common/cgroupconfigurator.py
@@ -27,10 +27,40 @@ from azurelinuxagent.common.exception import ExtensionErrorCodes, CGroupsExcepti
 from azurelinuxagent.common.future import ustr
 from azurelinuxagent.common.osutil import get_osutil
 from azurelinuxagent.common.version import get_distro
-from azurelinuxagent.common.utils import shellutil
+from azurelinuxagent.common.utils import shellutil, fileutil
 from azurelinuxagent.common.utils.extensionprocessutil import handle_process_completion
 from azurelinuxagent.common.event import add_event, WALAEventOperation
 
+_AZURE_SLICE = "azure.slice"
+_AZURE_SLICE_CONTENTS = """
+[Unit]
+Description=Slice for Azure VM Agent and Extensions
+DefaultDependencies=no
+Before=slices.target
+"""
+_VMEXTENSIONS_SLICE = "azure-vmextensions.slice"
+_VMEXTENSIONS_SLICE_CONTENTS = """
+[Unit]
+Description=Slice for Azure VM Extensions
+DefaultDependencies=no
+Before=slices.target
+[Slice]
+CPUAccounting=yes
+"""
+_AGENT_DROP_IN_FILE_SLICE = "10-Slice.conf"
+_AGENT_DROP_IN_FILE_SLICE_CONTENTS = """
+# This drop-in unit file was created by the Azure VM Agent.
+# Do not edit.
+[Service]
+Slice=azure.slice
+"""
+_AGENT_DROP_IN_FILE_CPU_ACCOUNTING = "11-CPUAccounting.conf"
+_AGENT_DROP_IN_FILE_CPU_ACCOUNTING_CONTENTS = """
+# This drop-in unit file was created by the Azure VM Agent.
+# Do not edit.
+[Service]
+CPUAccounting=yes
+"""
 
 class CGroupConfigurator(object):
     """
@@ -55,138 +85,65 @@ class CGroupConfigurator(object):
                 if self._initialized:
                     return
 
-                #
                 # check whether cgroup monitoring is supported on the current distro
-                #
                 self._cgroups_supported = CGroupsApi.cgroups_supported()
                 if not self._cgroups_supported:
                     logger.info("Cgroup monitoring is not supported on {0}", get_distro())
                     return
 
-                #
-                # check systemd
-                #
+                # check that systemd is detected correctly
                 self._cgroups_api = SystemdCgroupsApi()
-
                 if not self._cgroups_api.is_systemd():
-                    message = "systemd was not detected on {0}".format(get_distro())
-                    logger.warn(message)
-                    add_event(op=WALAEventOperation.CGroupsInitialize, is_success=False, message=message, log_event=False)
+                    self.__log_cgroup_warning("systemd was not detected on {0}", get_distro())
                     return
 
-                def log_cgroup_info(format_string, *args):
-                    message = format_string.format(*args)
-                    logger.info(message)
-                    add_event(op=WALAEventOperation.CGroupsInfo, message=message)
-
-                log_cgroup_info("systemd version: {0}", self._cgroups_api.get_systemd_version())
+                self.__log_cgroup_info("systemd version: {0}", self._cgroups_api.get_systemd_version())
 
-                self.__collect_azure_unit_telemetry()
-                self.__collect_agent_unit_files_telemetry()
+                # This is temporarily disabled while we analyze telemetry. Likely it will be removed.
+                # self.__collect_azure_unit_telemetry()
+                # self.__collect_agent_unit_files_telemetry()
 
-                #
-                # Older versions of the daemon (2.2.31-2.2.40) wrote their PID to /sys/fs/cgroup/{cpu,memory}/WALinuxAgent/WALinuxAgent.  When running
-                # under systemd this could produce invalid resource usage data. Do not enable cgroups under this condition.
-                #
-                legacy_cgroups = self._cgroups_api.cleanup_legacy_cgroups()
-
-                if legacy_cgroups > 0:
-                    log_cgroup_info("The daemon's PID was added to a legacy cgroup; will not monitor resource usage.")
+                if not self.__check_no_legacy_cgroups():
                     return
 
-                #
-                # check v1 controllers
-                #
-                cpu_controller_root, memory_controller_root = self._cgroups_api.get_cgroup_mount_points()
+                cpu_controller_root, memory_controller_root = self.__get_cgroup_controllers()
 
-                if cpu_controller_root is not None:
-                    logger.info("The CPU cgroup controller is mounted at {0}", cpu_controller_root)
-                else:
-                    log_cgroup_info("The CPU cgroup controller is not mounted")
+                agent_slice = self.__ensure_azure_slices_exist()
 
-                if memory_controller_root is not None:
-                    logger.info("The memory cgroup controller is mounted at {0}", memory_controller_root)
-                else:
-                    log_cgroup_info("The memory cgroup controller is not mounted")
-
-                #
-                # check v2 controllers
-                #
-                cgroup2_mount_point, cgroup2_controllers = self._cgroups_api.get_cgroup2_controllers()
-                if cgroup2_mount_point is not None:
-                    log_cgroup_info("cgroups v2 mounted at {0}.  Controllers: [{1}]", cgroup2_mount_point, cgroup2_controllers)
-
-                #
-                # check the cgroups for the agent
-                #
-                agent_unit_name = self._cgroups_api.get_agent_unit_name()
-                cpu_cgroup_relative_path, memory_cgroup_relative_path = self._cgroups_api.get_process_cgroup_relative_paths("self")
-                expected_relative_path = os.path.join('system.slice', agent_unit_name)
-                if cpu_cgroup_relative_path is None:
-                    log_cgroup_info("The agent's process is not within a CPU cgroup")
-                else:
-                    if cpu_cgroup_relative_path != expected_relative_path:
-                        log_cgroup_info("The Agent is not in the expected cgroup; will not enable cgroup monitoring. CPU relative path:[{0}] Expected:[{1}]", cpu_cgroup_relative_path, expected_relative_path)
-                        return
-                    cpu_accounting = self._cgroups_api.get_unit_property(agent_unit_name, "CPUAccounting")
-                    log_cgroup_info('CPUAccounting: {0}', cpu_accounting)
-
-                if memory_cgroup_relative_path is None:
-                    log_cgroup_info("The agent's process is not within a memory cgroup")
-                else:
-                    if memory_cgroup_relative_path != expected_relative_path:
-                        log_cgroup_info("The Agent is not in the expected cgroup; will not enable cgroup monitoring. Memory relative path:[{0}] Expected:[{1}]", memory_cgroup_relative_path, expected_relative_path)
-                        return
-                    memory_accounting = self._cgroups_api.get_unit_property(agent_unit_name, "MemoryAccounting")
-                    log_cgroup_info('MemoryAccounting: {0}', memory_accounting)
-
-                #
-                # All good, enable cgroups and start monitoring the agent
-                #
-                if cpu_controller_root is None or cpu_cgroup_relative_path is None:
-                    logger.info("Will not track CPU for the agent's cgroup")
-                else:
-                    self._agent_cpu_cgroup_path = os.path.join(cpu_controller_root, cpu_cgroup_relative_path)
-                    log_cgroup_info("Agent CPU cgroup: {0}", self._agent_cpu_cgroup_path)
-                    CGroupsTelemetry.track_cgroup(CpuCgroup(agent_unit_name, self._agent_cpu_cgroup_path))
+                self._agent_cpu_cgroup_path, self._agent_memory_cgroup_path = self.__get_agent_cgroups(agent_slice, cpu_controller_root, memory_controller_root)
 
-                if memory_controller_root is None or memory_cgroup_relative_path is None:
-                    logger.info("Will not track memory for the agent's cgroup")
-                else:
-                    self._agent_memory_cgroup_path = os.path.join(memory_controller_root, memory_cgroup_relative_path)
-                    log_cgroup_info("Agent Memory cgroup: {0}", self._agent_memory_cgroup_path)
-                    CGroupsTelemetry.track_cgroup(MemoryCgroup(agent_unit_name, self._agent_memory_cgroup_path))
+                agent_service_name = self._cgroups_api.get_agent_unit_name()
+                if self._agent_cpu_cgroup_path is not None:
+                    self.__log_cgroup_info("Agent CPU cgroup: {0}", self._agent_cpu_cgroup_path)
+                    CGroupsTelemetry.track_cgroup(CpuCgroup(agent_service_name, self._agent_cpu_cgroup_path))
+
+                if self._agent_memory_cgroup_path is not None:
+                    self.__log_cgroup_info("Agent Memory cgroup: {0}", self._agent_memory_cgroup_path)
+                    CGroupsTelemetry.track_cgroup(MemoryCgroup(agent_service_name, self._agent_memory_cgroup_path))
 
                 if self._agent_cpu_cgroup_path is not None or self._agent_memory_cgroup_path is not None:
                     self._cgroups_enabled = True
 
-                log_cgroup_info('Cgroups enabled: {0}', self._cgroups_enabled)
+                self.__log_cgroup_info('Cgroups enabled: {0}', self._cgroups_enabled)
 
             except Exception as exception:
-                message = "Error initializing cgroups: {0}".format(ustr(exception))
-                logger.warn(message)
-                add_event(op=WALAEventOperation.CGroupsInitialize, is_success=False, message=message, log_event=False)
+                self.__log_cgroup_warning("Error initializing cgroups: {0}", ustr(exception))
             finally:
                 self._initialized = True
 
-        def enabled(self):
-            return self._cgroups_enabled
-
-        def resource_limits_enforced(self):
-            return False
-
-        def enable(self):
-            if not self._cgroups_supported:
-                raise CGroupsException("Attempted to enable cgroups, but they are not supported on the current platform")
-
-            self._cgroups_enabled = True
-
-        def disable(self):
-            self._cgroups_enabled = False
-            CGroupsTelemetry.reset()
+        @staticmethod
+        def __log_cgroup_info(format_string, *args):
+            message = format_string.format(*args)
+            logger.info(message)
+            add_event(op=WALAEventOperation.CGroupsInfo, message=message)
 
         @staticmethod
-        def __collect_azure_unit_telemetry():
+        def __log_cgroup_warning(format_string, *args):
+            message = format_string.format(*args)
+            logger.info(message)  # log as INFO for now, in the future it should be logged as WARNING
+            add_event(op=WALAEventOperation.CGroupsInfo, message=message, is_success=False, log_event=False)
+
+        def __collect_azure_unit_telemetry(self):
             azure_units = []
 
             try:
@@ -196,22 +153,16 @@ class CGroupConfigurator(object):
                     if match is not None:
                         azure_units.append((match.group(1), line))
             except shellutil.CommandError as command_error:
-                message = "Failed to list systemd units: {0}".format(ustr(command_error))
-                logger.info(message)
-                add_event(op=WALAEventOperation.CGroupsInitialize, is_success=False, message=message, log_event=False)
+                self.__log_cgroup_warning("Failed to list systemd units: {0}", ustr(command_error))
 
             for unit_name, unit_description in azure_units:
                 unit_slice = "Unknown"
                 try:
                     unit_slice = SystemdCgroupsApi.get_unit_property(unit_name, "Slice")
                 except Exception as exception:
-                    message = "Failed to query Slice for {0}: {1}".format(unit_name, ustr(exception))
-                    logger.info(message)
-                    add_event(op=WALAEventOperation.CGroupsInitialize, is_success=False, message=message, log_event=False)
+                    self.__log_cgroup_warning("Failed to query Slice for {0}: {1}", unit_name, ustr(exception))
 
-                message = "Found an Azure unit under slice {0}: {1}".format(unit_slice, unit_description)
-                logger.info(message)
-                add_event(op=WALAEventOperation.CGroupsInitialize, message=message)
+                self.__log_cgroup_info("Found an Azure unit under slice {0}: {1}", unit_slice, unit_description)
 
             if len(azure_units) == 0:
                 try:
@@ -219,14 +170,12 @@ class CGroupConfigurator(object):
                     for line in cgroups.split('\n'):
                         if re.match(r'[^\x00-\xff]+azure\.slice\s*', line, re.UNICODE):
                             logger.info(ustr("Found a cgroup for azure.slice\n{0}").format(cgroups))
-                            add_event(op=WALAEventOperation.CGroupsInitialize, message="Found a cgroup for azure.slice")
+                            # Don't add the output of systemd-cgls to the telemetry, since currently it does not support Unicode
+                            add_event(op=WALAEventOperation.CGroupsInfo, message="Found a cgroup for azure.slice")
                 except shellutil.CommandError as command_error:
-                    message = "Failed to list systemd units: {0}".format(ustr(command_error))
-                    logger.info(message)
-                    add_event(op=WALAEventOperation.CGroupsInitialize, is_success=False, message=message, log_event=False)
+                    self.__log_cgroup_warning("Failed to list systemd units: {0}", ustr(command_error))
 
-        @staticmethod
-        def __collect_agent_unit_files_telemetry():
+        def __collect_agent_unit_files_telemetry(self):
             agent_unit_files = []
             agent_service_name = get_osutil().get_service_name()
             try:
@@ -234,79 +183,212 @@ class CGroupConfigurator(object):
                 if fragment_path != "/lib/systemd/system/{0}.service".format(agent_service_name):
                     agent_unit_files.append(fragment_path)
             except Exception as exception:
-                message = "Failed to query the agent's FragmentPath: {0}".format(ustr(exception))
-                logger.info(message)
-                add_event(op=WALAEventOperation.CGroupsInitialize, is_success=False, message=message, log_event=False)
+                self.__log_cgroup_warning("Failed to query the agent's FragmentPath: {0}", ustr(exception))
 
             try:
                 drop_in_paths = SystemdCgroupsApi.get_unit_property(agent_service_name, "DropInPaths")
                 for path in drop_in_paths.split():
                     agent_unit_files.append(path)
             except Exception as exception:
-                message = "Failed to query the agent's DropInPaths: {0}".format(ustr(exception))
-                logger.info(message)
-                add_event(op=WALAEventOperation.CGroupsInitialize, is_success=False, message=message, log_event=False)
+                self.__log_cgroup_warning("Failed to query the agent's DropInPaths: {0}", ustr(exception))
 
             for unit_file in agent_unit_files:
                 try:
                     with open(unit_file, "r") as file_object:
-                        message = "Found a custom unit file for the agent: {0}\n{1}".format(unit_file, file_object.read())
-                        logger.info(message)
-                        add_event(op=WALAEventOperation.CGroupsInitialize, message=message)
+                        self.__log_cgroup_info("Found a custom unit file for the agent: {0}\n{1}", unit_file, file_object.read())
                 except Exception as exception:
-                    message = "Can't read {0}: {1}".format(unit_file, ustr(exception))
-                    logger.info(message)
-                    add_event(op=WALAEventOperation.CGroupsInitialize, message=message)
+                    self.__log_cgroup_warning("Can't read {0}: {1}", unit_file, ustr(exception))
 
-        def create_slices(self):
-            if not self.enabled():
-                return
-
-            # Create root slices for agent and agent and extensions for systemd-managed distros.
-            # The hierarchy is as follows:
-            # ├─user.slice
-            # ...
-            # ├─system.slice
-            # ...
-            # └─azure.slice
-            #   └─azure-vmextensions.slice
+        def __check_no_legacy_cgroups(self):
+            """
+            Older versions of the daemon (2.2.31-2.2.40) wrote their PID to /sys/fs/cgroup/{cpu,memory}/WALinuxAgent/WALinuxAgent. When running
+            under systemd this could produce invalid resource usage data. Cgroups should not be enabled under this condition.
+            """
+            legacy_cgroups = self._cgroups_api.cleanup_legacy_cgroups()
+            if legacy_cgroups > 0:
+                self.__log_cgroup_warning("The daemon's PID was added to a legacy cgroup; will not monitor resource usage.")
+                return False
+            return True
 
-            # Both methods will log to local log and emit telemetry.
-            # The slices will be created if they don't previously exist.
+        def __get_cgroup_controllers(self):
+            #
+            # check v1 controllers
+            #
+            cpu_controller_root, memory_controller_root = self._cgroups_api.get_cgroup_mount_points()
 
-            if not os.path.exists(SystemdCgroupsApi.get_azure_slice()):
-                self.create_azure_slice()
+            if cpu_controller_root is not None:
+                logger.info("The CPU cgroup controller is mounted at {0}", cpu_controller_root)
+            else:
+                self.__log_cgroup_warning("The CPU cgroup controller is not mounted")
 
-            if not os.path.exists(SystemdCgroupsApi.get_extensions_slice()):
-                self.create_extensions_slice()
+            if memory_controller_root is not None:
+                logger.info("The memory cgroup controller is mounted at {0}", memory_controller_root)
+            else:
+                self.__log_cgroup_warning("The memory cgroup controller is not mounted")
 
-        def create_azure_slice(self):
-            """"
-            Creates the slice for the VM Agent and extensions.
-            """
-            if not self.enabled():
-                return
+            #
+            # check v2 controllers
+            #
+            cgroup2_mount_point, cgroup2_controllers = self._cgroups_api.get_cgroup2_controllers()
+            if cgroup2_mount_point is not None:
+                self.__log_cgroup_info("cgroups v2 mounted at {0}.  Controllers: [{1}]", cgroup2_mount_point, cgroup2_controllers)
 
-            try:
-                self._cgroups_api.create_azure_slice()
-            except Exception as exception:
-                error_message = "Failed to create the azure slice. Error: {0}".format(ustr(exception))
-                logger.warn(error_message)
-                add_event(op=WALAEventOperation.CGroupsInitialize, message=error_message)
+            return cpu_controller_root, memory_controller_root
 
-        def create_extensions_slice(self):
+        def __ensure_azure_slices_exist(self):
             """
-            Creates the slice that includes the cgroups for all extensions
+            The agent creates "azure.slice" for use by extensions and the agent. The agent runs under "azure.slice" directly and each
+            extension runs under its own slice ("Microsoft.CPlat.Extension.slice" in the example below). All the slices for
+            extensions are grouped under "vmextensions.slice".
+
+            Example:  -.slice
+                      ├─user.slice
+                      ├─system.slice
+                      └─azure.slice
+                        ├─walinuxagent.service
+                        │ ├─5759 /usr/bin/python3 -u /usr/sbin/waagent -daemon
+                        │ └─5764 python3 -u bin/WALinuxAgent-2.2.53-py2.7.egg -run-exthandlers
+                        └─azure-vmextensions.slice
+                          └─Microsoft.CPlat.Extension.slice
+                              └─5894 /usr/bin/python3 /var/lib/waagent/Microsoft.CPlat.Extension-1.0.0.0/enable.py
+
+            This method ensures that the "azure" and "vmextensions" slices are created. Setup should create those slices
+            under /lib/systemd/system; but if they do not exist, __ensure_azure_slices_exist will create them.
+            It also creates drop-in files to set the agent's slice and CPU accounting properties if they have not been
+            set up in the agent's unit file.
+            Lastly, the method also cleans up unit files left over from previous versions of the agent.
+
+            Returns the slice under which the agent should currently be running.
             """
-            if not self.enabled():
-                return
 
+            # Older agents used to create this slice, but it was never used. Cleanup the file.
+            self._cleanup_unit_file("/etc/systemd/system/system-walinuxagent.extensions.slice")
+
+            azure_slice = os.path.join("/lib/systemd/system", _AZURE_SLICE)
+            vmextensions_slice = os.path.join("/lib/systemd/system", _VMEXTENSIONS_SLICE)
+            agent_unit_file = "/lib/systemd/system/{0}".format(self._cgroups_api.get_agent_unit_name())
+            agent_drop_in_file_slice = "/lib/systemd/system/{0}.d/{1}".format(self._cgroups_api.get_agent_unit_name(), _AGENT_DROP_IN_FILE_SLICE)
+            agent_drop_in_file_cpu_accounting = "/lib/systemd/system/{0}.d/{1}".format(self._cgroups_api.get_agent_unit_name(), _AGENT_DROP_IN_FILE_CPU_ACCOUNTING)
+
+            files_to_create = []
+            return_azure_slice = False
+
+            if os.path.exists(azure_slice):
+                return_azure_slice = True
+            else:
+                files_to_create.append((azure_slice, _AZURE_SLICE_CONTENTS))
+
+            if not os.path.exists(vmextensions_slice):
+                files_to_create.append((vmextensions_slice, _VMEXTENSIONS_SLICE_CONTENTS))
+
+            if fileutil.findstr_in_file(agent_unit_file, "Slice=azure.slice"):
+                self._cleanup_unit_file(agent_drop_in_file_slice)
+            else:
+                if not os.path.exists(agent_drop_in_file_slice):
+                    files_to_create.append((agent_drop_in_file_slice, _AGENT_DROP_IN_FILE_SLICE_CONTENTS))
+
+            if fileutil.findstr_in_file(agent_unit_file, "CPUAccounting=yes"):
+                self._cleanup_unit_file(agent_drop_in_file_cpu_accounting)
+            else:
+                if not os.path.exists(agent_drop_in_file_cpu_accounting):
+                    files_to_create.append((agent_drop_in_file_cpu_accounting, _AGENT_DROP_IN_FILE_CPU_ACCOUNTING_CONTENTS))
+
+            if len(files_to_create) > 0:
+                try:
+                    for path, contents in files_to_create:
+                        self._create_unit_file(path, contents)
+
+                    # reload the systemd configuration, but the new slice will not be used until the agent's service restarts
+                    try:
+                        logger.info("Executing systemctl daemon-reload...")
+                        shellutil.run_command(["systemctl", "daemon-reload"])
+                    except Exception as exception:
+                        self.__log_cgroup_warning("daemon-reload failed: {0}", ustr(exception))
+                except Exception:
+                    # the exception is already logged in the above functions
+                    for unit_file in files_to_create:
+                        self._cleanup_unit_file(unit_file)
+
+            return _AZURE_SLICE if return_azure_slice else "system.slice"
+
+        def _create_unit_file(self, path, contents):
             try:
-                self._cgroups_api.create_extensions_slice()
+                parent, _ = os.path.split(path)
+                if not os.path.exists(parent):
+                    fileutil.mkdir(parent, mode=0o755)
+                fileutil.write_file(path, contents)
+                self.__log_cgroup_info("Created {0}", path)
             except Exception as exception:
-                error_message = "Failed to create slice for VM extensions. Error: {0}".format(ustr(exception))
-                logger.warn(error_message)
-                add_event(op=WALAEventOperation.CGroupsInitialize, message=error_message)
+                self.__log_cgroup_warning("Failed to create {0} - {1}", path, ustr(exception))
+                raise
+
+        def _cleanup_unit_file(self, path):
+            if os.path.exists(path):
+                try:
+                    os.remove(path)
+                    self.__log_cgroup_info("Removed {0}", path)
+                except Exception as exception:
+                    self.__log_cgroup_warning("Failed to remove {0}: {1}", path, ustr(exception))
+
+        def __get_agent_cgroups(self, agent_slice, cpu_controller_root, memory_controller_root):
+            agent_service_name = self._cgroups_api.get_agent_unit_name()
+
+            expected_relative_path = os.path.join(agent_slice, agent_service_name)
+            cpu_cgroup_relative_path, memory_cgroup_relative_path = self._cgroups_api.get_process_cgroup_relative_paths("self")
+
+            if cpu_cgroup_relative_path is None:
+                self.__log_cgroup_warning("The agent's process is not within a CPU cgroup")
+            else:
+                if cpu_cgroup_relative_path == expected_relative_path:
+                    cpu_accounting = self._cgroups_api.get_unit_property(agent_service_name, "CPUAccounting")
+                    self.__log_cgroup_info('CPUAccounting: {0}', cpu_accounting)
+                else:
+                    cpu_cgroup_relative_path = None  # Set the path to None to prevent monitoring
+                    self.__log_cgroup_warning(
+                        "The Agent is not in the expected CPU cgroup; will not enable monitoring. Cgroup:[{0}] Expected:[{1}]",
+                        cpu_cgroup_relative_path,
+                        expected_relative_path)
+
+            if memory_cgroup_relative_path is None:
+                self.__log_cgroup_warning("The agent's process is not within a memory cgroup")
+            else:
+                if memory_cgroup_relative_path == expected_relative_path:
+                    memory_accounting = self._cgroups_api.get_unit_property(agent_service_name, "MemoryAccounting")
+                    self.__log_cgroup_info('MemoryAccounting: {0}', memory_accounting)
+                else:
+                    memory_cgroup_relative_path = None  # Set the path to None to prevent monitoring
+                    self.__log_cgroup_warning(
+                        "The Agent is not in the expected memory cgroup; will not enable monitoring. CGroup:[{0}] Expected:[{1}]",
+                        memory_cgroup_relative_path,
+                        expected_relative_path)
+
+            if cpu_controller_root is not None and cpu_cgroup_relative_path is not None:
+                agent_cpu_cgroup_path = os.path.join(cpu_controller_root, cpu_cgroup_relative_path)
+            else:
+                agent_cpu_cgroup_path = None
+
+            if memory_controller_root is not None and memory_cgroup_relative_path is not None:
+                agent_memory_cgroup_path = os.path.join(memory_controller_root, memory_cgroup_relative_path)
+            else:
+                agent_memory_cgroup_path = None
+
+            return agent_cpu_cgroup_path, agent_memory_cgroup_path
+
+        def enabled(self):
+            return self._cgroups_enabled
+
+        def resource_limits_enforced(self):
+            return False
+
+        def enable(self):
+            if not self._cgroups_supported:
+                raise CGroupsException("Attempted to enable cgroups, but they are not supported on the current platform")
+
+            self._cgroups_enabled = True
+
+        def disable(self):
+            self._cgroups_enabled = False
+            CGroupsTelemetry.reset()
 
         def check_processes_in_agent_cgroup(self):
             """
diff --git a/azurelinuxagent/common/event.py b/azurelinuxagent/common/event.py
index c03ddd27..c8387be5 100644
--- a/azurelinuxagent/common/event.py
+++ b/azurelinuxagent/common/event.py
@@ -71,10 +71,8 @@ class WALAEventOperation:  # pylint: disable=no-init
     AgentEnabled = "AgentEnabled"
     ArtifactsProfileBlob = "ArtifactsProfileBlob"
     CGroupsCleanUp = "CGroupsCleanUp"
-    CGroupsDebug = "CGroupsDebug"
     CGroupsDisabled = "CGroupsDisabled"
     CGroupsInfo = "CGroupsInfo"
-    CGroupsInitialize = "CGroupsInitialize"
     CGroupsLimitsCrossed = "CGroupsLimitsCrossed"
     CollectEventErrors = "CollectEventErrors"
     CollectEventUnicodeErrors = "CollectEventUnicodeErrors"
diff --git a/azurelinuxagent/ga/update.py b/azurelinuxagent/ga/update.py
index 1146f82c..2c813fb3 100644
--- a/azurelinuxagent/ga/update.py
+++ b/azurelinuxagent/ga/update.py
@@ -526,7 +526,6 @@ class UpdateHandler(object):
     def _ensure_cgroups_initialized(self):
         configurator = CGroupConfigurator.get_instance()
         configurator.initialize()
-        configurator.create_slices()
 
     def _evaluate_agent_health(self, latest_agent):
         """
diff --git a/init/ubuntu/azure-vmextensions.slice b/init/ubuntu/azure-vmextensions.slice
index f614e608..87dd84b1 100644
--- a/init/ubuntu/azure-vmextensions.slice
+++ b/init/ubuntu/azure-vmextensions.slice
@@ -1,2 +1,6 @@
 [Unit]
 Description=Slice for Azure VM Extensions
+DefaultDependencies=no
+Before=slices.target
+[Slice]
+CPUAccounting=yes
diff --git a/init/ubuntu/azure.slice b/init/ubuntu/azure.slice
index 674a9a51..6310d192 100644
--- a/init/ubuntu/azure.slice
+++ b/init/ubuntu/azure.slice
@@ -1,2 +1,4 @@
 [Unit]
 Description=Slice for Azure VM Agent and Extensions
+DefaultDependencies=no
+Before=slices.target
diff --git a/init/ubuntu/walinuxagent.service b/init/ubuntu/walinuxagent.service
index 3cf47c5b..f3887c5b 100644
--- a/init/ubuntu/walinuxagent.service
+++ b/init/ubuntu/walinuxagent.service
@@ -17,6 +17,8 @@ ConditionPathExists=/etc/waagent.conf
 Type=simple
 ExecStart=/usr/bin/python3 -u /usr/sbin/waagent -daemon
 Restart=always
+Slice=azure.slice
+CPUAccounting=yes
 
 [Install]
 WantedBy=multi-user.target
diff --git a/setup.py b/setup.py
index ae287661..c258e4b8 100755
--- a/setup.py
+++ b/setup.py
@@ -147,7 +147,11 @@ def get_data_files(name, version, fullname):  # pylint: disable=R0912
         else:
             # Ubuntu15.04+ uses systemd
             set_systemd_files(data_files, dest=systemd_dir_path,
-                              src=["init/ubuntu/walinuxagent.service"])
+                              src=[
+                                  "init/ubuntu/walinuxagent.service",
+                                  "init/ubuntu/azure.slice",
+                                  "init/ubuntu/azure-vmextensions.slice"
+                              ])
     elif name == 'suse' or name == 'opensuse':  # pylint: disable=R1714
         set_conf_files(data_files, src=["config/suse/waagent.conf"])
         set_logrotate_files(data_files)


Test patch:
diff --git a/tests/common/mock_cgroup_commands.py b/tests/common/mock_cgroup_commands.py
index a7622680..8bef9875 100644
--- a/tests/common/mock_cgroup_commands.py
+++ b/tests/common/mock_cgroup_commands.py
@@ -19,16 +19,13 @@ import contextlib
 import os
 import re
 import subprocess
+import sys
 
+from azurelinuxagent.common.osutil import get_osutil
 from azurelinuxagent.common.utils import fileutil
 from tests.tools import patch, data_dir
 
-#
-# Default values for the mocked commands.
-#
-# The output comes from an Ubuntu 18 system
-#
-__DEFAULT_COMMANDS = [
+__MOCKED_COMMANDS = [
     (r"^systemctl --version$",
 '''systemd 237
 +PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid
@@ -60,6 +57,8 @@ cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blki
 '''MemoryAccounting=no
 '''),
 
+    (r"^systemctl daemon-reload", ""),
+
     (r"^systemd-run --unit=([^\s]+) --scope ([^\s]+)",
 ''' 
 Running scope as unit: TEST_UNIT.scope
@@ -68,25 +67,51 @@ Thu 28 May 2020 07:25:55 AM PDT
 
 ]
 
-__DEFAULT_FILES = [
+__service_file = "{0}.service".format(get_osutil().get_service_name())
+
+__MOCKED_FILES = [
     (r"^/proc/self/cgroup$", os.path.join(data_dir, 'cgroups', 'proc_self_cgroup')),
     (r"^/proc/[0-9]+/cgroup$", os.path.join(data_dir, 'cgroups', 'proc_pid_cgroup')),
     (r"^/sys/fs/cgroup/unified/cgroup.controllers$", os.path.join(data_dir, 'cgroups', 'sys_fs_cgroup_unified_cgroup.controllers')),
+    (r"^/lib/systemd/system/{0}$".format(__service_file), os.path.join(data_dir, 'init', __service_file + "_system-slice")),
 ]
 
+__MOCKED_PATHS = [
+    r"^(/lib/systemd/system)",
+    r"^(/etc/systemd/system)"
+]
 
+# W0212: Access to a protected member __commands of a client class (protected-access) - Disabled: patcher.__commands is added
+# only for debugging purposes and should not be public (hence it is marked as private).
+# pylint: disable=protected-access
 @contextlib.contextmanager
-def mock_cgroup_commands():
+def mock_cgroup_commands(tmp_dir):
+    """
+    Creates a set of mocks useful for tests related to cgroups (currently it only provides support for systemd platforms).
+
+    The function mocks Popen, fileutil.mkdir, os.path.exists and the open builtin function.
+
+    The mock for Popen looks for a match in __MOCKED_COMMANDS and, if found, forwards the call to the the echo command
+    to produce the output for the matching item. Otherwise it forwards the call to the original Popen function.
+
+    The mocks for the other functions first look for a match in __MOCKED_FILES and, if found, map the file to the
+    corresponding path in the matching item. If there is no match, then it checks if the file is under one of the paths
+    in  __MOCKED_PATHS and map the path to the given tmp_dir (e.g. "/lib/systemd/system" becomes
+    "<tmp_dir>/lib/systemd/system".) If there no matches, the path is not changed. Once this mapping has completed
+    the mocks invoke the corresponding original function.
+
+    Matches are done using regular expressions; the regular expressions in __MOCKED_PATHS must create group 0 to indicate
+    the section of the path that needs to be mapped (i.e. use parenthesis around the section that needs to be mapped.)
+
+    The command output used in __MOCKED_COMMANDS come from an Ubuntu 18 system.
+    """
     original_popen = subprocess.Popen
-    original_read_file = fileutil.read_file
-    original_write_file = fileutil.write_file
+    original_mkdir = fileutil.mkdir
     original_path_exists = os.path.exists
+    original_open = open
 
-    def add_file(pattern, file_path):
-        patcher.files.insert(0, (pattern, file_path))
-
-    def add_command(pattern, output):
-        patcher.commands.insert(0, (pattern, output))
+    def add_command_mock(pattern, output):
+        patcher.__commands.insert(0, (pattern, output))
 
     def mock_popen(command, *args, **kwargs):
         if isinstance(command, list):
@@ -94,44 +119,46 @@ def mock_cgroup_commands():
         else:
             command_string = command
 
-        for cmd in patcher.commands:
+        for cmd in patcher.__commands:
             match = re.match(cmd[0], command_string)
             if match is not None:
                 command = ["echo", cmd[1]]
                 break
 
         return original_popen(command, *args, **kwargs)
-    
-    def mock_read_file(filepath, **kwargs):
-        for item in patcher.files:
-            match = re.match(item[0], filepath)
-            if match is not None:
-                filepath = item[1]
-        return original_read_file(filepath, **kwargs)
 
-    def mock_write_file(filepath, content, **kwargs):
-        for item in patcher.files:
-            match = re.match(item[0], filepath)
+    def get_mapped_path(path):
+        for item in __MOCKED_FILES:
+            match = re.match(item[0], path)
             if match is not None:
-                filepath = item[1]
-        return original_write_file(filepath, content, **kwargs)
+                return item[1]
+
+        for item in __MOCKED_PATHS:
+            mapped = re.sub(item, r"{0}\1".format(tmp_dir), path)
+            if mapped != path:
+                mapped_parent = os.path.split(mapped)[0]
+                if not original_path_exists(mapped_parent):
+                    os.makedirs(mapped_parent)
+                return mapped
+        return path
+
+    def mock_mkdir(path, *args, **kwargs):
+        return original_mkdir(get_mapped_path(path), *args, **kwargs)
+
+    def mock_open(path, *args, **kwargs):
+        return original_open(get_mapped_path(path), *args, **kwargs)
 
     def mock_path_exists(path):
-        for item in patcher.files:
-            match = re.match(item[0], path)
-            if match is not None:
-                return True
-        return original_path_exists(path)
+        return original_path_exists(get_mapped_path(path))
 
+    builtin_popen = "__builtin__.open" if sys.version_info[0] == 2 else "builtins.open"
     with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen) as patcher:
-        with patch("azurelinuxagent.common.cgroupapi.os.path.exists", side_effect=mock_path_exists):
-            with patch("azurelinuxagent.common.cgroupapi.fileutil.read_file", side_effect=mock_read_file):
-                with patch("azurelinuxagent.common.cgroupapi.fileutil.write_file", side_effect=mock_write_file):
+        with patch("azurelinuxagent.common.cgroupconfigurator.fileutil.mkdir", side_effect=mock_mkdir):
+            with patch("azurelinuxagent.common.cgroupapi.os.path.exists", side_effect=mock_path_exists):
+                with patch(builtin_popen, side_effect=mock_open):
                     with patch('azurelinuxagent.common.cgroupapi.CGroupsApi.cgroups_supported', return_value=True):
                         with patch('azurelinuxagent.common.cgroupapi.CGroupsApi.is_systemd', return_value=True):
-                            patcher.commands = __DEFAULT_COMMANDS[:]
-                            patcher.files = __DEFAULT_FILES[:]
-                            patcher.add_file = add_file
-                            patcher.add_command = add_command
+                            patcher.__commands = __MOCKED_COMMANDS[:]
+                            patcher.add_command_mock = add_command_mock
+                            patcher.get_mapped_path = get_mapped_path
                             yield patcher
-
diff --git a/tests/common/test_cgroupapi.py b/tests/common/test_cgroupapi.py
index 16d1b7d6..4fd72f13 100644
--- a/tests/common/test_cgroupapi.py
+++ b/tests/common/test_cgroupapi.py
@@ -108,25 +108,25 @@ class CGroupsApiTestCase(_MockedFileSystemTestCase):
 @skip_if_predicate_false(is_systemd_present, "Systemd cgroups API doesn't manage cgroups on systems not using systemd.")
 class SystemdCgroupsApiTestCase(AgentTestCase):
     def test_get_systemd_version_should_return_a_version_number(self):
-        with mock_cgroup_commands():
+        with mock_cgroup_commands(self.tmp_dir):
             version_info = SystemdCgroupsApi.get_systemd_version()
             found = re.search(r"systemd \d+", version_info) is not None
             self.assertTrue(found, "Could not determine the systemd version: {0}".format(version_info))
 
     def test_get_cpu_and_memory_mount_points_should_return_the_cgroup_mount_points(self):
-        with mock_cgroup_commands():
+        with mock_cgroup_commands(self.tmp_dir):
             cpu, memory = SystemdCgroupsApi().get_cgroup_mount_points()
             self.assertEqual(cpu, '/sys/fs/cgroup/cpu,cpuacct', "The mount point for the CPU controller is incorrect")
             self.assertEqual(memory, '/sys/fs/cgroup/memory', "The mount point for the memory controller is incorrect")
 
     def test_get_cpu_and_memory_cgroup_relative_paths_for_process_should_return_the_cgroup_relative_paths(self):
-        with mock_cgroup_commands():
+        with mock_cgroup_commands(self.tmp_dir):
             cpu, memory = SystemdCgroupsApi.get_process_cgroup_relative_paths('self')
             self.assertEqual(cpu, "system.slice/walinuxagent.service", "The relative path for the CPU cgroup is incorrect")
             self.assertEqual(memory, "system.slice/walinuxagent.service", "The relative memory for the CPU cgroup is incorrect")
 
     def test_get_cgroup2_controllers_should_return_the_v2_cgroup_controllers(self):
-        with mock_cgroup_commands():
+        with mock_cgroup_commands(self.tmp_dir):
             mount_point, controllers = SystemdCgroupsApi.get_cgroup2_controllers()
 
             self.assertEqual(mount_point, "/sys/fs/cgroup/unified", "Invalid mount point for V2 cgroups")
@@ -134,42 +134,11 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
             self.assertIn("memory", controllers, "The memory controller is not in the list of V2 controllers")
 
     def test_get_unit_property_should_return_the_value_of_the_given_property(self):
-        with mock_cgroup_commands():
+        with mock_cgroup_commands(self.tmp_dir):
             cpu_accounting = SystemdCgroupsApi.get_unit_property("walinuxagent.service", "CPUAccounting")
 
             self.assertEqual(cpu_accounting, "no", "Property {0} of {1} is incorrect".format("CPUAccounting", "walinuxagent.service"))
 
-    def test_get_extensions_slice_root_name_should_return_the_root_slice_for_extensions(self):
-        root_slice_name = SystemdCgroupsApi()._get_extensions_root_slice_name()  # pylint: disable=protected-access
-        self.assertEqual(root_slice_name, "azure-vmextensions.slice")
-
-    def test_get_extension_slice_name_should_return_the_slice_for_the_given_extension(self):
-        extension_name = "Microsoft.Azure.DummyExtension-1.0"
-        extension_slice_name = SystemdCgroupsApi()._get_extension_slice_name(extension_name)  # pylint: disable=protected-access
-        self.assertEqual(extension_slice_name, "azure-vmextensions-Microsoft.Azure.DummyExtension_1.0.slice")
-
-    def test_create_azure_slice_should_create_unit_file(self):
-        azure_slice_path = os.path.join(self.tmp_dir, "azure.slice")
-        self.assertFalse(os.path.exists(azure_slice_path))
-
-        with mock_cgroup_commands() as mocks:
-            # Mock out the actual calls to /etc/systemd
-            mocks.add_file(r"^/etc/systemd/system/azure.slice$", azure_slice_path)
-            SystemdCgroupsApi().create_azure_slice()
-
-        self.assertTrue(os.path.exists(azure_slice_path))
-
-    def test_create_extensions_slice_should_create_unit_file(self):
-        extensions_slice_path = os.path.join(self.tmp_dir, "azure-vmextensions.slice")
-        self.assertFalse(os.path.exists(extensions_slice_path))
-
-        with mock_cgroup_commands() as mocks:
-            # Mock out the actual calls to /etc/systemd
-            mocks.add_file(r"^/etc/systemd/system/azure-vmextensions.slice$", extensions_slice_path)
-            SystemdCgroupsApi().create_extensions_slice()
-
-        self.assertTrue(os.path.exists(extensions_slice_path))
-
     def assert_cgroups_created(self, extension_cgroups):
         self.assertEqual(len(extension_cgroups), 2,
                          'start_extension_command did not return the expected number of cgroups')
@@ -200,7 +169,7 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
                 command = "echo TEST_OUTPUT"
             return original_popen(command, *args, **kwargs)
 
-        with mock_cgroup_commands() as mock_commands:  # pylint: disable=unused-variable
+        with mock_cgroup_commands(self.tmp_dir) as mock_commands:  # pylint: disable=unused-variable
             with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as output_file:
                 with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen) as popen_patch:  # pylint: disable=unused-variable
                     command_output = SystemdCgroupsApi().start_extension_command(
@@ -217,7 +186,7 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
 
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     def test_start_extension_command_should_execute_the_command_in_a_cgroup(self, _):
-        with mock_cgroup_commands():
+        with mock_cgroup_commands(self.tmp_dir):
             SystemdCgroupsApi().start_extension_command(
                 extension_name="Microsoft.Compute.TestExtension-1.2.3",
                 command="test command",
@@ -233,13 +202,10 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
             self.assertTrue(
                 any(cg for cg in tracked if cg.name == 'Microsoft.Compute.TestExtension-1.2.3' and 'cpu' in cg.path),
                 "The extension's CPU is not being tracked")
-            self.assertTrue(
-                any(cg for cg in tracked if cg.name == 'Microsoft.Compute.TestExtension-1.2.3' and 'memory' in cg.path),
-                "The extension's memory is not being tracked")
 
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     def test_start_extension_command_should_use_systemd_to_execute_the_command(self, _):
-        with mock_cgroup_commands():
+        with mock_cgroup_commands(self.tmp_dir):
             with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", wraps=subprocess.Popen) as popen_patch:
                 SystemdCgroupsApi().start_extension_command(
                     extension_name="Microsoft.Compute.TestExtension-1.2.3",
@@ -267,9 +233,8 @@ class SystemdCgroupsApiMockedFileSystemTestCase(_MockedFileSystemTestCase):
         legacy_cpu_cgroup = CGroupsTools.create_legacy_agent_cgroup(self.cgroups_file_system_root, "cpu", '')
         legacy_memory_cgroup = CGroupsTools.create_legacy_agent_cgroup(self.cgroups_file_system_root, "memory", '')
 
-        with patch("azurelinuxagent.common.cgroupapi.add_event") as mock_add_event:  # pylint: disable=unused-variable
-            with patch("azurelinuxagent.common.cgroupapi.get_agent_pid_file_path", return_value=daemon_pid_file):
-                legacy_cgroups = SystemdCgroupsApi().cleanup_legacy_cgroups()
+        with patch("azurelinuxagent.common.cgroupapi.get_agent_pid_file_path", return_value=daemon_pid_file):
+            legacy_cgroups = SystemdCgroupsApi().cleanup_legacy_cgroups()
 
         self.assertEqual(legacy_cgroups, 2, "cleanup_legacy_cgroups() did not find all the expected cgroups")
         self.assertFalse(os.path.exists(legacy_cpu_cgroup), "cleanup_legacy_cgroups() did not remove the CPU legacy cgroup")
diff --git a/tests/common/test_cgroupconfigurator.py b/tests/common/test_cgroupconfigurator.py
index 26b95fac..cec4c2b0 100644
--- a/tests/common/test_cgroupconfigurator.py
+++ b/tests/common/test_cgroupconfigurator.py
@@ -17,6 +17,7 @@
 
 from __future__ import print_function
 
+import contextlib
 import os
 import random
 import re
@@ -33,6 +34,7 @@ from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry
 from azurelinuxagent.common.event import WALAEventOperation
 from azurelinuxagent.common.exception import CGroupsException, ExtensionError, ExtensionErrorCodes
 from azurelinuxagent.common.future import ustr
+from azurelinuxagent.common.osutil import get_osutil
 from azurelinuxagent.common.utils import shellutil
 from tests.common.mock_cgroup_commands import mock_cgroup_commands
 from tests.tools import AgentTestCase, patch, mock_sleep, i_am_root
@@ -46,63 +48,60 @@ class CGroupConfiguratorSystemdTestCase(AgentTestCase):
         CGroupConfigurator._instance = None  # pylint: disable=protected-access
         AgentTestCase.tearDownClass()
 
-    @staticmethod
-    def _get_new_cgroup_configurator_instance(initialize=True, mock_commands=None, mock_files=None):
+    @contextlib.contextmanager
+    def _get_cgroup_configurator(self, initialize=True, command_mocks=None):
         # protected-access<W0212> Disabled: OK to access CGroupConfigurator._instance from unit test for CGroupConfigurator
         CGroupConfigurator._instance = None  # pylint: disable=protected-access
         configurator = CGroupConfigurator.get_instance()
         CGroupsTelemetry.reset()
-        if initialize:
-            with mock_cgroup_commands() as mocks:
-                if mock_files is not None:
-                    for item in mock_files:
-                        mocks.add_file(item[0], item[1])
-                if mock_commands is not None:
-                    for command in mock_commands:
-                        mocks.add_command(command[0], command[1])
+        with mock_cgroup_commands(self.tmp_dir) as mocks:
+            if command_mocks is not None:
+                for command in command_mocks:
+                    mocks.add_command_mock(command[0], command[1])
+            configurator.mocks = mocks
+            if initialize:
                 configurator.initialize()
-        return configurator
+            yield configurator
 
     def test_initialize_should_start_tracking_the_agent_cgroups(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
+            tracked = CGroupsTelemetry._tracked  # pylint: disable=protected-access
 
-        # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
-        tracked = CGroupsTelemetry._tracked  # pylint: disable=protected-access
-
-        self.assertTrue(configurator.enabled(), "Cgroups should be enabled")
-        self.assertTrue(any(cg for cg in tracked if cg.name == 'walinuxagent.service' and 'cpu' in cg.path),
-            "The Agent's CPU is not being tracked. Tracked: {0}".format(tracked))
-        self.assertTrue(any(cg for cg in tracked if cg.name == 'walinuxagent.service' and 'memory' in cg.path),
-            "The Agent's memory is not being tracked. Tracked: {0}".format(tracked))
+            self.assertTrue(configurator.enabled(), "Cgroups should be enabled")
+            self.assertTrue(any(cg for cg in tracked if cg.name == 'walinuxagent.service' and 'cpu' in cg.path),
+                "The Agent's CPU is not being tracked. Tracked: {0}".format(tracked))
+            self.assertTrue(any(cg for cg in tracked if cg.name == 'walinuxagent.service' and 'memory' in cg.path),
+                "The Agent's memory is not being tracked. Tracked: {0}".format(tracked))
 
     def test_initialize_should_start_tracking_other_controllers_when_one_is_not_present(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance(
-            mock_commands=[(r"^mount -t cgroup$",
- '''cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
- cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
- cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
- cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
- cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
- cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
- cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
- cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
- cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
- cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
- cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
- ''')])
-
-        # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
-        tracked = CGroupsTelemetry._tracked  # pylint: disable=protected-access
+        command_mocks = [(
+            r"^mount -t cgroup$",
+'''cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
+cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
+cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
+cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
+cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
+cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
+cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
+cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
+cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
+cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
+cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
+''')]
+        with self._get_cgroup_configurator(command_mocks=command_mocks) as configurator:
+            # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
+            tracked = CGroupsTelemetry._tracked  # pylint: disable=protected-access
 
-        self.assertTrue(configurator.enabled(), "Cgroups should be enabled")
-        self.assertFalse(any(cg for cg in tracked if cg.name == 'walinuxagent.service' and 'cpu' in cg.path),
-            "The Agent's CPU should not be tracked. Tracked: {0}".format(tracked))
-        self.assertTrue(any(cg for cg in tracked if cg.name == 'walinuxagent.service' and 'memory' in cg.path),
-            "The Agent's memory is not being tracked. Tracked: {0}".format(tracked))
+            self.assertTrue(configurator.enabled(), "Cgroups should be enabled")
+            self.assertFalse(any(cg for cg in tracked if cg.name == 'walinuxagent.service' and 'cpu' in cg.path),
+                "The Agent's CPU should not be tracked. Tracked: {0}".format(tracked))
+            self.assertTrue(any(cg for cg in tracked if cg.name == 'walinuxagent.service' and 'memory' in cg.path),
+                "The Agent's memory is not being tracked. Tracked: {0}".format(tracked))
 
     def test_initialize_should_not_enable_cgroups_is_the_cpu_and_memory_controllers_are_not_present(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance(
-            mock_commands=[(r"^mount -t cgroup$",
+        command_mocks = [(
+r"^mount -t cgroup$",
 '''cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
 cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
 cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
@@ -113,130 +112,108 @@ cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,fr
 cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
 cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
 cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
-                            ''')])
-
-        # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
-        tracked = CGroupsTelemetry._tracked  # pylint: disable=protected-access
+''')]
+        with self._get_cgroup_configurator(command_mocks=command_mocks) as configurator:
+            # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
+            tracked = CGroupsTelemetry._tracked  # pylint: disable=protected-access
 
-        self.assertFalse(configurator.enabled(), "Cgroups should not be enabled")
-        self.assertEqual(len(tracked), 0, "No cgroups should be tracked. Tracked: {0}".format(tracked))
+            self.assertFalse(configurator.enabled(), "Cgroups should not be enabled")
+            self.assertEqual(len(tracked), 0, "No cgroups should be tracked. Tracked: {0}".format(tracked))
 
     def test_initialize_should_not_enable_cgroups_when_the_agent_is_not_in_the_system_slice(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance(
-            mock_commands=[(r"^mount -t cgroup$",
-                            '''cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
-                            cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
-                            cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
-                            cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
-                            cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
-                            cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
-                            cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
-                            cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
-                            cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
-                            cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
-                                                        ''')])
-
-        # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
-        tracked = CGroupsTelemetry._tracked  # pylint: disable=protected-access
-
-        self.assertFalse(configurator.enabled(), "Cgroups should not be enabled")
-        self.assertEqual(len(tracked), 0, "No cgroups should be tracked. Tracked: {0}".format(tracked))
+        command_mocks = [(
+r"^mount -t cgroup$",
+'''cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
+cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
+cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
+cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
+cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
+cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
+cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
+cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
+cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
+cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
+''')]
+
+        with self._get_cgroup_configurator(command_mocks=command_mocks) as configurator:
+            # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
+            tracked = CGroupsTelemetry._tracked  # pylint: disable=protected-access
+
+            self.assertFalse(configurator.enabled(), "Cgroups should not be enabled")
+            self.assertEqual(len(tracked), 0, "No cgroups should be tracked. Tracked: {0}".format(tracked))
+
+    def test_initialize_should_create_slice_unit_files_when_they_do_not_exist(self):
+        with self._get_cgroup_configurator() as configurator:
+            # When the unit files do not exist under /lib/systemd/system, initialize() should create them
+            # (note that the mock CGroupConfigurator maps these files to a test location, so we need to use the mapped path)
+            agent_unit_name = get_osutil().get_service_name() + ".service"
+            azure_slice_unit_file = configurator.mocks.get_mapped_path("/lib/systemd/system/azure.slice")
+            extensions_slice_unit_file = configurator.mocks.get_mapped_path("/lib/systemd/system/azure-vmextensions.slice")
+            agent_drop_in_file_slice = configurator.mocks.get_mapped_path("/lib/systemd/system/{0}.d/10-Slice.conf".format(agent_unit_name))
+            agent_drop_in_file_cpu_accounting = configurator.mocks.get_mapped_path("/lib/systemd/system/{0}.d/11-CPUAccounting.conf".format(agent_unit_name))
+
+            self.assertTrue(os.path.exists(azure_slice_unit_file), "{0} was not created".format(azure_slice_unit_file))
+            self.assertTrue(os.path.exists(extensions_slice_unit_file), "{0} was not created".format(extensions_slice_unit_file))
+            self.assertTrue(os.path.exists(agent_drop_in_file_slice), "{0} was not created".format(agent_drop_in_file_slice))
+            self.assertTrue(os.path.exists(agent_drop_in_file_cpu_accounting), "{0} was not created".format(agent_drop_in_file_cpu_accounting))
 
     def test_enable_and_disable_should_change_the_enabled_state_of_cgroups(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            self.assertTrue(configurator.enabled(), "CGroupConfigurator should be enabled by default")
 
-        self.assertTrue(configurator.enabled(), "CGroupConfigurator should be enabled by default")
+            configurator.disable()
+            self.assertFalse(configurator.enabled(), "disable() should disable the CGroupConfigurator")
 
-        configurator.disable()
-        self.assertFalse(configurator.enabled(), "disable() should disable the CGroupConfigurator")
-
-        configurator.enable()
-        self.assertTrue(configurator.enabled(), "enable() should enable the CGroupConfigurator")
+            configurator.enable()
+            self.assertTrue(configurator.enabled(), "enable() should enable the CGroupConfigurator")
 
     def test_enable_should_raise_cgroups_exception_when_cgroups_are_not_supported(self):
-        with patch("azurelinuxagent.common.cgroupapi.CGroupsApi.cgroups_supported", return_value=False):
-            configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance(initialize=False)
-            configurator.initialize()
+        with self._get_cgroup_configurator(initialize=False) as configurator:
+            with patch("azurelinuxagent.common.cgroupapi.CGroupsApi.cgroups_supported", return_value=False):
+                configurator.initialize()
 
-            with self.assertRaises(CGroupsException) as context_manager:
-                configurator.enable()
-            self.assertIn("Attempted to enable cgroups, but they are not supported on the current platform", str(context_manager.exception))
+                with self.assertRaises(CGroupsException) as context_manager:
+                    configurator.enable()
+                self.assertIn("Attempted to enable cgroups, but they are not supported on the current platform", str(context_manager.exception))
 
     def test_disable_should_reset_tracked_cgroups(self):
-        # Start tracking a couple of dummy cgroups
-        CGroupsTelemetry.track_cgroup(CGroup("dummy", "/sys/fs/cgroup/memory/system.slice/dummy.service", "cpu"))
-        CGroupsTelemetry.track_cgroup(CGroup("dummy", "/sys/fs/cgroup/memory/system.slice/dummy.service", "memory"))
-
-        CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance().disable()
-
-        # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
-        self.assertEqual(len(CGroupsTelemetry._tracked), 0)  # pylint: disable=protected-access
-
-    def test_cgroup_operations_should_not_invoke_the_cgroup_api_when_cgroups_are_not_enabled(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
-        configurator.disable()
-
-        # List of operations to test, and the functions to mock used in order to do verifications
-        operations = [
-            [configurator.create_extensions_slice, "azurelinuxagent.common.cgroupapi.SystemdCgroupsApi.create_extensions_slice"],
-        ]
-
-        for operation in operations:
-            with patch(operation[1]) as mock_cgroup_api_operation:
-                operation[0]()
-
-            self.assertEqual(mock_cgroup_api_operation.call_count, 0)
-
-    def test_cgroup_operations_should_log_a_warning_when_the_cgroup_api_raises_an_exception(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
-
-        # cleanup_legacy_cgroups disables cgroups on error, so make disable() a no-op
-        with patch.object(configurator, "disable"):
-            # List of operations to test, and the functions to mock in order to raise exceptions
-            operations = [
-                [configurator.create_extensions_slice, "azurelinuxagent.common.cgroupapi.SystemdCgroupsApi.create_extensions_slice"],
-            ]
+        with self._get_cgroup_configurator(initialize=False) as configurator:
+            # Start tracking a couple of dummy cgroups
+            CGroupsTelemetry.track_cgroup(CGroup("dummy", "/sys/fs/cgroup/memory/system.slice/dummy.service", "cpu"))
+            CGroupsTelemetry.track_cgroup(CGroup("dummy", "/sys/fs/cgroup/memory/system.slice/dummy.service", "memory"))
 
-            def raise_exception(*_):
-                raise Exception("A TEST EXCEPTION")
+            configurator.disable()
 
-            for operation in operations:
-                with patch("azurelinuxagent.common.cgroupconfigurator.logger.warn") as mock_logger_warn:
-                    with patch(operation[1], raise_exception):
-                        operation[0]()
+            # protected-access<W0212> Disabled: OK to access CGroupConfigurator._tracked from unit test for CGroupConfigurator
+            self.assertEqual(len(CGroupsTelemetry._tracked), 0)  # pylint: disable=protected-access
 
-                    self.assertEqual(mock_logger_warn.call_count, 1)
-
-                    args, _ = mock_logger_warn.call_args
-                    message = args[0]
-                    self.assertIn("A TEST EXCEPTION", message)
 
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     def test_start_extension_command_should_not_use_systemd_when_cgroups_are_not_enabled(self, _):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
-        configurator.disable()
+        with self._get_cgroup_configurator() as configurator:
+            configurator.disable()
 
-        with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", wraps=subprocess.Popen) as patcher:
-            configurator.start_extension_command(
-                extension_name="Microsoft.Compute.TestExtension-1.2.3",
-                command="date",
-                timeout=300,
-                shell=False,
-                cwd=self.tmp_dir,
-                env={},
-                stdout=subprocess.PIPE,
-                stderr=subprocess.PIPE)
+            with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", wraps=subprocess.Popen) as patcher:
+                configurator.start_extension_command(
+                    extension_name="Microsoft.Compute.TestExtension-1.2.3",
+                    command="date",
+                    timeout=300,
+                    shell=False,
+                    cwd=self.tmp_dir,
+                    env={},
+                    stdout=subprocess.PIPE,
+                    stderr=subprocess.PIPE)
 
-            command_calls = [args[0] for args, _ in patcher.call_args_list if len(args) > 0 and "date" in args[0]]
-            self.assertEqual(len(command_calls), 1, "The test command should have been called exactly once [{0}]".format(command_calls))
-            self.assertNotIn("systemd-run", command_calls[0], "The command should not have been invoked using systemd")
-            self.assertEqual(command_calls[0], "date", "The command line should not have been modified")
+                command_calls = [args[0] for args, _ in patcher.call_args_list if len(args) > 0 and "date" in args[0]]
+                self.assertEqual(len(command_calls), 1, "The test command should have been called exactly once [{0}]".format(command_calls))
+                self.assertNotIn("systemd-run", command_calls[0], "The command should not have been invoked using systemd")
+                self.assertEqual(command_calls[0], "date", "The command line should not have been modified")
 
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     def test_start_extension_command_should_use_systemd_run_when_cgroups_are_enabled(self, _):
-        with mock_cgroup_commands():
+        with self._get_cgroup_configurator() as configurator:
             with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", wraps=subprocess.Popen) as popen_patch:
-                CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance().start_extension_command(
+                configurator.start_extension_command(
                     extension_name="Microsoft.Compute.TestExtension-1.2.3",
                     command="the-test-extension-command",
                     timeout=300,
@@ -255,8 +232,8 @@ cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blki
     def test_start_extension_command_should_start_tracking_the_extension_cgroups(self, _):
         # CPU usage is initialized when we begin tracking a CPU cgroup; since this test does not retrieve the
         # CPU usage, there is no need for initialization
-        with mock_cgroup_commands():
-            CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance().start_extension_command(
+        with self._get_cgroup_configurator() as configurator:
+            configurator.start_extension_command(
                 extension_name="Microsoft.Compute.TestExtension-1.2.3",
                 command="test command",
                 timeout=300,
@@ -272,88 +249,84 @@ cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blki
         self.assertTrue(
             any(cg for cg in tracked if cg.name == 'Microsoft.Compute.TestExtension-1.2.3' and 'cpu' in cg.path),
             "The extension's CPU is not being tracked")
-        self.assertTrue(
-            any(cg for cg in tracked if cg.name == 'Microsoft.Compute.TestExtension-1.2.3' and 'memory' in cg.path),
-            "The extension's memory is not being tracked")
 
     def test_start_extension_command_should_raise_an_exception_when_the_command_cannot_be_started(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            original_popen = subprocess.Popen
 
-        original_popen = subprocess.Popen
+            def mock_popen(command_arg, *args, **kwargs):
+                if "test command" in command_arg:
+                    raise Exception("A TEST EXCEPTION")
+                return original_popen(command_arg, *args, **kwargs)
 
-        def mock_popen(command_arg, *args, **kwargs):
-            if "test command" in command_arg:
-                raise Exception("A TEST EXCEPTION")
-            return original_popen(command_arg, *args, **kwargs)
-
-        with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen):
-            with self.assertRaises(Exception) as context_manager:
-                configurator.start_extension_command(
-                    extension_name="Microsoft.Compute.TestExtension-1.2.3",
-                    command="test command",
-                    timeout=300,
-                    shell=False,
-                    cwd=self.tmp_dir,
-                    env={},
-                    stdout=subprocess.PIPE,
-                    stderr=subprocess.PIPE)
+            with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen):
+                with self.assertRaises(Exception) as context_manager:
+                    configurator.start_extension_command(
+                        extension_name="Microsoft.Compute.TestExtension-1.2.3",
+                        command="test command",
+                        timeout=300,
+                        shell=False,
+                        cwd=self.tmp_dir,
+                        env={},
+                        stdout=subprocess.PIPE,
+                        stderr=subprocess.PIPE)
 
-                self.assertIn("A TEST EXCEPTION", str(context_manager.exception))
+                    self.assertIn("A TEST EXCEPTION", str(context_manager.exception))
 
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     def test_start_extension_command_should_disable_cgroups_and_invoke_the_command_directly_if_systemd_fails(self, _):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            original_popen = subprocess.Popen
 
-        original_popen = subprocess.Popen
-
-        def mock_popen(command, *args, **kwargs):
-            if command.startswith('systemd-run'):
-                # Inject a syntax error to the call
-                command = command.replace('systemd-run', 'systemd-run syntax_error')
-            return original_popen(command, *args, **kwargs)
+            def mock_popen(command, *args, **kwargs):
+                if command.startswith('systemd-run'):
+                    # Inject a syntax error to the call
+                    command = command.replace('systemd-run', 'systemd-run syntax_error')
+                return original_popen(command, *args, **kwargs)
 
-        with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as output_file:
-            with patch("azurelinuxagent.common.cgroupconfigurator.add_event") as mock_add_event:
-                with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen) as popen_patch:
-                    CGroupsTelemetry.reset()
+            with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as output_file:
+                with patch("azurelinuxagent.common.cgroupconfigurator.add_event") as mock_add_event:
+                    with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen) as popen_patch:
+                        CGroupsTelemetry.reset()
 
-                    command = "echo TEST_OUTPUT"
+                        command = "echo TEST_OUTPUT"
 
-                    command_output = configurator.start_extension_command(
-                        extension_name="Microsoft.Compute.TestExtension-1.2.3",
-                        command=command,
-                        timeout=300,
-                        shell=True,
-                        cwd=self.tmp_dir,
-                        env={},
-                        stdout=output_file,
-                        stderr=output_file)
+                        command_output = configurator.start_extension_command(
+                            extension_name="Microsoft.Compute.TestExtension-1.2.3",
+                            command=command,
+                            timeout=300,
+                            shell=True,
+                            cwd=self.tmp_dir,
+                            env={},
+                            stdout=output_file,
+                            stderr=output_file)
 
-                    self.assertFalse(configurator.enabled(), "Cgroups should have been disabled")
+                        self.assertFalse(configurator.enabled(), "Cgroups should have been disabled")
 
-                    args, kwargs = mock_add_event.call_args
-                    self.assertIn("Failed to start extension Microsoft.Compute.TestExtension-1.2.3 using systemd-run.",
-                                  kwargs['message'])
-                    self.assertIn("Failed to find executable syntax_error: No such file or directory",
-                                  kwargs['message'])
-                    self.assertEqual(False, kwargs['is_success'])
-                    self.assertEqual(WALAEventOperation.CGroupsDisabled, kwargs['op'])
+                        args, kwargs = mock_add_event.call_args
+                        self.assertIn("Failed to start extension Microsoft.Compute.TestExtension-1.2.3 using systemd-run.",
+                                      kwargs['message'])
+                        self.assertIn("Failed to find executable syntax_error: No such file or directory",
+                                      kwargs['message'])
+                        self.assertEqual(False, kwargs['is_success'])
+                        self.assertEqual(WALAEventOperation.CGroupsDisabled, kwargs['op'])
 
-                    extension_calls = [args[0] for (args, _) in popen_patch.call_args_list if command in args[0]]
+                        extension_calls = [args[0] for (args, _) in popen_patch.call_args_list if command in args[0]]
 
-                    self.assertEqual(2, len(extension_calls), "The extension should have been invoked exactly twice")
-                    self.assertIn("systemd-run --unit=Microsoft.Compute.TestExtension_1.2.3", extension_calls[0],
-                                  "The first call to the extension should have used systemd")
-                    self.assertEqual(command, extension_calls[1],
-                                      "The second call to the extension should not have used systemd")
+                        self.assertEqual(2, len(extension_calls), "The extension should have been invoked exactly twice")
+                        self.assertIn("systemd-run --unit=Microsoft.Compute.TestExtension_1.2.3", extension_calls[0],
+                                      "The first call to the extension should have used systemd")
+                        self.assertEqual(command, extension_calls[1],
+                                          "The second call to the extension should not have used systemd")
 
-                    self.assertEqual(len(CGroupsTelemetry._tracked), 0, "No cgroups should have been created")  # pylint: disable=protected-access
+                        self.assertEqual(len(CGroupsTelemetry._tracked), 0, "No cgroups should have been created")  # pylint: disable=protected-access
 
-                    self.assertIn("TEST_OUTPUT\n", command_output, "The test output was not captured")
+                        self.assertIn("TEST_OUTPUT\n", command_output, "The test output was not captured")
 
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     def test_start_extension_command_should_disable_cgroups_and_invoke_the_command_directly_if_systemd_times_out(self, _):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            pass  # release the mocks used to create the test CGroupConfigurator so that they do not conflict the mock Popen below
 
         # Systemd has its own internal timeout which is shorter than what we define for extension operation timeout.
         # When systemd times out, it will write a message to stderr and exit with exit code 1.
@@ -396,12 +369,12 @@ cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blki
                     self.assertEqual(len(CGroupsTelemetry._tracked), 0, "No cgroups should have been created")  # pylint: disable=protected-access
 
     @attr('requires_sudo')
-    @patch("azurelinuxagent.common.cgroupapi.add_event")
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     def test_start_extension_command_should_not_use_fallback_option_if_extension_fails(self, *args):
         self.assertTrue(i_am_root(), "Test does not run when non-root")
 
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            pass  # release the mocks used to create the test CGroupConfigurator so that they do not conflict the mock Popen below
 
         command = "ls folder_does_not_exist"
 
@@ -432,13 +405,13 @@ cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blki
                     self.assertIn("Microsoft.Compute.TestExtension_1.2.3", ustr(context_manager.exception))
 
     @attr('requires_sudo')
-    @patch("azurelinuxagent.common.cgroupapi.add_event")
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     @patch("azurelinuxagent.common.utils.extensionprocessutil.TELEMETRY_MESSAGE_MAX_LEN", 5)
     def test_start_extension_command_should_not_use_fallback_option_if_extension_fails_with_long_output(self, *args):
         self.assertTrue(i_am_root(), "Test does not run when non-root")
 
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            pass  # release the mocks used to create the test CGroupConfigurator so that they do not conflict the mock Popen below
 
         long_output = "a"*20  # large enough to ensure both stdout and stderr are truncated
         long_stdout_stderr_command = "echo {0} && echo {0} >&2 && ls folder_does_not_exist".format(long_output)
@@ -470,11 +443,11 @@ cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blki
                     self.assertNotIn("Microsoft.Compute.TestExtension_1.2.3", ustr(context_manager.exception))
 
     @attr('requires_sudo')
-    @patch("azurelinuxagent.common.cgroupapi.add_event")
     def test_start_extension_command_should_not_use_fallback_option_if_extension_times_out(self, *args):  # pylint: disable=unused-argument
         self.assertTrue(i_am_root(), "Test does not run when non-root")
 
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            pass  # release the mocks used to create the test CGroupConfigurator so that they do not conflict the mock Popen below
 
         with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as stdout:
             with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as stderr:
@@ -498,7 +471,8 @@ cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blki
 
     @patch('time.sleep', side_effect=lambda _: mock_sleep())
     def test_start_extension_command_should_capture_only_the_last_subprocess_output(self, _):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            pass  # release the mocks used to create the test CGroupConfigurator so that they do not conflict the mock Popen below
 
         original_popen = subprocess.Popen
 
@@ -512,23 +486,23 @@ cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blki
 
         with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as stdout:
             with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as stderr:
-                with patch("azurelinuxagent.common.cgroupapi.add_event"):
-                    with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen):
-                        # We expect this call to fail because of the syntax error
-                        process_output = configurator.start_extension_command(
-                            extension_name="Microsoft.Compute.TestExtension-1.2.3",
-                            command="echo 'very specific test message'",
-                            timeout=300,
-                            shell=True,
-                            cwd=self.tmp_dir,
-                            env={},
-                            stdout=stdout,
-                            stderr=stderr)
+                with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen):
+                    # We expect this call to fail because of the syntax error
+                    process_output = configurator.start_extension_command(
+                        extension_name="Microsoft.Compute.TestExtension-1.2.3",
+                        command="echo 'very specific test message'",
+                        timeout=300,
+                        shell=True,
+                        cwd=self.tmp_dir,
+                        env={},
+                        stdout=stdout,
+                        stderr=stderr)
 
-                        self.assertEqual(expected_output.format("very specific test message"), process_output)
+                    self.assertEqual(expected_output.format("very specific test message"), process_output)
 
     def test_check_processes_in_agent_cgroup_should_disable_cgroups_when_there_are_unexpected_processes_in_the_agent_cgroup(self):
-        configurator = CGroupConfiguratorSystemdTestCase._get_new_cgroup_configurator_instance()
+        with self._get_cgroup_configurator() as configurator:
+            pass  # release the mocks used to create the test CGroupConfigurator so that they do not conflict the mock Popen below
 
         # The test script recursively creates a given number of descendant processes, then it blocks until the
         # 'stop_file' exists. It produces an output file containing the PID of each descendant process.
@@ -592,7 +566,7 @@ exit 0
                 # Extensions are stated using systemd-run; mock Popen to remove the call to systemd-run; the test script creates a couple of
                 # child processes, which would simulate the extension's processes.
                 def mock_popen(command, *args, **kwargs):
-                    match = re.match(r"^systemd-run --unit=[^\s]+ --scope (.+)", command)
+                    match = re.match(r"^systemd-run --unit=[^\s]+ --scope --slice=[^\s]+ (.+)", command)
                     is_systemd_run = match is not None
                     if is_systemd_run:
                         command = match.group(1)
diff --git a/tests/data/init/walinuxagent.service_system-slice b/tests/data/init/walinuxagent.service_system-slice
new file mode 100644
index 00000000..3cf47c5b
--- /dev/null
+++ b/tests/data/init/walinuxagent.service_system-slice
@@ -0,0 +1,23 @@
+#
+# NOTE:
+#   This file hosted on WALinuxAgent repository only for reference purposes.
+#   Please refer to a recent image to find out the up-to-date systemd unit file.
+#
+
+[Unit]
+Description=Azure Linux Agent
+
+After=network-online.target cloud-init.service
+Wants=network-online.target sshd.service sshd-keygen.service
+
+ConditionFileIsExecutable=/usr/sbin/waagent
+ConditionPathExists=/etc/waagent.conf
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/python3 -u /usr/sbin/waagent -daemon
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/tests/ga/test_update.py b/tests/ga/test_update.py
index 5b91fd16..84fdc528 100644
--- a/tests/ga/test_update.py
+++ b/tests/ga/test_update.py
@@ -21,7 +21,6 @@ from threading import currentThread
 from mock import PropertyMock
 
 from azurelinuxagent.common import conf
-from azurelinuxagent.common.cgroupconfigurator import CGroupConfigurator
 from azurelinuxagent.common.event import EVENTS_DIRECTORY
 from azurelinuxagent.common.exception import ProtocolError, UpdateError, ResourceGoneError
 from azurelinuxagent.common.future import ustr
@@ -42,7 +41,6 @@ from azurelinuxagent.ga.exthandlers import ExtHandlerInstance, HandlerEnvironmen
 from azurelinuxagent.ga.update import GuestAgent, GuestAgentError, MAX_FAILURE, AGENT_MANIFEST_FILE, \
     get_update_handler, ORPHAN_POLL_INTERVAL, AGENT_PARTITION_FILE, AGENT_ERROR_FILE, ORPHAN_WAIT_INTERVAL, \
     CHILD_LAUNCH_RESTART_MAX, CHILD_HEALTH_INTERVAL, UpdateHandler
-from tests.common.mock_cgroup_commands import mock_cgroup_commands
 from tests.protocol.mocks import mock_wire_protocol
 from tests.protocol.mockwiredata import DATA_FILE, DATA_FILE_MULTIPLE_EXT
 from tests.tools import AgentTestCase, call, data_dir, DEFAULT, patch, load_bin_data, load_data, Mock, MagicMock, \
@@ -842,44 +840,6 @@ class TestUpdate(UpdateTestCase):
                 stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH,
                 mode)
 
-    def test_ensure_cgroups_initialized_creates_slices(self):
-        try:
-            azure_slice_path = os.path.join(self.tmp_dir, "azure.slice")
-            extensions_slice_path = os.path.join(self.tmp_dir, "azure-vmextensions.slice")
-
-            self.assertFalse(os.path.exists(azure_slice_path))
-            self.assertFalse(os.path.exists(extensions_slice_path))
-
-            CGroupConfigurator._instance = None  # pylint: disable=protected-access
-            with mock_cgroup_commands() as mocks:
-                # Mock out all the actual calls to systemd
-                mocks.add_file(r"^/etc/systemd/system/azure.slice$", azure_slice_path)
-                mocks.add_file(r"^/etc/systemd/system/azure-vmextensions.slice$", extensions_slice_path)
-
-                with patch.object(CGroupConfigurator.get_instance(), "enabled", return_value=True):
-                    self.update_handler._ensure_cgroups_initialized()  # pylint: disable=protected-access
-
-                    # Ensure we created the slice files with proper content if cgroups are enabled
-                    self.assertTrue(os.path.exists(azure_slice_path))
-                    self.assertTrue(os.path.exists(extensions_slice_path))
-                    self.assertEqual(fileutil.read_file(azure_slice_path), """[Unit]
-Description=Slice for Azure VM Agent and Extensions""")
-                    self.assertEqual(fileutil.read_file(extensions_slice_path), """[Unit]
-Description=Slice for Azure VM Extensions""")
-
-                # Clean files up for next assertion
-                os.remove(azure_slice_path)
-                os.remove(extensions_slice_path)
-
-                with patch.object(CGroupConfigurator.get_instance(), "enabled", return_value=False):
-                    self.update_handler._ensure_cgroups_initialized()  # pylint: disable=protected-access
-
-                    # Ensure we don't create the slice files if cgroups are disabled
-                    self.assertFalse(os.path.exists(azure_slice_path))
-                    self.assertFalse(os.path.exists(extensions_slice_path))
-        finally:
-            CGroupConfigurator._instance = None  # pylint: disable=protected-access
-
     def _test_evaluate_agent_health(self, child_agent_index=0):
         self.prepare_agents()
 
diff --git a/tests/utils/cgroups_tools.py b/tests/utils/cgroups_tools.py
index 19aeaa9e..45b81744 100644
--- a/tests/utils/cgroups_tools.py
+++ b/tests/utils/cgroups_tools.py
@@ -16,7 +16,6 @@
 #
 
 import os
-from azurelinuxagent.common.cgroupapi import VM_AGENT_CGROUP_NAME
 from azurelinuxagent.common.utils import fileutil
 
 class CGroupsTools(object):
@@ -42,7 +41,7 @@ class CGroupsTools(object):
 
         This method creates a mock cgroup using the newer path and adds the given PID to it.
         """
-        new_cgroup = os.path.join(cgroups_file_system_root, controller, VM_AGENT_CGROUP_NAME)
+        new_cgroup = os.path.join(cgroups_file_system_root, controller, "walinuxagent.service")
         if not os.path.exists(new_cgroup):
             os.makedirs(new_cgroup)
         fileutil.append_file(os.path.join(new_cgroup, "cgroup.procs"), extension_handler_pid + "\n")