Skip to content

Commit

Permalink
Merge pull request #776 from grafana/dev
Browse files Browse the repository at this point in the history
Release new helm chart version 1.0.9 (v1.0.50)
  • Loading branch information
mderynck authored Nov 5, 2022
2 parents fee1235 + 6109c7b commit 144abaa
Show file tree
Hide file tree
Showing 35 changed files with 1,358 additions and 767 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## v1.0.51 (2022-11-05)

- Bug Fixes

## v1.0.50 (2022-11-03)

- Updates to documentation
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ PYTEST = $(ENV)/bin/pytest
DOCKER_FILE ?= docker-compose-developer.yml

define setup_engine_env
export `grep -v '^#' .env | xargs -0` && cd engine
export `grep -v '^#' .env.dev | xargs -0` && cd engine
endef

$(ENV):
Expand Down
2 changes: 0 additions & 2 deletions docs/sources/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,4 @@ Grafana OnCall is an open source incident response management tool built to help
- **Massive scalability:** Grafana OnCall is equipped with a full API and Terraform capabilities. Ready for GitOps and large organization configuration.


> **Note:** You can use [Grafana Cloud](https://grafana.com/products/cloud/?plcmt=nav-products-cta1&cta=cloud) to avoid installing, maintaining, and scaling your own instance of Grafana OnCall. The free forever plan includes 30 Grafana OnCall notification. [Create an account to get started](https://grafana.com/auth/sign-up/create-user?pg=oncall&plcmt=hero-btn-1).
{{< section >}}
3 changes: 3 additions & 0 deletions docs/sources/alert-behavior/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ Once Grafana OnCall receives an alert, the following occurs, based on the alert
- Default or customized alert templates are applied to deliver the most useful alert fields with the most valuable information, in a readable format.
- Alerts are grouped based on your alert grouping configurations, combining similar or related alerts to reduce alert noise.
- Alerts automatically resolve if an alert from the monitoring system matches the resolve condition for that alert.


{{< section >}}
5 changes: 1 addition & 4 deletions docs/sources/get-started/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ These procedures introduce you to initial Grafana OnCall configuration steps, in

## Before you begin

Grafana OnCall is available for Grafana Cloud as well as Grafana open source users. You must have a Grafana Cloud account or [Open Source Grafana OnCall]({{< relref "../open-source" >}})

For more information, see [Grafana Pricing](https://grafana.com/pricing/) for details.

Grafana OnCall is available for Grafana Cloud as well as Grafana open source users. You must have a Grafana Cloud account or use [Open Source Grafana OnCall]({{< relref "../open-source" >}})

## Install Open Source Grafana OnCall

Expand Down
2 changes: 1 addition & 1 deletion engine/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.9-alpine
FROM python:3.9-alpine3.16
RUN apk add bash python3-dev build-base linux-headers pcre-dev mariadb-connector-c-dev openssl-dev libffi-dev git
RUN pip install uwsgi

Expand Down
4 changes: 2 additions & 2 deletions engine/apps/alerts/models/alert_receive_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from django.utils import timezone
from django.utils.crypto import get_random_string
from emoji import emojize
from jinja2 import Template

from apps.alerts.grafana_alerting_sync_manager.grafana_alerting_sync import GrafanaAlertingSyncManager
from apps.alerts.integration_options_mixin import IntegrationOptionsMixin
Expand All @@ -29,6 +28,7 @@
from common.api_helpers.utils import create_engine_url
from common.exceptions import TeamCanNotBeChangedError, UnableToSendDemoAlert
from common.insight_log import EntityEvent, write_resource_insight_log
from common.jinja_templater import jinja_template_env
from common.public_primary_keys import generate_public_primary_key, increase_public_primary_key_length

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -360,7 +360,7 @@ def is_demo_alert_enabled(self):
def description(self):
if self.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING:
contact_points = self.contact_points.all()
rendered_description = Template(self.config.description).render(
rendered_description = jinja_template_env.from_string(self.config.description).render(
is_finished_alerting_setup=self.is_finished_alerting_setup,
grafana_alerting_entities=[
{
Expand Down
4 changes: 2 additions & 2 deletions engine/apps/alerts/models/custom_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
from django.db import models
from django.db.models import F
from django.utils import timezone
from jinja2 import Template
from requests.auth import HTTPBasicAuth

from common.jinja_templater import jinja_template_env
from common.public_primary_keys import generate_public_primary_key, increase_public_primary_key_length

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -103,7 +103,7 @@ def build_post_kwargs(self, alert):
if self.forward_whole_payload:
post_kwargs["json"] = alert.raw_request_data
elif self.data:
rendered_data = Template(self.data).render(
rendered_data = jinja_template_env.from_string(self.data).render(
{
"alert_payload": self._escape_alert_payload(alert.raw_request_data),
"alert_group_id": alert.group.public_primary_key,
Expand Down
5 changes: 3 additions & 2 deletions engine/apps/api/serializers/custom_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
from collections import defaultdict

from django.core.validators import URLValidator, ValidationError
from jinja2 import Template, TemplateError
from jinja2 import TemplateError
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator

from apps.alerts.models import CustomButton
from common.api_helpers.custom_fields import TeamPrimaryKeyRelatedField
from common.api_helpers.utils import CurrentOrganizationDefault, CurrentTeamDefault
from common.jinja_templater import jinja_template_env


class CustomButtonSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -52,7 +53,7 @@ def validate_data(self, data):
return None

try:
template = Template(data)
template = jinja_template_env.from_string(data)
except TemplateError:
raise serializers.ValidationError("Data has incorrect template")

Expand Down
6 changes: 5 additions & 1 deletion engine/apps/api/serializers/on_call_shifts.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,12 @@ def _validate_frequency(self, frequency, event_type, rolling_users, interval, by
raise serializers.ValidationError(
{"frequency": ["Cannot set 'frequency' for shifts with type 'override'"]}
)
if frequency != CustomOnCallShift.FREQUENCY_WEEKLY and by_day:
if frequency not in (CustomOnCallShift.FREQUENCY_WEEKLY, CustomOnCallShift.FREQUENCY_DAILY) and by_day:
raise serializers.ValidationError({"by_day": ["Cannot set days value for this frequency type"]})
if frequency == CustomOnCallShift.FREQUENCY_DAILY and by_day and interval > len(by_day):
raise serializers.ValidationError(
{"interval": ["Interval must be less than or equal to the number of selected days"]}
)

def _validate_rotation_start(self, shift_start, rotation_start):
if rotation_start < shift_start:
Expand Down
25 changes: 23 additions & 2 deletions engine/apps/api/tests/test_oncall_shift.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ def test_create_on_call_shift_invalid_data_by_day(on_call_shift_internal_api_set
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["by_day"][0] == "Cannot set days value for non-recurrent shifts"

# by_day with non-weekly frequency
# by_day with non-weekly/non-daily frequency
data = {
"title": "Test Shift 2",
"type": CustomOnCallShift.TYPE_ROLLING_USERS_EVENT,
Expand All @@ -749,7 +749,7 @@ def test_create_on_call_shift_invalid_data_by_day(on_call_shift_internal_api_set
"shift_end": (start_date + timezone.timedelta(hours=2)).strftime("%Y-%m-%dT%H:%M:%SZ"),
"rotation_start": start_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
"until": None,
"frequency": CustomOnCallShift.FREQUENCY_DAILY,
"frequency": CustomOnCallShift.FREQUENCY_MONTHLY,
"interval": None,
"by_day": [CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY]],
"rolling_users": [[user1.public_primary_key]],
Expand Down Expand Up @@ -789,6 +789,27 @@ def test_create_on_call_shift_invalid_data_interval(on_call_shift_internal_api_s
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["interval"][0] == "Cannot set interval for non-recurrent shifts"

# by_day, daily, interval > len(by_day)
data = {
"title": "Test Shift 2",
"type": CustomOnCallShift.TYPE_ROLLING_USERS_EVENT,
"schedule": schedule.public_primary_key,
"priority_level": 0,
"shift_start": start_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
"shift_end": (start_date + timezone.timedelta(hours=2)).strftime("%Y-%m-%dT%H:%M:%SZ"),
"rotation_start": start_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
"until": None,
"frequency": CustomOnCallShift.FREQUENCY_DAILY,
"interval": 2,
"by_day": [CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY]],
"rolling_users": [[user1.public_primary_key]],
}

response = client.post(url, data, format="json", **make_user_auth_headers(user1, token))

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["interval"][0] == "Interval must be less than or equal to the number of selected days"


@pytest.mark.django_db
def test_create_on_call_shift_invalid_data_shift_end(on_call_shift_internal_api_setup, make_user_auth_headers):
Expand Down
8 changes: 7 additions & 1 deletion engine/apps/api/views/schedule.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import datetime

import pytz
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Count, OuterRef, Subquery
Expand Down Expand Up @@ -295,7 +297,11 @@ def next_shifts_per_user(self, request, pk):
users = {u: None for u in schedule.related_users()}
for e in events:
user = e["users"][0]["pk"] if e["users"] else None
if user is not None and users.get(user) is None and e["end"] > now:
event_end = e["end"]
if not isinstance(event_end, datetime.datetime):
# all day events end is a date, make it a datetime for comparison
event_end = datetime.datetime.combine(event_end, datetime.datetime.min.time(), tzinfo=pytz.UTC)
if user is not None and users.get(user) is None and event_end > now:
users[user] = e

result = {"users": users}
Expand Down
5 changes: 3 additions & 2 deletions engine/apps/public_api/serializers/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
from collections import defaultdict

from django.core.validators import URLValidator, ValidationError
from jinja2 import Template, TemplateError
from jinja2 import TemplateError
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator

from apps.alerts.models import CustomButton
from common.api_helpers.custom_fields import TeamPrimaryKeyRelatedField
from common.api_helpers.utils import CurrentOrganizationDefault
from common.jinja_templater import jinja_template_env


class ActionCreateSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -56,7 +57,7 @@ def validate_data(self, data):
return None

try:
template = Template(data)
template = jinja_template_env.from_string(data)
except TemplateError:
raise serializers.ValidationError("Data has incorrect template")

Expand Down
10 changes: 7 additions & 3 deletions engine/apps/public_api/serializers/on_call_shifts.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def create(self, validated_data):
self._validate_frequency_daily(
validated_data["type"],
validated_data.get("frequency"),
validated_data.get("interval"),
validated_data.get("by_day"),
validated_data.get("by_monthday"),
)
Expand Down Expand Up @@ -201,14 +202,16 @@ def _validate_frequency_and_week_start(self, event_type, frequency, week_start):
elif frequency == CustomOnCallShift.FREQUENCY_WEEKLY and week_start is None:
raise BadRequest(detail="Field 'week_start' is required for frequency type 'weekly'")

def _validate_frequency_daily(self, event_type, frequency, by_day, by_monthday):
def _validate_frequency_daily(self, event_type, frequency, interval, by_day, by_monthday):
if event_type == CustomOnCallShift.TYPE_ROLLING_USERS_EVENT:
if frequency == CustomOnCallShift.FREQUENCY_DAILY:
if by_day or by_monthday:
if by_monthday:
raise BadRequest(
detail="Day limits are temporarily disabled for on-call shifts with type 'rolling_users' "
"and frequency 'daily'"
)
if by_day and interval > len(by_day):
raise BadRequest(detail="Interval must be less than or equal to the number of selected days")

def _validate_start_rotation_from_user_index(self, type, index):
if type == CustomOnCallShift.TYPE_ROLLING_USERS_EVENT and index is None:
Expand Down Expand Up @@ -354,9 +357,10 @@ def update(self, instance, validated_data):
if frequency != instance.frequency:
self._validate_frequency_and_week_start(event_type, frequency, week_start)

interval = validated_data.get("interval", instance.interval)
by_day = validated_data.get("by_day", instance.by_day)
by_monthday = validated_data.get("by_monthday", instance.by_monthday)
self._validate_frequency_daily(event_type, frequency, by_day, by_monthday)
self._validate_frequency_daily(event_type, frequency, interval, by_day, by_monthday)

if start_rotation_from_user_index != instance.start_rotation_from_user_index:
self._validate_start_rotation_from_user_index(event_type, start_rotation_from_user_index)
Expand Down
6 changes: 6 additions & 0 deletions engine/apps/public_api/tests/test_on_call_shifts.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
"until": "not-a-date",
}

invalid_field_data_9 = {
"frequency": CustomOnCallShift.FREQUENCY_DAILY,
"interval": 5,
}


@pytest.mark.django_db
def test_get_on_call_shift(make_organization_and_user_with_token, make_on_call_shift, make_schedule):
Expand Down Expand Up @@ -284,6 +289,7 @@ def test_update_on_call_shift(make_organization_and_user_with_token, make_on_cal
invalid_field_data_6,
invalid_field_data_7,
invalid_field_data_8,
invalid_field_data_9,
],
)
def test_update_on_call_shift_invalid_field(make_organization_and_user_with_token, make_on_call_shift, data_to_update):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ def get_events_from_ical_between(self, calendar: Calendar, start_date: datetime,

def filter_extra_days(event):
event_start, event_end = self.get_start_and_end_with_respect_to_event_type(event)
if event_start > event_end:
return False
return time_span_contains_event(start_date, end_date, event_start, event_end)

return list(filter(filter_extra_days, events))
Expand Down
Loading

0 comments on commit 144abaa

Please sign in to comment.