def __init__(self, configuration, monitors):
        CopyingManager.__init__(self, configuration, monitors)
        # Approach:  We will override key methods of CopyingManager, blocking them from returning until the controller
        # tells it to proceed.  This allows us to then do things like write new log lines while the CopyingManager is
        # blocked.   Coordinating the communication between the two threads is done using two condition variables.
        # We changed the CopyingManager to block in three places: while it is sleeping before it starts a new loop,
        # when it invokes ``_send_events`` to send a new request, and when it blocks to receive the response.
        # These three states or referred to as "sleeping", "blocked_on_send", "blocked_on_receive".
        #
        # This cv protects all of the variables written by the CopyingManager thread.
        self.__test_state_cv = threading.Condition()
        # Which state the CopyingManager is currently blocked in -- "sleeping", "blocked_on_send", "blocked_on_receive"
        self.__test_state = None
        # The number of times the CopyingManager has blocked.
        self.__test_state_changes = 0
        # Whether or not the CopyingManager should stop.
        self.__test_stopping = False
        # Written by CopyingManager.  The last AddEventsRequest request passed into ``_send_events``.
        self.__captured_request = None
        # Protected by __test_state_cv.  The status message to return for the next call to ``_send_events``.
        self.__pending_response = None

        # This cv protects __advance_requests and is used mainly by the testing thread.
        self.__advance_requests_cv = threading.Condition()
        # This is incremented everytime the controller wants the CopyingManager to advance to the next blocking state,
        # regardless of which state it is in.
        self.__advance_requests = 0

        self.__controller = TestableCopyingManager.TestController(self)
示例#2
0
    def __init__(self, configuration, monitors):
        CopyingManager.__init__(self, configuration, monitors)
        # Approach:  We will override key methods of CopyingManager, blocking them from returning until the controller
        # tells it to proceed.  This allows us to then do things like write new log lines while the CopyingManager is
        # blocked.   Coordinating the communication between the two threads is done using one condition variable.
        # We changed the CopyingManager to block in three places: while it is sleeping before it starts a new loop,
        # when it invokes `_send_events` to send a new request, and when it blocks to receive the response.
        # These three states are referred to as 'sleeping', 'sending', 'responding'.
        #
        # The CopyingManager will have state to record where it should next block (i.e., if it should block at
        # 'sleeping' when it attempts to sleep).  The test controller will manipulate this state, notifying changes on
        # the condition variable. The CopyingManager will block in this state (and indicate it is blocked) until the
        # test controller sets a new state to block at.
        #
        # This cv protects all of the variables written by the CopyingManager thread.
        self.__test_state_cv = threading.Condition()
        # Which state the CopyingManager should block in -- "sleeping", "sending", "responding"
        # We initialize it to a special value "all" so that it stops as soon the CopyingManager starts up.
        self.__test_stop_state = 'all'
        # If not none, a state the test must pass through before it tries to stop at `__test_stop_state`.
        # If this transition is not observed by the time it does get to the stop state, an assertion is thrown.
        self.__test_required_transition = None
        # Whether or not the CopyingManager is stopped at __test_stop_state.
        self.__test_is_stopped = False
        # Written by CopyingManager.  The last AddEventsRequest request passed into ``_send_events``.
        self.__captured_request = None
        # Protected by __test_state_cv.  The status message to return for the next call to ``_send_events``.
        self.__pending_response = None

        self.__controller = TestableCopyingManager.TestController(self)
示例#3
0
    def __init__(self, configuration, monitors):
        CopyingManager.__init__(self, configuration, monitors)
        # Approach:  We will override key methods of CopyingManager, blocking them from returning until the controller
        # tells it to proceed.  This allows us to then do things like write new log lines while the CopyingManager is
        # blocked.   Coordinating the communication between the two threads is done using two condition variables.
        # We changed the CopyingManager to block in three places: while it is sleeping before it starts a new loop,
        # when it invokes ``_send_events`` to send a new request, and when it blocks to receive the response.
        # These three states or referred to as "sleeping", "blocked_on_send", "blocked_on_receive".
        #
        # This cv protects all of the variables written by the CopyingManager thread.
        self.__test_state_cv = threading.Condition()
        # Which state the CopyingManager is currently blocked in -- "sleeping", "blocked_on_send", "blocked_on_receive"
        self.__test_state = None
        # The number of times the CopyingManager has blocked.
        self.__test_state_changes = 0
        # Whether or not the CopyingManager should stop.
        self.__test_stopping = False
        # Written by CopyingManager.  The last AddEventsRequest request passed into ``_send_events``.
        self.__captured_request = None
        # Protected by __test_state_cv.  The status message to return for the next call to ``_send_events``.
        self.__pending_response = None

        # This cv protects __advance_requests and is used mainly by the testing thread.
        self.__advance_requests_cv = threading.Condition()
        # This is incremented everytime the controller wants the CopyingManager to advance to the next blocking state,
        # regardless of which state it is in.
        self.__advance_requests = 0

        self.__controller = TestableCopyingManager.TestController(self)
    def __create_test_instance(self, configuration_logs_entry,
                               monitors_log_configs):
        config_dir = tempfile.mkdtemp()
        config_file = os.path.join(config_dir, 'agentConfig.json')
        config_fragments_dir = os.path.join(config_dir, 'configs.d')
        os.makedirs(config_fragments_dir)

        logs_json_array = JsonArray()

        for entry in configuration_logs_entry:
            logs_json_array.add(JsonObject(content=entry))

        fp = open(config_file, 'w')
        fp.write(
            json_lib.serialize(JsonObject(api_key='fake',
                                          logs=logs_json_array)))
        fp.close()

        default_paths = DefaultPaths('/var/log/scalyr-agent-2',
                                     '/etc/scalyr-agent-2/agent.json',
                                     '/var/lib/scalyr-agent-2')

        config = Configuration(config_file, default_paths)
        config.parse()

        self.__monitor_fake_instances = []
        for monitor_log_config in monitors_log_configs:
            self.__monitor_fake_instances.append(
                FakeMonitor(monitor_log_config))

        # noinspection PyTypeChecker
        return CopyingManager(config, self.__monitor_fake_instances)
示例#5
0
 def test_get_server_attribute_no_override(self):
     logs_json_array = JsonArray()
     config = ScalyrTestUtils.create_configuration(
         extra_toplevel_config={'logs': logs_json_array})
     self.__monitor_fake_instances = []
     monitor_a = FakeMonitor1({'path': 'testA.log'},
                              id='a',
                              attribute_key='common_key')
     monitor_b = FakeMonitor1({'path': 'testB.log'},
                              id='b',
                              attribute_key='common_key')
     self.__monitor_fake_instances.append(monitor_a)
     self.__monitor_fake_instances.append(monitor_b)
     copy_manager = CopyingManager(config, self.__monitor_fake_instances)
     if monitor_a.access_order < monitor_b.access_order:
         first_accessed = monitor_a
         second_accessed = monitor_b
     else:
         first_accessed = monitor_b
         second_accessed = monitor_a
     self.assertLess(first_accessed.access_order,
                     second_accessed.access_order)
     self.assertEquals(
         copy_manager.expanded_server_attributes['common_key'],
         first_accessed.attribute_value)
示例#6
0
    def stop_manager(self, wait_on_join=True, join_timeout=5):
        """Stops the manager's thread.

        @param wait_on_join:  Whether or not to wait on thread to finish.
        @param join_timeout:  The number of seconds to wait on the join.
        @type wait_on_join: bool
        @type join_timeout: float
        @return:
        @rtype:
        """
        # We need to do some extra work here in case the CopyingManager thread is currently in a blocked state.
        # We need to tell it to keep running.
        self.__test_state_cv.acquire()
        self.__test_stop_state = None
        self.__test_state_cv.notifyAll()
        self.__test_state_cv.release()

        CopyingManager.stop_manager(self,
                                    wait_on_join=wait_on_join,
                                    join_timeout=join_timeout)
    def stop_manager(self, wait_on_join=True, join_timeout=5):
        """Stops the manager's thread.

        @param wait_on_join:  Whether or not to wait on thread to finish.
        @param join_timeout:  The number of seconds to wait on the join.
        @type wait_on_join: bool
        @type join_timeout: float
        @return:
        @rtype:
        """
        # We need to do some extra work here in case the CopyingManager thread is currently in a blocked state.
        # We need to tell it to advance.
        self.__test_state_cv.acquire()
        self.__test_stopping = True
        self.__test_state_cv.release()

        self.__advance_requests_cv.acquire()
        self.__advance_requests += 1
        self.__advance_requests_cv.notifyAll()
        self.__advance_requests_cv.release()

        CopyingManager.stop_manager(self, wait_on_join=wait_on_join, join_timeout=join_timeout)
示例#8
0
    def __create_test_instance(self, configuration_logs_entry, monitors_log_configs):
        logs_json_array = JsonArray()
        for entry in configuration_logs_entry:
            logs_json_array.add(JsonObject(content=entry))

        config = ScalyrTestUtils.create_configuration(extra_toplevel_config={'logs': logs_json_array})

        self.__monitor_fake_instances = []
        for monitor_log_config in monitors_log_configs:
            self.__monitor_fake_instances.append(FakeMonitor(monitor_log_config))

        # noinspection PyTypeChecker
        return CopyingManager(config, self.__monitor_fake_instances)
 def run_test():
     manager_poll_interval = 30
     fake_clock = FakeClock()
     monitors_manager, config = ScalyrTestUtils.create_test_monitors_manager(
         config_monitors=[{
             'module':
             "scalyr_agent.builtin_monitors.kubernetes_monitor",
         }],
         extra_toplevel_config={
             'user_agent_refresh_interval': manager_poll_interval
         },
         null_logger=True,
         fake_clock=fake_clock,
     )
     copying_manager = CopyingManager(config, monitors_manager.monitors)
示例#10
0
 def test_get_server_attribute(self):
     logs_json_array = JsonArray()
     config = ScalyrTestUtils.create_configuration(
         extra_toplevel_config={'logs': logs_json_array})
     self.__monitor_fake_instances = []
     monitor_a = FakeMonitor1({'path': 'testA.log'},
                              id='a',
                              attribute_key='KEY_a')
     monitor_b = FakeMonitor1({'path': 'testB.log'},
                              id='b',
                              attribute_key='KEY_b')
     self.__monitor_fake_instances.append(monitor_a)
     self.__monitor_fake_instances.append(monitor_b)
     copy_manager = CopyingManager(config, self.__monitor_fake_instances)
     attribs = copy_manager.expanded_server_attributes
     self.assertEquals(attribs['KEY_a'], monitor_a.attribute_value)
     self.assertEquals(attribs['KEY_b'], monitor_b.attribute_value)
 def test_get_server_attribute(self):
     logs_json_array = JsonArray()
     config = ScalyrTestUtils.create_configuration(
         extra_toplevel_config={"logs": logs_json_array})
     self.__monitor_fake_instances = []
     monitor_a = FakeMonitor1({"path": "testA.log"},
                              id="a",
                              attribute_key="KEY_a")
     monitor_b = FakeMonitor1({"path": "testB.log"},
                              id="b",
                              attribute_key="KEY_b")
     self.__monitor_fake_instances.append(monitor_a)
     self.__monitor_fake_instances.append(monitor_b)
     copy_manager = CopyingManager(config, self.__monitor_fake_instances)
     attribs = copy_manager.expanded_server_attributes
     self.assertEquals(attribs["KEY_a"], monitor_a.attribute_value)
     self.assertEquals(attribs["KEY_b"], monitor_b.attribute_value)
示例#12
0
 def run_test():
     manager_poll_interval = 30
     fake_clock = FakeClock()
     monitors_manager, config = ScalyrTestUtils.create_test_monitors_manager(
         config_monitors=[{
             "module":
             "scalyr_agent.builtin_monitors.kubernetes_monitor"
         }],
         extra_toplevel_config={
             "user_agent_refresh_interval": manager_poll_interval
         },
         null_logger=True,
         fake_clock=fake_clock,
     )
     copying_manager = CopyingManager(config, monitors_manager.monitors)
     self.assertEquals(
         copying_manager._CopyingManager__expanded_server_attributes.
         get("_k8s_ver"),
         "star",
     )
示例#13
0
    def __init__(self, configuration, monitors):
        CopyingManager.__init__(self, configuration, monitors)
        TestableCopyingManagerFlowController.__init__(self, configuration)

        # do this just to tell static analyzer that this is a testable instances.
        self._log_matchers = self._log_matchers  # type: List[TestableLogMatcher]
    def test_environment_aware_module_params(self, mock_docker):

        # Define test values here for all k8s and k8s_event monitor config params that are environment aware.
        # Be sure to use non-default test values
        TEST_INT = 123456789
        TEST_STRING = "dummy string"
        TEST_ARRAY_OF_STRINGS = ["s1", "s2", "s3"]
        STANDARD_PREFIX = "_STANDARD_PREFIX_"  # env var is SCALYR_<param_name>

        # The following map contains config params to be tested
        # config_param_name: (custom_env_name, test_value)
        docker_testmap = {
            "container_check_interval": (STANDARD_PREFIX, TEST_INT, int),
            "docker_api_version": (STANDARD_PREFIX, TEST_STRING, str),
            "docker_log_prefix": (STANDARD_PREFIX, TEST_STRING, str),
            "log_mode": ("SCALYR_DOCKER_LOG_MODE", TEST_STRING, str),
            "docker_raw_logs": (
                STANDARD_PREFIX,
                False,
                bool,
            ),  # test config file is set to True
            "docker_percpu_metrics": (
                STANDARD_PREFIX,
                True,
                bool,
            ),  # test config file is set to False
            "metrics_only": ("SCALYR_DOCKER_METRICS_ONLY", True, bool),
            "container_globs":
            (STANDARD_PREFIX, TEST_ARRAY_OF_STRINGS, ArrayOfStrings),
            "container_globs_exclude": (
                STANDARD_PREFIX,
                TEST_ARRAY_OF_STRINGS,
                ArrayOfStrings,
            ),
            "report_container_metrics": (STANDARD_PREFIX, False, bool),
            "label_include_globs": (
                STANDARD_PREFIX,
                TEST_ARRAY_OF_STRINGS,
                ArrayOfStrings,
            ),
            "label_exclude_globs": (
                STANDARD_PREFIX,
                TEST_ARRAY_OF_STRINGS,
                ArrayOfStrings,
            ),
            "labels_as_attributes": (STANDARD_PREFIX, True, bool),
            "label_prefix": (STANDARD_PREFIX, TEST_STRING, str),
            "use_labels_for_log_config": (STANDARD_PREFIX, False, bool),
        }

        # Fake the environment varaibles
        for key, value in docker_testmap.items():
            custom_name = value[0]
            env_name = (("SCALYR_%s" % key).upper() if custom_name
                        == STANDARD_PREFIX else custom_name.upper())
            envar_value = str(value[1])
            if value[2] == ArrayOfStrings:
                # Array of strings should be entered into environment in the user-preferred format
                # which is without square brackets and quotes around each element
                envar_value = envar_value[1:-1]  # strip square brackets
                envar_value = envar_value.replace("'", "")
            else:
                envar_value = (envar_value.lower()
                               )  # lower() needed for proper bool encoding
            os.environ[env_name] = envar_value

        self._write_file_with_separator_conversion(""" {
            logs: [ { path:"/var/log/tomcat6/$DIR_VAR.log" }],
            api_key: "abcd1234",
        }
        """)
        self._write_config_fragment_file_with_separator_conversion(
            "docker.json",
            """ {
            "monitors": [
                {
                    module: "scalyr_agent.builtin_monitors.docker_monitor",
                    docker_raw_logs: true
                }
            ]
        }
        """,
        )

        config = self._create_test_configuration_instance()
        config.parse()

        monitors_manager, mock_logger = self._make_monitors_manager(config)
        docker_monitor = monitors_manager.monitors[0]

        # All environment-aware params defined in the docker monitor must be gested
        self.assertEquals(
            set(docker_testmap.keys()),
            set(docker_monitor._config._environment_aware_map.keys()),
        )

        # Verify module-level conflicts between env var and config file are logged at module-creation time
        mock_logger.warn.assert_called_with(
            "Conflicting values detected between scalyr_agent.builtin_monitors.docker_monitor config file "
            "parameter `docker_raw_logs` and the environment variable `SCALYR_DOCKER_RAW_LOGS`. "
            "Ignoring environment variable.",
            limit_once_per_x_secs=300,
            limit_key=
            "config_conflict_scalyr_agent.builtin_monitors.docker_monitor_docker_raw_logs_SCALYR_DOCKER_RAW_LOGS",
        )

        CopyingManager(config, monitors_manager.monitors)
        # Override Agent Logger to prevent writing to disk
        for monitor in monitors_manager.monitors:
            monitor._logger = FakeAgentLogger("fake_agent_logger")

        # Verify environment variable values propagate into DockerMonitor monitor MonitorConfig
        monitor_2_testmap = {
            docker_monitor: docker_testmap,
        }
        for monitor, testmap in monitor_2_testmap.items():
            for key, value in testmap.items():
                test_val, convert_to = value[1:]
                if key in ["docker_raw_logs"]:
                    # Keys were defined in config files so should not have changed
                    self.assertNotEquals(
                        test_val,
                        monitor._config.get(key, convert_to=convert_to))
                else:
                    # Keys were empty in config files so they take on environment values
                    materialized_value = monitor._config.get(
                        key, convert_to=convert_to)
                    if hasattr(test_val, "__iter__"):
                        self.assertEquals([x1 for x1 in test_val],
                                          [x2 for x2 in materialized_value])
                    else:
                        self.assertEquals(test_val, materialized_value)
示例#15
0
    def test_environment_aware_module_params(self, mock_docker):

        # Define test values here for all k8s and k8s_event monitor config params that are environment aware.
        # Be sure to use non-default test values
        TEST_INT = 123456789
        TEST_FLOAT = 1234567.89
        TEST_STRING = "dummy string"
        TEST_PARSE_FORMAT = "cri"
        TEST_ARRAY_OF_STRINGS = ["s1", "s2", "s3"]
        STANDARD_PREFIX = "_STANDARD_PREFIX_"  # env var is SCALYR_<param_name>

        # The following map contains config params to be tested
        # config_param_name: (custom_env_name, test_value)
        k8s_testmap = {
            "container_check_interval": (STANDARD_PREFIX, TEST_INT, int),
            "initial_stopped_container_collection_window": (
                STANDARD_PREFIX,
                TEST_INT,
                int,
            ),
            "docker_max_parallel_stats": (STANDARD_PREFIX, TEST_INT, int),
            "docker_percpu_metrics": (STANDARD_PREFIX, True, bool),
            "container_globs":
            (STANDARD_PREFIX, TEST_ARRAY_OF_STRINGS, ArrayOfStrings),
            "report_container_metrics": (STANDARD_PREFIX, False, bool),
            "report_k8s_metrics": (STANDARD_PREFIX, True, bool),
            "k8s_ignore_pod_sandboxes": (STANDARD_PREFIX, False, bool),
            "k8s_include_all_containers": (STANDARD_PREFIX, False, bool),
            "k8s_sidecar_mode": (STANDARD_PREFIX, True, bool),
            "k8s_parse_format":
            (STANDARD_PREFIX, TEST_PARSE_FORMAT, six.text_type),
            "k8s_always_use_cri": (STANDARD_PREFIX, True, bool),
            "k8s_cri_query_filesystem": (STANDARD_PREFIX, True, bool),
            "k8s_always_use_docker": (STANDARD_PREFIX, True, bool),
            "k8s_kubelet_host_ip": (STANDARD_PREFIX, False, bool),
            "k8s_kubelet_api_url_template": (STANDARD_PREFIX, False, bool),
            "gather_k8s_pod_info": (STANDARD_PREFIX, True, bool),
        }

        k8s_events_testmap = {
            "max_log_size": ("SCALYR_K8S_MAX_LOG_SIZE", TEST_INT, int),
            "max_log_rotations":
            ("SCALYR_K8S_MAX_LOG_ROTATIONS", TEST_INT, int),
            "log_flush_delay":
            ("SCALYR_K8S_LOG_FLUSH_DELAY", TEST_FLOAT, float),
            "message_log":
            ("SCALYR_K8S_MESSAGE_LOG", TEST_STRING, six.text_type),
            "event_object_filter": (
                "SCALYR_K8S_EVENT_OBJECT_FILTER",
                TEST_ARRAY_OF_STRINGS,
                ArrayOfStrings,
            ),
            "leader_check_interval": (
                "SCALYR_K8S_LEADER_CHECK_INTERVAL",
                TEST_INT,
                int,
            ),
            "leader_node":
            ("SCALYR_K8S_LEADER_NODE", TEST_STRING, six.text_type),
            "check_labels": ("SCALYR_K8S_CHECK_LABELS", True, bool),
            "ignore_master": ("SCALYR_K8S_IGNORE_MASTER", False, bool),
        }

        # Fake the environment variables
        for map in [k8s_testmap, k8s_events_testmap]:
            for key, value in map.items():
                custom_name = value[0]
                env_name = (("SCALYR_%s" % key).upper() if custom_name
                            == STANDARD_PREFIX else custom_name.upper())
                param_value = value[1]
                if value[2] == ArrayOfStrings:
                    # Array of strings should be entered into environment in the user-preferred format
                    # which is without square brackets and quotes around each element
                    envar_value = "[{0}]".format(", ".join(param_value))
                else:
                    envar_value = six.text_type(param_value)
                    envar_value = (envar_value.lower()
                                   )  # lower() needed for proper bool encoding
                os.environ[env_name] = envar_value

        self._write_file_with_separator_conversion(""" {
            logs: [ { path:"/var/log/tomcat6/$DIR_VAR.log" }],
            api_key: "abcd1234",
        }
        """)
        self._write_config_fragment_file_with_separator_conversion(
            "k8s.json",
            """ {
            "monitors": [
                {
                    "module": "scalyr_agent.builtin_monitors.kubernetes_monitor",
                    "report_k8s_metrics": false,
                },
                {
                    "module": "scalyr_agent.builtin_monitors.kubernetes_events_monitor"
                }
            ]
        }
        """,
        )

        monitors_manager, config, mock_logger = self._create_test_objects()
        k8s_monitor = monitors_manager.monitors[0]
        k8s_events_monitor = monitors_manager.monitors[1]

        # All environment-aware params defined in the k8s and k8s_events monitors must be tested
        self.assertEquals(
            set(k8s_testmap.keys()),
            set(k8s_monitor._config._environment_aware_map.keys()),
        )

        self.assertEquals(
            set(k8s_events_testmap.keys()),
            set(k8s_events_monitor._config._environment_aware_map.keys()),
        )

        # Verify module-level conflicts between env var and config file are logged at module-creation time
        mock_logger.warn.assert_called_with(
            "Conflicting values detected between scalyr_agent.builtin_monitors.kubernetes_monitor config file "
            "parameter `report_k8s_metrics` and the environment variable `SCALYR_REPORT_K8S_METRICS`. "
            "Ignoring environment variable.",
            limit_once_per_x_secs=300,
            limit_key=
            "config_conflict_scalyr_agent.builtin_monitors.kubernetes_monitor_report_k8s_metrics_SCALYR_REPORT_K8S_METRICS",
        )

        CopyingManager(config, monitors_manager.monitors)
        # Override Agent Logger to prevent writing to disk
        for monitor in monitors_manager.monitors:
            monitor._logger = FakeAgentLogger("fake_agent_logger")

        # Verify environment variable values propagate into kubernetes monitor MonitorConfig
        monitor_2_testmap = {
            k8s_monitor: k8s_testmap,
            k8s_events_monitor: k8s_events_testmap,
        }
        for monitor, testmap in monitor_2_testmap.items():
            for key, value in testmap.items():
                test_val, convert_to = value[1:]
                if key in ["report_k8s_metrics", "api_key"]:
                    # Keys were defined in config files so should not have changed
                    self.assertNotEquals(
                        test_val,
                        monitor._config.get(key, convert_to=convert_to))
                else:
                    # Keys were empty in config files so they take on environment values
                    materialized_value = monitor._config.get(
                        key, convert_to=convert_to)
                    if hasattr(test_val, "__iter__"):
                        self.assertEquals([x1 for x1 in test_val],
                                          [x2 for x2 in materialized_value])
                    else:
                        self.assertEquals(test_val, materialized_value)