Esempio n. 1
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))
Esempio n. 2
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))
Esempio n. 3
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)
Esempio n. 4
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")
    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")

        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:
                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:
                            configurator.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.assertEqual(
                            context_manager.exception.code,
                            ExtensionErrorCodes.PluginHandlerScriptTimedout)
                        self.assertIn("Timeout",
                                      ustr(context_manager.exception))
    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")

        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)

        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 popen_patch:
                    with self.assertRaises(ExtensionError) as context_manager:
                        configurator.start_extension_command(
                            extension_name=
                            "Microsoft.Compute.TestExtension-1.2.3",
                            command=long_stdout_stderr_command,
                            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 long_stdout_stderr_command in args[0]
                    ]

                    self.assertEqual(
                        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 first call to the extension should have used systemd"
                    )

                    self.assertEqual(context_manager.exception.code,
                                     ExtensionErrorCodes.PluginUnknownFailure)
                    self.assertIn("Non-zero exit code",
                                  ustr(context_manager.exception))
                    # stdout and stderr should have been truncated, so the scope name doesn't appear in stderr
                    # even though systemd-run ran
                    self.assertNotIn("Microsoft.Compute.TestExtension_1.2.3",
                                     ustr(context_manager.exception))
Esempio n. 7
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")
    def test_telemetry_with_tracked_cgroup(self, *_):
        self.assertTrue(i_am_root(), "Test does not run when non-root")
        CGroupConfigurator._instance = None

        max_num_polls = 30
        time_to_wait = 3
        extn_name = "foobar-1.0.0"
        num_summarization_values = 7

        cgs = make_new_cgroup(extn_name)
        self.assertEqual(len(cgs), 2)

        ext_handler_properties = ExtHandlerProperties()
        ext_handler_properties.version = "1.0.0"
        self.ext_handler = ExtHandler(name='foobar')
        self.ext_handler.properties = ext_handler_properties
        self.ext_handler_instance = ExtHandlerInstance(
            ext_handler=self.ext_handler, protocol=None)

        command = self.create_script(
            "keep_cpu_busy_and_consume_memory_for_5_seconds", '''
nohup python -c "import time

for i in range(5):
    x = [1, 2, 3, 4, 5] * (i * 1000)
    time.sleep({0})
    x *= 0
    print('Test loop')" &
'''.format(time_to_wait))

        self.log_dir = os.path.join(self.tmp_dir, "log")

        with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_base_dir", lambda *_: self.tmp_dir) as \
                patch_get_base_dir:
            with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_log_dir", lambda *_: self.log_dir) as \
                    patch_get_log_dir:
                self.ext_handler_instance.launch_command(command)

        self.assertTrue(
            CGroupsTelemetry.is_tracked(
                os.path.join(BASE_CGROUPS, "cpu", "walinuxagent.extensions",
                             "foobar_1.0.0")))
        self.assertTrue(
            CGroupsTelemetry.is_tracked(
                os.path.join(BASE_CGROUPS, "memory", "walinuxagent.extensions",
                             "foobar_1.0.0")))

        for i in range(max_num_polls):
            CGroupsTelemetry.poll_all_tracked()
            time.sleep(0.5)

        collected_metrics = CGroupsTelemetry.report_all_tracked()

        self.assertIn("memory", collected_metrics[extn_name])
        self.assertIn("cur_mem", collected_metrics[extn_name]["memory"])
        self.assertIn("max_mem", collected_metrics[extn_name]["memory"])
        self.assertEqual(
            len(collected_metrics[extn_name]["memory"]["cur_mem"]),
            num_summarization_values)
        self.assertEqual(
            len(collected_metrics[extn_name]["memory"]["max_mem"]),
            num_summarization_values)

        self.assertIsInstance(
            collected_metrics[extn_name]["memory"]["cur_mem"][5], str)
        self.assertIsInstance(
            collected_metrics[extn_name]["memory"]["cur_mem"][6], str)
        self.assertIsInstance(
            collected_metrics[extn_name]["memory"]["max_mem"][5], str)
        self.assertIsInstance(
            collected_metrics[extn_name]["memory"]["max_mem"][6], str)

        self.assertIn("cpu", collected_metrics[extn_name])
        self.assertIn("cur_cpu", collected_metrics[extn_name]["cpu"])
        self.assertEqual(len(collected_metrics[extn_name]["cpu"]["cur_cpu"]),
                         num_summarization_values)

        self.assertIsInstance(
            collected_metrics[extn_name]["cpu"]["cur_cpu"][5], str)
        self.assertIsInstance(
            collected_metrics[extn_name]["cpu"]["cur_cpu"][6], str)

        for i in range(5):
            self.assertGreater(
                collected_metrics[extn_name]["memory"]["cur_mem"][i], 0)
            self.assertGreater(
                collected_metrics[extn_name]["memory"]["max_mem"][i], 0)
            self.assertGreaterEqual(
                collected_metrics[extn_name]["cpu"]["cur_cpu"][i], 0)
Esempio n. 9
0
    def test_telemetry_with_tracked_cgroup(self):
        self.assertTrue(i_am_root(), "Test does not run when non-root")

        # This test has some timing issues when systemd is managing cgroups, so we force the file system API
        # by creating a new instance of the CGroupConfigurator
        with patch("azurelinuxagent.common.cgroupapi.CGroupsApi._is_systemd", return_value=False):
            cgroup_configurator_instance = CGroupConfigurator._instance
            CGroupConfigurator._instance = None

            try:
                max_num_polls = 30
                time_to_wait = 3
                extn_name = "foobar-1.0.0"
                num_summarization_values = 7

                cgs = make_new_cgroup(extn_name)
                self.assertEqual(len(cgs), 2)

                ext_handler_properties = ExtHandlerProperties()
                ext_handler_properties.version = "1.0.0"
                self.ext_handler = ExtHandler(name='foobar')
                self.ext_handler.properties = ext_handler_properties
                self.ext_handler_instance = ExtHandlerInstance(ext_handler=self.ext_handler, protocol=None)

                command = self.create_script("keep_cpu_busy_and_consume_memory_for_5_seconds", '''
nohup python -c "import time

for i in range(5):
    x = [1, 2, 3, 4, 5] * (i * 1000)
    time.sleep({0})
    x *= 0
    print('Test loop')" &
'''.format(time_to_wait))

                self.log_dir = os.path.join(self.tmp_dir, "log")

                with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_base_dir", lambda *_: self.tmp_dir) as \
                        patch_get_base_dir:
                    with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_log_dir", lambda *_: self.log_dir) as \
                            patch_get_log_dir:
                        self.ext_handler_instance.launch_command(command)

                #
                # If the test is made to run using the systemd API, then the paths of the cgroups need to be checked differently:
                #
                #     self.assertEquals(len(CGroupsTelemetry._tracked), 2)
                #     cpu = os.path.join(BASE_CGROUPS, "cpu", "system.slice", r"foobar_1.0.0_.*\.scope")
                #     self.assertTrue(any(re.match(cpu, tracked.path) for tracked in CGroupsTelemetry._tracked))
                #     memory = os.path.join(BASE_CGROUPS, "memory", "system.slice", r"foobar_1.0.0_.*\.scope")
                #     self.assertTrue(any(re.match(memory, tracked.path) for tracked in CGroupsTelemetry._tracked))
                #
                self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
                    BASE_CGROUPS, "cpu", "walinuxagent.extensions", "foobar_1.0.0")))
                self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
                    BASE_CGROUPS, "memory", "walinuxagent.extensions", "foobar_1.0.0")))

                for i in range(max_num_polls):
                    CGroupsTelemetry.poll_all_tracked()
                    time.sleep(0.5)

                collected_metrics = CGroupsTelemetry.report_all_tracked()

                self.assertIn("memory", collected_metrics[extn_name])
                self.assertIn("cur_mem", collected_metrics[extn_name]["memory"])
                self.assertIn("max_mem", collected_metrics[extn_name]["memory"])
                self.assertEqual(len(collected_metrics[extn_name]["memory"]["cur_mem"]), num_summarization_values)
                self.assertEqual(len(collected_metrics[extn_name]["memory"]["max_mem"]), num_summarization_values)

                self.assertIsInstance(collected_metrics[extn_name]["memory"]["cur_mem"][5], str)
                self.assertIsInstance(collected_metrics[extn_name]["memory"]["cur_mem"][6], str)
                self.assertIsInstance(collected_metrics[extn_name]["memory"]["max_mem"][5], str)
                self.assertIsInstance(collected_metrics[extn_name]["memory"]["max_mem"][6], str)

                self.assertIn("cpu", collected_metrics[extn_name])
                self.assertIn("cur_cpu", collected_metrics[extn_name]["cpu"])
                self.assertEqual(len(collected_metrics[extn_name]["cpu"]["cur_cpu"]), num_summarization_values)

                self.assertIsInstance(collected_metrics[extn_name]["cpu"]["cur_cpu"][5], str)
                self.assertIsInstance(collected_metrics[extn_name]["cpu"]["cur_cpu"][6], str)

                for i in range(5):
                    self.assertGreater(collected_metrics[extn_name]["memory"]["cur_mem"][i], 0)
                    self.assertGreater(collected_metrics[extn_name]["memory"]["max_mem"][i], 0)
                    self.assertGreaterEqual(collected_metrics[extn_name]["cpu"]["cur_cpu"][i], 0)
                    # Equal because CPU could be zero for minimum value.
            finally:
                CGroupConfigurator._instance = cgroup_configurator_instance