def test_str_conversion(self):
        self.assertEquals(self.get(1, convert_to=six.text_type), "1")
        self.assertEquals(self.get("ah", convert_to=six.text_type), "ah")
        self.assertEquals(self.get(False, convert_to=six.text_type), "False")
        self.assertEquals(self.get(1.3, convert_to=six.text_type), "1.3")
        self.assertEquals(self.get(1, convert_to=six.text_type), "1")

        test_array = ["a", "b", "c"]

        # str -> ArrayOfStrings (must support different variations)
        arr = ArrayOfStrings(test_array)
        self.assertEquals(self.get("a,b,c", convert_to=ArrayOfStrings), arr)
        self.assertEquals(self.get("a,b,  c", convert_to=ArrayOfStrings), arr)
        self.assertEquals(self.get('"a", "b", "c"', convert_to=ArrayOfStrings),
                          arr)
        self.assertEquals(self.get("'a', 'b', 'c'", convert_to=ArrayOfStrings),
                          arr)
        self.assertEquals(self.get("[a, b, c]", convert_to=ArrayOfStrings),
                          arr)
        self.assertEquals(
            self.get("['a', \"b\", c]", convert_to=ArrayOfStrings), arr)

        # str -> JsonArray
        self.assertEquals(
            self.get(scalyr_util.json_encode(test_array),
                     convert_to=JsonArray),
            JsonArray(*test_array),
        )
        self.assertRaises(
            BadMonitorConfiguration,
            # single quotes are invalid JSON
            lambda: self.assertEquals(
                self.get(six.text_type(test_array), convert_to=JsonArray),
                JsonArray(*test_array),
            ),
        )

        # str -> JsonObject
        test_obj = {"a": 1, "b": "two", "c": [1, 2, 3]}
        self.assertEquals(
            self.get(scalyr_util.json_encode(test_obj), convert_to=JsonObject),
            scalyr_util.json_scalyr_config_decode(
                scalyr_util.json_encode(test_obj)),
        )
Example #2
0
def run_standalone_monitor(
    monitor_module,
    monitor_python_path,
    monitor_config,
    monitor_sample_interval,
    monitor_debug_level,
    global_config_path,
):
    """Runs a single plugin monitor instance.

    @param monitor_module: The name of the python module implementing the monitor.
    @param monitor_python_path: The python path to search to find the module.
    @param monitor_config: The monitor configuration object.
    @param monitor_sample_interval: The default to use for the sample interval.
    @param monitor_debug_level: The debug level to use for logging.
    @param global_config_path:  The path to the agent.json global configuration file to use, or None if none was
        supplied.
    """
    scalyr_logging.set_log_destination(use_stdout=True)
    scalyr_logging.set_log_level(monitor_debug_level)

    log.log(scalyr_logging.DEBUG_LEVEL_1, "Attempting to run module %s",
            monitor_module)

    try:
        # Needs to be json_lib.parse because it is parsing configuration
        parsed_config = scalyr_util.json_scalyr_config_decode(monitor_config)
        log.log(scalyr_logging.DEBUG_LEVEL_1,
                "Parsed configuration successfully")
    except JsonParseException as e:
        print(
            "Failed to parse the monitor configuration as valid JSON: %s",
            six.text_type(e),
            file=sys.stderr,
        )
        return 1

    parsed_config["module"] = monitor_module
    if "id" not in parsed_config:
        parsed_config["id"] = ""

    # noinspection PyUnusedLocal
    def handle_shutdown_signal(signum, frame):
        print("Signal received, stopping monitor...", file=sys.stdout)
        monitor.stop()

    for sig in (signal.SIGTERM, signal.SIGINT):
        signal.signal(sig, handle_shutdown_signal)

    try:
        if global_config_path is not None:
            controller = PlatformController.new_platform()
            paths = controller.default_paths
            global_config = Configuration(global_config_path, paths, log)
            global_config.parse()
        else:
            global_config = None
        monitor = MonitorsManager.build_monitor(
            parsed_config,
            monitor_python_path,
            float(monitor_sample_interval),
            global_config,
        )
        log.log(scalyr_logging.DEBUG_LEVEL_1, "Constructed monitor")
        monitor.open_metric_log()
        log.log(scalyr_logging.DEBUG_LEVEL_1, "Starting monitor")
        monitor.start()

        while monitor.isAlive():
            time.sleep(0.1)
    except BadMonitorConfiguration as e:
        print("Invalid monitor configuration: %s" % six.text_type(e),
              file=sys.stderr)

    return 0
Example #3
0
def convert_config_param(field_name, value, convert_to, is_environment_variable=False):
    """Convert monitor config values to a different type according to the ALLOWED_CONVERSIONS matrix

    None is an invalid input and will raise BadConfiguration error.
    Empty strings will convert into str, bool, ArrayOfStrings, SpaceAndCommaSeparatedArrayOfStrings but raises
        exception for int, float, JsonArray, JsonObject

    """
    convert_from = type(value)

    kind = "environment variable"
    if not is_environment_variable:
        kind = "config param"

    conversion_allowed = False
    if convert_from in ALLOWED_CONVERSIONS:
        if convert_to in set([convert_from]) | ALLOWED_CONVERSIONS[convert_from]:
            conversion_allowed = True

    if not conversion_allowed:
        raise BadConfiguration(
            'Prohibited conversion of %s "%s" from %s to %s'
            % (kind, field_name, convert_from, convert_to),
            field_name,
            "illegalConversion",
        )

    # If no type change, simply return unconverted value
    if convert_from == convert_to:
        return value

    # Anything is allowed to go to str/unicode
    if convert_to in STRING_TYPES:
        return convert_to(value)

    if convert_from == list and convert_to == JsonArray:
        try:
            return JsonArray(*value)
        except JsonConversionException:
            raise BadConfiguration(
                'Could not convert value %s for field "%s" from %s to %s'
                % (value, field_name, convert_from, convert_to),
                field_name,
                "notJsonArray",
            )

    if convert_from in (list, JsonArray) and convert_to in (
        ArrayOfStrings,
        SpaceAndCommaSeparatedArrayOfStrings,
    ):
        list_of_strings = []
        for item in value:
            if type(item) not in STRING_TYPES:
                raise BadConfiguration(
                    'Non-string element found in value %s for field "%s"'
                    % (value, field_name),
                    field_name,
                    "notArrayOfStrings",
                )
            list_of_strings.append(item)
        return convert_to(list_of_strings)

    # Anything is allowed to go from string/unicode to the conversion type, as long as it can be parsed.
    # Special-case handle bool and JsonArray
    if convert_from in STRING_TYPES:

        if convert_to == bool:
            return six.text_type(value).lower() == "true"

        elif convert_to in (JsonArray, JsonObject):
            try:
                # Special case for empty objects
                if convert_to == JsonObject and not value:
                    return JsonObject()
                # Needs to be json_lib.parse since it is parsing configuration.
                return scalyr_util.json_scalyr_config_decode(value)
            except JsonParseException:
                raise BadConfiguration(
                    'Could not parse value %s for field "%s" as %s'
                    % (value, field_name, convert_to),
                    field_name,
                    "notJsonObject",
                )

        elif convert_to in (ArrayOfStrings, SpaceAndCommaSeparatedArrayOfStrings):
            try:
                # ArrayOfStrings and it's
                return parse_array_of_strings(value, convert_to.separators)
            except TypeError:
                raise BadConfiguration(
                    'Could not parse value %s for field "%s" as %s'
                    % (value, field_name, convert_to),
                    field_name,
                    "notArrayOfStrings",
                )

        elif convert_to in NUMERIC_TYPES:
            try:
                return convert_to(value)
            except ValueError:
                raise BadConfiguration(
                    'Could not parse value %s for field "%s" as numeric type %s'
                    % (value, field_name, convert_to),
                    field_name,
                    "notNumber",
                )

    if convert_from not in NUMERIC_TYPES:
        raise BadConfiguration(
            'Type conversion for field "%s" from %s to %s not implemented.'
            % (field_name, convert_from, convert_to),
            field_name,
            "notNumber",
        )

    if convert_to == bool:
        raise BadConfiguration(
            'A numeric value %s was given for boolean field "%s"' % (value, field_name),
            field_name,
            "notBoolean",
        )

    if convert_to not in NUMERIC_TYPES:
        raise BadConfiguration(
            'Type conversion for field "%s" from %s to %s not implemented.'
            % (field_name, convert_from, convert_to),
            field_name,
            "unsupportedConversion",
        )

    # At this point, we are trying to convert a number to another number type.  We only allow int to long
    # and long, int to float.
    if convert_to == float and convert_from in six.integer_types:
        return float(value)
    if convert_to in six.integer_types:
        return int(value)

    raise BadConfiguration(
        'A numeric value of %s was given for field "%s" but a %s is required.'
        % (value, field_name, convert_to),
        field_name,
        "wrongType",
    )