Пример #1
0
 def test_alert_rule_resolved_invalid(self):
     self.run_fail_validation_test(
         {"resolve_threshold": 500},
         {
             "nonFieldErrors": [
                 "critical alert threshold must be above resolution threshold"
             ]
         },
     )
     base_params = self.valid_params.copy()
     base_params["resolve_threshold"] = 0.5
     base_params["triggers"].pop()
     base_params["triggers"][0]["alertThreshold"] = 0.3
     serializer = AlertRuleSerializer(context=self.context,
                                      data=base_params)
     assert not serializer.is_valid()
     assert serializer.errors == {
         "nonFieldErrors":
         ["critical alert threshold must be above resolution threshold"]
     }
Пример #2
0
 def test_comparison_delta_above(self):
     params = self.valid_params.copy()
     params["comparison_delta"] = 60
     params["resolveThreshold"] = 10
     params["triggers"][0]["alertThreshold"] = 50
     params["triggers"][1]["alertThreshold"] = 40
     serializer = AlertRuleSerializer(context=self.context,
                                      data=params,
                                      partial=True)
     assert serializer.is_valid(), serializer.errors
     alert_rule = serializer.save()
     assert alert_rule.comparison_delta == 60 * 60
     assert alert_rule.resolve_threshold == 110
     triggers = {
         trigger.label: trigger
         for trigger in alert_rule.alertruletrigger_set.all()
     }
     assert triggers["critical"].alert_threshold == 150
     assert triggers["warning"].alert_threshold == 140
     assert alert_rule.snuba_query.resolution == DEFAULT_CMP_ALERT_RULE_RESOLUTION * 60
Пример #3
0
    def post(self, request, project):
        """
        Create an alert rule
        """
        if not features.has('organizations:incidents',
                            project.organization,
                            actor=request.user):
            raise ResourceDoesNotExist

        serializer = AlertRuleSerializer(
            context={'project': project},
            data=request.data,
        )

        if serializer.is_valid():
            alert_rule = serializer.save()
            return Response(serialize(alert_rule, request.user),
                            status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Пример #4
0
    def test_invalid_slack_channel(self):
        # We had an error where an invalid slack channel was spitting out unclear
        # error for the user, and CREATING THE RULE. So the next save (after fixing slack action)
        # says "Name already in use". This test makes sure that is not happening anymore.
        # We save a rule with an invalid slack, make sure we get back a useful error
        # and that the rule is not created.
        base_params = self.valid_params.copy()
        base_params["name"] = "Aun1qu3n4m3"
        integration = Integration.objects.create(
            external_id="1",
            provider="slack",
            metadata={
                "access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"
            },
        )
        integration.add_organization(self.organization, self.user)
        base_params["triggers"][0]["actions"].append({
            "type":
            AlertRuleTriggerAction.get_registered_type(
                AlertRuleTriggerAction.Type.SLACK).slug,
            "targetType":
            action_target_type_to_string[
                AlertRuleTriggerAction.TargetType.SPECIFIC],
            "targetIdentifier":
            "123",
            "integration":
            six.text_type(integration.id),
        })
        serializer = AlertRuleSerializer(context=self.context,
                                         data=base_params)
        assert serializer.is_valid()
        with self.assertRaises(serializers.ValidationError):
            serializer.save()

        # Make sure the rule was not created.
        assert len(list(AlertRule.objects.filter(name="Aun1qu3n4m3"))) == 0

        # Make sure the action was not created.
        alert_rule_trigger_actions = list(
            AlertRuleTriggerAction.objects.filter(integration=integration))
        assert len(alert_rule_trigger_actions) == 0
Пример #5
0
 def test_aggregate(self):
     self.run_fail_validation_test(
         {"aggregate": "what()"},
         {"aggregate": ["Invalid Metric: what() is not a valid function"]},
     )
     self.run_fail_validation_test(
         {"aggregate": "what"},
         {
             "nonFieldErrors": [
                 "Invalid Metric: Please pass a valid function for aggregation"
             ]
         },
     )
     self.run_fail_validation_test(
         {"aggregate": "123"},
         {
             "nonFieldErrors": [
                 "Invalid Metric: Please pass a valid function for aggregation"
             ]
         },
     )
     self.run_fail_validation_test(
         {"aggregate": "count_unique(123, hello)"},
         {
             "aggregate": [
                 "Invalid Metric: count_unique(123, hello): expected 1 arguments"
             ]
         },
     )
     self.run_fail_validation_test(
         {"aggregate": "max()"},
         {"aggregate": ["Invalid Metric: max(): expected 1 arguments"]})
     aggregate = "count_unique(tags[sentry:user])"
     base_params = self.valid_params.copy()
     base_params["aggregate"] = aggregate
     serializer = AlertRuleSerializer(context=self.context,
                                      data=base_params)
     assert serializer.is_valid(), serializer.errors
     alert_rule = serializer.save()
     assert alert_rule.snuba_query.aggregate == aggregate
    def test_alert_rule_threshold_resolve_only(self):
        resolve_threshold = 10
        payload = {
            "name":
            "hello_im_a_test",
            "time_window":
            10,
            "query":
            "level:error",
            "aggregate":
            "count()",
            "thresholdType":
            0,
            "resolveThreshold":
            10,
            "threshold_period":
            1,
            "projects": [self.project.slug],
            "triggers": [{
                "label":
                "critical",
                "alertThreshold":
                98,
                "actions": [{
                    "type": "email",
                    "targetType": "team",
                    "targetIdentifier": self.team.id
                }],
            }],
        }
        serializer = AlertRuleSerializer(context=self.context,
                                         data=payload,
                                         partial=True)

        assert serializer.is_valid(), serializer.errors
        assert serializer.validated_data[
            "threshold_type"] == AlertRuleThresholdType.ABOVE
        assert serializer.validated_data[
            "resolve_threshold"] == resolve_threshold
Пример #7
0
    def post(self, request, project):
        """
        Create an alert rule
        """
        if not features.has("organizations:incidents", project.organization, actor=request.user):
            raise ResourceDoesNotExist

        data = deepcopy(request.data)
        data["projects"] = [project.slug]

        serializer = AlertRuleSerializer(
            context={"organization": project.organization, "access": request.access}, data=data
        )

        if serializer.is_valid():
            alert_rule = serializer.save()
            alert_rule_created.send_robust(
                user=request.user, project=project, rule=alert_rule, rule_type="metric", sender=self
            )
            return Response(serialize(alert_rule, request.user), status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 def test_invalid_team_with_channel_timeout(self, mock_get_channel_id):
     self.setup_slack_integration()
     other_org = self.create_organization()
     new_team = self.create_team(organization=other_org)
     trigger = {
         "label":
         "critical",
         "alertThreshold":
         200,
         "actions": [
             {
                 "type": "slack",
                 "targetIdentifier": "my-channel",
                 "targetType": "specific",
                 "integration": self.integration.id,
             },
             {
                 "type": "email",
                 "targetType": "team",
                 "targetIdentifier": new_team.id
             },
         ],
     }
     base_params = self.valid_params.copy()
     base_params.update({"triggers": [trigger]})
     serializer = AlertRuleSerializer(context=self.context,
                                      data=base_params)
     # error is raised during save
     assert serializer.is_valid()
     with self.assertRaises(serializers.ValidationError) as err:
         serializer.save()
     assert err.exception.detail == {
         "nonFieldErrors": ["Team does not exist"]
     }
     mock_get_channel_id.assert_called_with(self.integration, "my-channel",
                                            10)
    def post(self, request: Request, organization) -> Response:
        """
        Create an alert rule
        """

        if not features.has(
                "organizations:incidents", organization, actor=request.user):
            raise ResourceDoesNotExist

        serializer = AlertRuleSerializer(
            context={
                "organization": organization,
                "access": request.access,
                "user": request.user
            },
            data=request.data,
        )

        if serializer.is_valid():
            alert_rule = serializer.save()
            return Response(serialize(alert_rule, request.user),
                            status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Пример #10
0
 def run_fail_validation_test(self, params, errors):
     base_params = self.valid_params.copy()
     base_params.update(params)
     serializer = AlertRuleSerializer(context=self.context, data=base_params)
     assert not serializer.is_valid()
     assert serializer.errors == errors
Пример #11
0
    def test_boundary(self):
        payload = {
            "name":
            "hello_im_a_test",
            "time_window":
            10,
            "query":
            "level:error",
            "threshold_type":
            0,
            "aggregation":
            0,
            "threshold_period":
            1,
            "projects": [self.project.slug],
            "triggers": [{
                "label":
                "critical",
                "alertThreshold":
                1,
                "resolveThreshold":
                2,
                "thresholdType":
                AlertRuleThresholdType.ABOVE.value,
                "actions": [{
                    "type": "email",
                    "targetType": "team",
                    "targetIdentifier": self.team.id
                }],
            }],
        }
        serializer = AlertRuleSerializer(context=self.context,
                                         data=payload,
                                         partial=True)

        assert serializer.is_valid(), serializer.errors

        # Now do a two trigger test:
        payload["triggers"].append({
            "label":
            "warning",
            "alertThreshold":
            0,
            "resolveThreshold":
            1,
            "thresholdType":
            AlertRuleThresholdType.ABOVE.value,
            "actions": [
                {
                    "type": "email",
                    "targetType": "team",
                    "targetIdentifier": self.team.id
                },
                {
                    "type": "email",
                    "targetType": "user",
                    "targetIdentifier": self.user.id
                },
            ],
        })

        serializer = AlertRuleSerializer(context=self.context,
                                         data=payload,
                                         partial=True)

        assert serializer.is_valid(), serializer.errors
Пример #12
0
def find_channel_id_for_alert_rule(organization_id,
                                   uuid,
                                   data,
                                   alert_rule_id=None,
                                   user_id=None):
    redis_rule_status = RedisRuleStatus(uuid)
    try:
        organization = Organization.objects.get(id=organization_id)
    except Organization.DoesNotExist:
        redis_rule_status.set_value("failed")
        return

    user = None
    if user_id:
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            pass

    alert_rule = None
    if alert_rule_id:
        try:
            alert_rule = AlertRule.objects.get(organization_id=organization_id,
                                               id=alert_rule_id)
        except AlertRule.DoesNotExist:
            redis_rule_status.set_value("failed")
            return

    try:
        mapped_ids = get_slack_channel_ids(organization, user, data)
    except (serializers.ValidationError, ChannelLookupTimeoutError,
            InvalidTriggerActionError) as e:
        # channel doesn't exist error or validation error
        logger.info(
            "get_slack_channel_ids.failed",
            extra={
                "exception": e,
            },
        )
        redis_rule_status.set_value("failed")
        return

    for trigger in data["triggers"]:
        for action in trigger["actions"]:
            if action["type"] == "slack":
                if action["targetIdentifier"] in mapped_ids:
                    action["input_channel_id"] = mapped_ids[
                        action["targetIdentifier"]]
                else:
                    # We can early exit because we couldn't map this action's slack channel name to a slack id
                    # This is a fail safe, but I think we shouldn't really hit this.
                    redis_rule_status.set_value("failed")
                    return

    # we use SystemAccess here because we can't pass the access instance from the request into the task
    # this means at this point we won't raise any validation errors associated with permissions
    # however, we should only be calling this task after we tried saving the alert rule first
    # which will catch those kinds of validation errors
    serializer = AlertRuleSerializer(
        context={
            "organization": organization,
            "access": SystemAccess(),
            "user": user,
            "use_async_lookup": True,
            "validate_channel_id": False,
        },
        data=data,
        instance=alert_rule,
    )
    if serializer.is_valid():
        try:
            alert_rule = serializer.save()
            redis_rule_status.set_value("success", alert_rule.id)
            return
        # we can still get a validation error for the channel not existing
        except (serializers.ValidationError, ChannelLookupTimeoutError):
            # channel doesn't exist error or validation error
            redis_rule_status.set_value("failed")
            return
    # some other error
    redis_rule_status.set_value("failed")
    return
Пример #13
0
 def test_transaction_dataset(self):
     serializer = AlertRuleSerializer(context=self.context, data=self.valid_transaction_params)
     assert serializer.is_valid(), serializer.errors
     alert_rule = serializer.save()
     assert alert_rule.snuba_query.dataset == QueryDatasets.TRANSACTIONS.value
     assert alert_rule.snuba_query.aggregate == "count()"