예제 #1
0
    def test_start_extension_command_should_use_systemd_if_not_failing(self):
        original_popen = subprocess.Popen

        def mock_popen(*args, **kwargs):
            return original_popen(*args, **kwargs)

        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.subprocess.Popen",
                           side_effect=mock_popen) as patch_mock_popen:
                    process, extension_cgroups = SystemdCgroupsApi(
                    ).start_extension_command(
                        extension_name="Microsoft.Compute.TestExtension-1.2.3",
                        command="date",
                        shell=True,
                        cwd=self.tmp_dir,
                        env={},
                        stdout=stdout,
                        stderr=stderr)

                    process.wait()

                    ret = process.poll()

                    # We should have invoked the extension command only once and succeeded
                    self.assertEquals(0, ret)
                    self.assertEquals(1, patch_mock_popen.call_count)

                    args = patch_mock_popen.call_args[0][0]
                    self.assertIn("systemd-run --unit", args)

                    self.assert_cgroups_created(extension_cgroups)
예제 #2
0
    def test_create_extension_cgroups_should_create_extension_slice(self):
        self.assertTrue(i_am_root(), "Test does not run when non-root")

        extension_name = "Microsoft.Azure.DummyExtension-1.0"
        cgroups = SystemdCgroupsApi().create_extension_cgroups(extension_name)
        cpu_cgroup, memory_cgroup = cgroups[0], cgroups[1]
        self.assertEqual(
            cpu_cgroup.path,
            "/sys/fs/cgroup/cpu/system.slice/Microsoft.Azure.DummyExtension_1.0"
        )
        self.assertEqual(
            memory_cgroup.path,
            "/sys/fs/cgroup/memory/system.slice/Microsoft.Azure.DummyExtension_1.0"
        )

        unit_name = SystemdCgroupsApi()._get_extension_slice_name(
            extension_name)
        self.assertEqual(
            "system-walinuxagent.extensions-Microsoft.Azure.DummyExtension_1.0.slice",
            unit_name)

        _, status = shellutil.run_get_output(
            "systemctl status {0}".format(unit_name))
        self.assertIn("Loaded: loaded", status)
        self.assertIn("Active: active", status)

        shellutil.run_get_output("systemctl stop {0}".format(unit_name))
        shellutil.run_get_output("systemctl disable {0}".format(unit_name))
        os.remove("/etc/systemd/system/{0}".format(unit_name))
        shellutil.run_get_output("systemctl daemon-reload")
예제 #3
0
    def test_start_extension_command_should_not_use_systemd_if_failing(self):
        original_popen = subprocess.Popen

        def mock_popen(*args, **kwargs):
            # Inject a syntax error to the call
            systemd_command = args[0].replace('systemd-run',
                                              'systemd-run syntax_error')
            new_args = (systemd_command, )
            return original_popen(new_args, **kwargs)

        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"
                           ) as mock_add_event:
                    with patch(
                            "azurelinuxagent.common.cgroupapi.subprocess.Popen",
                            side_effect=mock_popen) as patch_mock_popen:

                        # We expect this call to fail because of the syntax error
                        process, extension_cgroups = SystemdCgroupsApi(
                        ).start_extension_command(
                            extension_name=
                            "Microsoft.Compute.TestExtension-1.2.3",
                            command="date",
                            shell=True,
                            cwd=self.tmp_dir,
                            env={},
                            stdout=stdout,
                            stderr=stderr)

                        process.wait()

                        args, kwargs = mock_add_event.call_args
                        self.assertIn(
                            "Failed to run systemd-run for unit Microsoft.Compute.TestExtension_1.2.3",
                            kwargs['message'])
                        self.assertIn(
                            "Failed to find executable syntax_error: No such file or directory",
                            kwargs['message'])
                        self.assertEquals(False, kwargs['is_success'])
                        self.assertEquals('InvokeCommandUsingSystemd',
                                          kwargs['op'])

                        # We expect the process to ultimately succeed since the fallback option worked
                        ret = process.poll()
                        self.assertEquals(0, ret)

                        # We expect two calls to Popen, first for the systemd-run call, second for the fallback option
                        self.assertEquals(2, patch_mock_popen.call_count)

                        first_call_args = patch_mock_popen.mock_calls[0][1][0]
                        second_call_args = patch_mock_popen.mock_calls[1][1][0]
                        self.assertIn("systemd-run --unit", first_call_args)
                        self.assertNotIn("systemd-run --unit",
                                         second_call_args)

                        # No cgroups should have been created
                        self.assertEquals(extension_cgroups, [])
예제 #4
0
    def test_if_extensions_root_slice_is_created(self):
        SystemdCgroupsApi().create_extension_cgroups_root()

        unit_name = SystemdCgroupsApi()._get_extensions_slice_root_name()
        _, status = shellutil.run_get_output("systemctl status {0}".format(unit_name))
        self.assertIn("Loaded: loaded", status)
        self.assertIn("Active: active", status)

        shellutil.run_get_output("systemctl stop {0}".format(unit_name))
        shellutil.run_get_output("systemctl disable {0}".format(unit_name))
        os.remove("/etc/systemd/system/{0}".format(unit_name))
        shellutil.run_get_output("systemctl daemon-reload")
예제 #5
0
        def initialize(self):
            try:
                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 that systemd is detected correctly
                self._cgroups_api = SystemdCgroupsApi()
                if not systemd.is_systemd():
                    _log_cgroup_warning("systemd was not detected on {0}", get_distro())
                    return

                _log_cgroup_info("systemd version: {0}", systemd.get_version())

                # This is temporarily disabled while we analyze telemetry. Likely it will be removed.
                # self.__collect_azure_unit_telemetry()
                # self.__collect_agent_unit_files_telemetry()

                if not self.__check_no_legacy_cgroups():
                    return

                agent_unit_name = systemd.get_agent_unit_name()
                agent_slice = systemd.get_unit_property(agent_unit_name, "Slice")
                if agent_slice not in (_AZURE_SLICE, "system.slice"):
                    _log_cgroup_warning("The agent is within an unexpected slice: {0}", agent_slice)
                    return

                self.__setup_azure_slice()

                cpu_controller_root, memory_controller_root = self.__get_cgroup_controllers()
                self._agent_cpu_cgroup_path, self._agent_memory_cgroup_path = self.__get_agent_cgroups(agent_slice, cpu_controller_root, memory_controller_root)

                if self._agent_cpu_cgroup_path is not None:
                    _log_cgroup_info("Agent CPU cgroup: {0}", self._agent_cpu_cgroup_path)
                    self.enable()
                    CGroupsTelemetry.track_cgroup(CpuCgroup(AGENT_NAME_TELEMETRY, self._agent_cpu_cgroup_path))

                _log_cgroup_info('Cgroups enabled: {0}', self._cgroups_enabled)

            except Exception as exception:
                _log_cgroup_warning("Error initializing cgroups: {0}", ustr(exception))
            finally:
                self._initialized = True
예제 #6
0
 def is_extension_resource_limits_setup_completed(self, extension_name):
     unit_file_install_path = systemd.get_unit_file_install_path()
     extension_slice_path = os.path.join(unit_file_install_path,
                                         SystemdCgroupsApi.get_extension_slice_name(extension_name))
     if os.path.exists(extension_slice_path):
         return True
     return False
예제 #7
0
    def test_cleanup_legacy_cgroups_should_report_an_error_when_the_daemon_pid_was_added_to_the_legacy_cgroups(
            self):
        # Set up a mock /var/run/waagent.pid file
        daemon_pid = "42"
        daemon_pid_file = os.path.join(self.tmp_dir, "waagent.pid")
        fileutil.write_file(daemon_pid_file, daemon_pid + "\n")

        # Set up old controller cgroups and add the daemon's PID to them
        legacy_cpu_cgroup = CGroupsTools.create_legacy_agent_cgroup(
            self.cgroups_file_system_root, "cpu", daemon_pid)
        legacy_memory_cgroup = CGroupsTools.create_legacy_agent_cgroup(
            self.cgroups_file_system_root, "memory", daemon_pid)

        with patch("azurelinuxagent.common.cgroupapi.add_event"
                   ) as mock_add_event:
            with patch(
                    "azurelinuxagent.common.cgroupapi.get_agent_pid_file_path",
                    return_value=daemon_pid_file):
                with self.assertRaises(CGroupsException) as context_manager:
                    SystemdCgroupsApi().cleanup_legacy_cgroups()

        self.assertEquals(
            str(context_manager.exception),
            "[CGroupsException] The daemon's PID ({0}) was already added to the legacy cgroup; this invalidates resource usage data."
            .format(daemon_pid))

        # The method should have deleted the legacy cgroups
        self.assertFalse(os.path.exists(legacy_cpu_cgroup))
        self.assertFalse(os.path.exists(legacy_memory_cgroup))
예제 #8
0
 def test_get_service_cgroup_paths_should_return_the_cgroup_mount_points(self):
     with mock_cgroup_environment(self.tmp_dir):
         cpu, memory = SystemdCgroupsApi().get_unit_cgroup_paths("extension.service")
         self.assertIn(cpu, '/sys/fs/cgroup/cpu,cpuacct/system.slice/extension.service',
                       "The mount point for the CPU controller is incorrect")
         self.assertIn(memory, '/sys/fs/cgroup/memory/system.slice/extension.service',
                       "The mount point for the memory controller is incorrect")
예제 #9
0
    def test_get_processes_in_cgroup_should_return_the_processes_within_the_cgroup(
            self):
        with mock_cgroup_commands():
            processes = SystemdCgroupsApi.get_processes_in_cgroup(
                "/sys/fs/cgroup/cpu/system.slice/walinuxagent.service")

            self.assertTrue(
                len(processes) >= 2,
                "The cgroup should contain at least 2 procceses (daemon and extension handler): [{0}]"
                .format(processes))

            daemon_present = any("waagent -daemon" in command
                                 for (pid, command) in processes)
            self.assertTrue(
                daemon_present,
                "Could not find the daemon in the cgroup: [{0}]".format(
                    processes))

            extension_handler_present = any(
                re.search("(WALinuxAgent-.+\.egg|waagent) -run-exthandlers",
                          command) for (pid, command) in processes)
            self.assertTrue(
                extension_handler_present,
                "Could not find the extension handler in the cgroup: [{0}]".
                format(processes))
예제 #10
0
    def test_start_extension_command_should_use_systemd_and_not_the_fallback_option_if_successful(
            self, _):
        self.assertTrue(i_am_root(), "Test does not run when non-root")

        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.subprocess.Popen", wraps=subprocess.Popen) \
                        as patch_mock_popen:
                    extension_cgroups, process_output = SystemdCgroupsApi(
                    ).start_extension_command(
                        extension_name="Microsoft.Compute.TestExtension-1.2.3",
                        command="date",
                        timeout=300,
                        shell=True,
                        cwd=self.tmp_dir,
                        env={},
                        stdout=stdout,
                        stderr=stderr)

                    # We should have invoked the extension command only once and succeeded
                    self.assertEquals(1, patch_mock_popen.call_count)

                    args = patch_mock_popen.call_args[0][0]
                    self.assertIn("systemd-run --unit", args)

                    self.assert_cgroups_created(extension_cgroups)
예제 #11
0
    def test_start_extension_command_should_execute_the_command_in_a_cgroup(
            self, _):
        with mock_cgroup_commands():
            SystemdCgroupsApi().start_extension_command(
                extension_name="Microsoft.Compute.TestExtension-1.2.3",
                command="test command",
                shell=False,
                timeout=300,
                cwd=self.tmp_dir,
                env={},
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)

            tracked = CGroupsTelemetry._tracked

            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")
예제 #12
0
    def test_create_extension_cgroups_root_should_create_extensions_root_slice(
            self):
        self.assertTrue(i_am_root(), "Test does not run when non-root")

        SystemdCgroupsApi().create_extension_cgroups_root()

        unit_name = SystemdCgroupsApi()._get_extensions_slice_root_name()
        _, status = shellutil.run_get_output(
            "systemctl status {0}".format(unit_name))
        self.assertIn("Loaded: loaded", status)
        self.assertIn("Active: active", status)

        shellutil.run_get_output("systemctl stop {0}".format(unit_name))
        shellutil.run_get_output("systemctl disable {0}".format(unit_name))
        os.remove("/etc/systemd/system/{0}".format(unit_name))
        shellutil.run_get_output("systemctl daemon-reload")
예제 #13
0
    def test_create_agent_cgroups_should_create_cgroups_on_all_controllers(
            self, patch_read_file):
        mock_proc_self_cgroup = '''12:blkio:/system.slice/walinuxagent.service
11:memory:/system.slice/walinuxagent.service
10:perf_event:/
9:hugetlb:/
8:freezer:/
7:net_cls,net_prio:/
6:devices:/system.slice/walinuxagent.service
5:cpuset:/
4:cpu,cpuacct:/system.slice/walinuxagent.service
3:pids:/system.slice/walinuxagent.service
2:rdma:/
1:name=systemd:/system.slice/walinuxagent.service
0::/system.slice/walinuxagent.service
'''
        patch_read_file.return_value = mock_proc_self_cgroup
        agent_cgroups = SystemdCgroupsApi().create_agent_cgroups()

        def assert_cgroup_created(controller):
            expected_cgroup_path = os.path.join(CGROUPS_FILE_SYSTEM_ROOT,
                                                controller, "system.slice",
                                                VM_AGENT_CGROUP_NAME)

            self.assertTrue(
                any(cgroups.path == expected_cgroup_path
                    for cgroups in agent_cgroups))
            self.assertTrue(
                any(cgroups.name == VM_AGENT_CGROUP_NAME
                    for cgroups in agent_cgroups))

        assert_cgroup_created("cpu")
        assert_cgroup_created("memory")
예제 #14
0
    def test_start_extension_command_should_not_use_fallback_option_if_extension_times_out(
            self, *args):
        self.assertTrue(i_am_root(), "Test does not run when non-root")

        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.utils.extensionprocessutil.wait_for_process_completion_or_timeout",
                        return_value=[True, None]):
                    with patch(
                            "azurelinuxagent.common.cgroupapi.SystemdCgroupsApi._is_systemd_failure",
                            return_value=False):
                        with self.assertRaises(
                                ExtensionError) as context_manager:
                            SystemdCgroupsApi().start_extension_command(
                                extension_name=
                                "Microsoft.Compute.TestExtension-1.2.3",
                                command="date",
                                timeout=300,
                                shell=True,
                                cwd=self.tmp_dir,
                                env={},
                                stdout=stdout,
                                stderr=stderr)

                        self.assertEquals(
                            context_manager.exception.code,
                            ExtensionErrorCodes.PluginHandlerScriptTimedout)
                        self.assertIn("Timeout",
                                      ustr(context_manager.exception))
예제 #15
0
    def test_start_extension_command_should_use_systemd_to_execute_the_command(
            self, _):
        with mock_cgroup_commands():
            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",
                    command="the-test-extension-command",
                    timeout=300,
                    shell=True,
                    cwd=self.tmp_dir,
                    env={},
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE)

                extension_calls = [
                    args[0] for (args, _) in popen_patch.call_args_list
                    if "the-test-extension-command" in args[0]
                ]

                self.assertEquals(
                    1, len(extension_calls),
                    "The extension should have been invoked exactly once")
                self.assertIn(
                    "systemd-run --unit=Microsoft.Compute.TestExtension_1.2.3",
                    extension_calls[0],
                    "The extension should have been invoked using systemd")
예제 #16
0
    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")

        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.subprocess.Popen", wraps=subprocess.Popen) \
                        as patch_mock_popen:
                    with self.assertRaises(ExtensionError) as context_manager:
                        SystemdCgroupsApi().start_extension_command(
                            extension_name=
                            "Microsoft.Compute.TestExtension-1.2.3",
                            command="ls folder_does_not_exist",
                            timeout=300,
                            shell=True,
                            cwd=self.tmp_dir,
                            env={},
                            stdout=stdout,
                            stderr=stderr)

                        # We should have invoked the extension command only once, in the systemd-run case
                        self.assertEquals(1, patch_mock_popen.call_count)
                        args = patch_mock_popen.call_args[0][0]
                        self.assertIn("systemd-run --unit", args)

                        self.assertEquals(
                            context_manager.exception.code,
                            ExtensionErrorCodes.PluginUnknownFailure)
                        self.assertIn("Non-zero exit code",
                                      ustr(context_manager.exception))
예제 #17
0
    def test_start_extension_command_should_return_the_command_output(self, _):
        original_popen = subprocess.Popen

        def mock_popen(command, *args, **kwargs):
            if command.startswith(
                    'systemd-run --unit=Microsoft.Compute.TestExtension_1.2.3'
            ):
                command = "echo TEST_OUTPUT"
            return original_popen(command, *args, **kwargs)

        with mock_cgroup_commands() as mock_commands:
            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:
                    command_output = SystemdCgroupsApi(
                    ).start_extension_command(
                        extension_name="Microsoft.Compute.TestExtension-1.2.3",
                        command="A_TEST_COMMAND",
                        shell=True,
                        timeout=300,
                        cwd=self.tmp_dir,
                        env={},
                        stdout=output_file,
                        stderr=output_file)

                    self.assertIn("[stdout]\nTEST_OUTPUT\n", command_output,
                                  "The test output was not captured")
예제 #18
0
    def test_get_cgroup2_controllers_should_return_the_v2_cgroup_controllers(self):
        with mock_cgroup_environment(self.tmp_dir):
            mount_point, controllers = SystemdCgroupsApi.get_cgroup2_controllers()

            self.assertEqual(mount_point, "/sys/fs/cgroup/unified", "Invalid mount point for V2 cgroups")
            self.assertIn("cpu", controllers, "The CPU controller is not in the list of V2 controllers")
            self.assertIn("memory", controllers, "The memory controller is not in the list of V2 controllers")
예제 #19
0
 def test_get_systemd_version_should_return_a_version_number(self):
     with mock_cgroup_commands():
         version_info = SystemdCgroupsApi.get_systemd_version()
         found = re.search("systemd \d+", version_info) is not None
         self.assertTrue(
             found, "Could not determine the systemd version: {0}".format(
                 version_info))
예제 #20
0
    def test_cleanup_legacy_cgroups_should_remove_legacy_cgroups(self):
        # Set up a mock /var/run/waagent.pid file
        daemon_pid_file = os.path.join(self.tmp_dir, "waagent.pid")
        fileutil.write_file(daemon_pid_file, "42\n")

        # Set up old controller cgroups, but do not add the daemon's PID to them
        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:
            with patch(
                    "azurelinuxagent.common.cgroupapi.get_agent_pid_file_path",
                    return_value=daemon_pid_file):
                legacy_cgroups = SystemdCgroupsApi().cleanup_legacy_cgroups()

        self.assertEquals(
            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")
        self.assertFalse(
            os.path.exists(legacy_memory_cgroup),
            "cleanup_legacy_cgroups() did not remove the memory legacy cgroup")
예제 #21
0
 def test_it_should_return_extension_slice_name(self):
     extension_name = "Microsoft.Azure.DummyExtension-1.0"
     extension_slice_name = SystemdCgroupsApi()._get_extension_slice_name(
         extension_name)
     self.assertEqual(
         extension_slice_name,
         "system-walinuxagent.extensions-Microsoft.Azure.DummyExtension_1.0.slice"
     )
예제 #22
0
 def mock_cgroup_paths(*args, **kwargs):
     if args and args[0] == "self":
         relative_path = "{0}/{1}".format(
             cgroupconfigurator.LOGCOLLECTOR_SLICE,
             logcollector.CGROUPS_UNIT)
         return (cgroupconfigurator.LOGCOLLECTOR_SLICE,
                 relative_path)
     return SystemdCgroupsApi.get_process_cgroup_relative_paths(
         *args, **kwargs)
예제 #23
0
    def test_start_extension_command_should_invoke_the_command_directly_if_systemd_times_out(
            self, _):
        # 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.
        # In that case, we will internally recognize the failure due to the non-zero exit code, not as a timeout.
        original_popen = subprocess.Popen
        systemd_timeout_command = "echo 'Failed to start transient scope unit: Connection timed out' >&2 && exit 1"

        def mock_popen(*args, **kwargs):
            # If trying to invoke systemd, mock what would happen if systemd timed out internally:
            # write failure to stderr and exit with exit code 1.
            new_args = args
            if "systemd-run" in args[0]:
                new_args = (systemd_timeout_command, )

            return original_popen(new_args, **kwargs)

        expected_output = "[stdout]\n{0}\n\n\n[stderr]\n"

        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.subprocess.Popen",
                           side_effect=mock_popen) as popen_patch:
                    CGroupsTelemetry.reset()

                    SystemdCgroupsApi().start_extension_command(
                        extension_name="Microsoft.Compute.TestExtension-1.2.3",
                        command="echo 'success'",
                        timeout=300,
                        shell=True,
                        cwd=self.tmp_dir,
                        env={},
                        stdout=stdout,
                        stderr=stderr)

                    extension_calls = [
                        args[0] for (args, _) in popen_patch.call_args_list
                        if "echo 'success'" in args[0]
                    ]

                    self.assertEquals(
                        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.assertEquals(
                        "echo 'success'", extension_calls[1],
                        "The second call to the extension should not have used systemd"
                    )

                    self.assertEquals(len(CGroupsTelemetry._tracked), 0,
                                      "No cgroups should have been created")
예제 #24
0
    def test_get_unit_property_should_return_the_value_of_the_given_property(
            self):
        with mock_cgroup_commands():
            cpu_accounting = SystemdCgroupsApi.get_unit_property(
                "walinuxagent.service", "CPUAccounting")

            self.assertEquals(
                cpu_accounting, "no",
                "Property {0} of {1} is incorrect".format(
                    "CPUAccounting", "walinuxagent.service"))
예제 #25
0
 def test_get_cpu_and_memory_mount_points_should_return_the_cgroup_mount_points(
         self):
     with mock_cgroup_commands():
         cpu, memory = SystemdCgroupsApi().get_cgroup_mount_points()
         self.assertEquals(
             cpu, '/sys/fs/cgroup/cpu,cpuacct',
             "The mount point for the CPU controller is incorrect")
         self.assertEquals(
             memory, '/sys/fs/cgroup/memory',
             "The mount point for the memory controller is incorrect")
예제 #26
0
    def test_start_extension_command_should_use_systemd_if_not_failing(self):
        original_popen = subprocess.Popen

        def mock_popen(*args, **kwargs):
            return original_popen(*args, **kwargs)

        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.subprocess.Popen", side_effect=mock_popen) as patch_mock_popen:
                    process, extension_cgroups = SystemdCgroupsApi().start_extension_command(
                        extension_name="Microsoft.Compute.TestExtension-1.2.3",
                        command="date",
                        shell=True,
                        cwd=self.tmp_dir,
                        env={},
                        stdout=stdout,
                        stderr=stderr)

                    process.wait()

                    ret = process.poll()

                    # We should have invoked the extension command only once and succeeded
                    self.assertEquals(0, ret)
                    self.assertEquals(1, patch_mock_popen.call_count)

                    # Assert that the extension's cgroups were created as well
                    self.assertEqual(len(extension_cgroups), 2, 'start_extension_command did not return the expected number of cgroups')

                    cpu_found = memory_found = False

                    for cgroup in extension_cgroups:
                        match = re.match(r'^/sys/fs/cgroup/(cpu|memory)/system.slice/Microsoft.Compute.TestExtension_1\.2\.3\_([a-f0-9-]+)\.scope$', cgroup.path)

                        self.assertTrue(match is not None, "Unexpected path for cgroup: {0}".format(cgroup.path))

                        if match.group(1) == 'cpu':
                            cpu_found = True
                        if match.group(1) == 'memory':
                            memory_found = True

                    self.assertTrue(cpu_found, 'start_extension_command did not return a cpu cgroup')
                    self.assertTrue(memory_found, 'start_extension_command did not return a memory cgroup')
예제 #27
0
 def test_get_cpu_and_memory_cgroup_relative_paths_for_process_should_return_the_cgroup_relative_paths(
         self):
     with mock_cgroup_commands():
         cpu, memory = SystemdCgroupsApi.get_process_cgroup_relative_paths(
             'self')
         self.assertEquals(
             cpu, "system.slice/walinuxagent.service",
             "The relative path for the CPU cgroup is incorrect")
         self.assertEquals(
             memory, "system.slice/walinuxagent.service",
             "The relative memory for the CPU cgroup is incorrect")
예제 #28
0
    def test_start_extension_command_should_create_extension_scopes(self):
        original_popen = subprocess.Popen

        def mock_popen(*args, **kwargs):
            return original_popen("date", **kwargs)

        # we mock subprocess.Popen to execute a dummy command (date), so no actual cgroups are created; their paths
        # should be computed properly, though
        with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen",
                   mock_popen):
            process, extension_cgroups = SystemdCgroupsApi(
            ).start_extension_command(
                extension_name="Microsoft.Compute.TestExtension-1.2.3",
                command="date",
                shell=False,
                cwd=self.tmp_dir,
                env={},
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)

            process.wait()
            self.assert_cgroups_created(extension_cgroups)
예제 #29
0
    def test_start_extension_command_should_capture_only_the_last_subprocess_output(
            self):
        original_popen = subprocess.Popen

        def mock_popen(*args, **kwargs):
            # Inject a syntax error to the call
            systemd_command = args[0].replace('systemd-run',
                                              'systemd-run syntax_error')
            new_args = (systemd_command, )
            return original_popen(new_args, **kwargs)

        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"
                           ) as mock_add_event:
                    with patch(
                            "azurelinuxagent.common.cgroupapi.subprocess.Popen",
                            side_effect=mock_popen) as patch_mock_popen:
                        # We expect this call to fail because of the syntax error
                        process, extension_cgroups = SystemdCgroupsApi(
                        ).start_extension_command(
                            extension_name=
                            "Microsoft.Compute.TestExtension-1.2.3",
                            command="echo 'very specific test message'",
                            shell=True,
                            cwd=self.tmp_dir,
                            env={},
                            stdout=stdout,
                            stderr=stderr)

                        process.wait()
                        process_output = read_output(stdout, stderr)
                        self.assertEquals(
                            "[stdout]\nvery specific test message\n\n\n[stderr]\n",
                            process_output)
예제 #30
0
    def test_start_extension_command_should_create_extension_scopes(self):
        original_popen = subprocess.Popen

        def mock_popen(*args, **kwargs):
            return original_popen("date", **kwargs)

        # we mock subprocess.Popen to execute a dummy command (date), so no actual cgroups are created; their paths
        # should be computed properly, though
        with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", mock_popen):
            process, extension_cgroups = SystemdCgroupsApi().start_extension_command(
                extension_name="Microsoft.Compute.TestExtension-1.2.3",
                command="date",
                shell=False,
                cwd=self.tmp_dir,
                env={},
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)

            process.wait()

            self.assertEqual(len(extension_cgroups), 2, 'start_extension_command did not return the expected number of cgroups')

            cpu_found = memory_found = False

            for cgroup in extension_cgroups:
                match = re.match(r'^/sys/fs/cgroup/(cpu|memory)/system.slice/Microsoft.Compute.TestExtension_1\.2\.3\_([a-f0-9-]+)\.scope$', cgroup.path)

                self.assertTrue(match is not None, "Unexpected path for cgroup: {0}".format(cgroup.path))

                if match.group(1) == 'cpu':
                    cpu_found = True
                if match.group(1) == 'memory':
                    memory_found = True

            self.assertTrue(cpu_found, 'start_extension_command did not return a cpu cgroup')
            self.assertTrue(memory_found, 'start_extension_command did not return a memory cgroup')