Merge branch 'dev' into web-schedules-fixes-bunch-3
This commit is contained in:
commit
29b49ea1a3
9 changed files with 151 additions and 14 deletions
|
|
@ -76,9 +76,13 @@ def notify_user_async(user_pk, alert_group_pk, notification_policy_pk):
|
|||
subject, html_message = build_subject_and_message(alert_group, emails_left)
|
||||
|
||||
message = strip_tags(html_message)
|
||||
email_from = settings.EMAIL_HOST_USER
|
||||
recipient_list = [user.email]
|
||||
|
||||
if settings.LICENSE == settings.CLOUD_LICENSE_NAME:
|
||||
email_from = "oncall@{}.grafana.net".format(user.organization.stack_slug)
|
||||
else:
|
||||
email_from = live_settings.EMAIL_HOST_USER
|
||||
|
||||
connection = get_connection(
|
||||
host=live_settings.EMAIL_HOST,
|
||||
port=live_settings.EMAIL_PORT,
|
||||
|
|
|
|||
|
|
@ -155,3 +155,72 @@ def test_notify_user_no_emails_left(
|
|||
log_record = notification_policy.personal_log_records.last()
|
||||
assert log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED
|
||||
assert log_record.notification_error_code == UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_MAIL_LIMIT_EXCEEDED
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_notify_user_from_email_oss(
|
||||
settings,
|
||||
make_organization,
|
||||
make_user_for_organization,
|
||||
make_token_for_organization,
|
||||
make_alert_receive_channel,
|
||||
make_alert_group,
|
||||
make_alert,
|
||||
make_user_notification_policy,
|
||||
):
|
||||
settings.LICENSE = settings.OPEN_SOURCE_LICENSE_NAME
|
||||
settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||
settings.EMAIL_HOST = "test"
|
||||
settings.EMAIL_HOST_USER = "test@test.com"
|
||||
|
||||
organization = make_organization(stack_slug="example")
|
||||
user = make_user_for_organization(organization)
|
||||
|
||||
alert_receive_channel = make_alert_receive_channel(organization)
|
||||
alert_group = make_alert_group(alert_receive_channel)
|
||||
|
||||
make_alert(alert_group=alert_group, raw_request_data=alert_receive_channel.config.example_payload)
|
||||
|
||||
notification_policy = make_user_notification_policy(
|
||||
user,
|
||||
UserNotificationPolicy.Step.NOTIFY,
|
||||
notify_by=8,
|
||||
important=False,
|
||||
)
|
||||
|
||||
notify_user_async(user.pk, alert_group.pk, notification_policy.pk)
|
||||
assert mail.outbox[0].from_email == "test@test.com"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_notify_user_from_email_cloud(
|
||||
settings,
|
||||
make_organization,
|
||||
make_user_for_organization,
|
||||
make_token_for_organization,
|
||||
make_alert_receive_channel,
|
||||
make_alert_group,
|
||||
make_alert,
|
||||
make_user_notification_policy,
|
||||
):
|
||||
settings.LICENSE = settings.CLOUD_LICENSE_NAME
|
||||
settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||
settings.EMAIL_HOST = "test"
|
||||
|
||||
organization = make_organization(stack_slug="slug")
|
||||
user = make_user_for_organization(organization)
|
||||
|
||||
alert_receive_channel = make_alert_receive_channel(organization)
|
||||
alert_group = make_alert_group(alert_receive_channel)
|
||||
|
||||
make_alert(alert_group=alert_group, raw_request_data=alert_receive_channel.config.example_payload)
|
||||
|
||||
notification_policy = make_user_notification_policy(
|
||||
user,
|
||||
UserNotificationPolicy.Step.NOTIFY,
|
||||
notify_by=8,
|
||||
important=False,
|
||||
)
|
||||
|
||||
notify_user_async(user.pk, alert_group.pk, notification_policy.pk)
|
||||
assert mail.outbox[0].from_email == "oncall@slug.grafana.net"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# Generated by Django 3.2.15 on 2022-10-25 03:16
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('user_management', '0003_user_hide_phone_number'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Region',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=300)),
|
||||
('slug', models.CharField(max_length=50, unique=True)),
|
||||
('oncall_backend_url', models.URLField(null=True)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='region_slug',
|
||||
field=models.CharField(default=None, max_length=300, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='migration_destination',
|
||||
field=models.ForeignKey(db_column='migration_destination_slug', default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='regions', to='user_management.region', to_field='slug'),
|
||||
),
|
||||
]
|
||||
|
|
@ -23,19 +23,21 @@ class RequestTimeLoggingMiddleware(MiddlewareMixin):
|
|||
seconds = (dt - request._logging_start_dt).total_seconds()
|
||||
status_code = 0 if response is None else response.status_code
|
||||
content_length = request.headers.get("content-length", default=0)
|
||||
integration_type = "N/A"
|
||||
integration_token = "N/A"
|
||||
message = (
|
||||
"inbound "
|
||||
f"latency={str(seconds)} status={status_code} method={request.method} path={request.path} "
|
||||
f"content-length={content_length} slow={int(seconds > settings.SLOW_THRESHOLD_SECONDS)} "
|
||||
)
|
||||
if hasattr(request, "user") and request.user and request.user.id:
|
||||
user_id = request.user.id
|
||||
org_id = request.user.organization_id
|
||||
message += f"user_id={user_id} org_id={org_id} "
|
||||
if request.path.startswith("/integrations/v1"):
|
||||
split_path = request.path.split("/")
|
||||
integration_type = split_path[3]
|
||||
integration_token = split_path[4]
|
||||
logging.info(
|
||||
"inbound "
|
||||
f"latency={str(seconds)} status={status_code} method={request.method} path={request.path} "
|
||||
f"content-length={content_length} slow={int(seconds > settings.SLOW_THRESHOLD_SECONDS)} "
|
||||
f"integration_type={integration_type} "
|
||||
f"integration_token={integration_token}"
|
||||
)
|
||||
message += f"integration_type={integration_type} integration_token={integration_token} "
|
||||
logging.info(message)
|
||||
|
||||
def process_request(self, request):
|
||||
self.log_message(request, None, "request")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ type: application
|
|||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 1.0.7
|
||||
version: 1.0.8
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
|
|
|||
|
|
@ -224,6 +224,11 @@ externalRabbitmq:
|
|||
port:
|
||||
user:
|
||||
password:
|
||||
protocol:
|
||||
vhost:
|
||||
existingSecret: ""
|
||||
passwordKey: password
|
||||
usernameKey: username
|
||||
```
|
||||
|
||||
### Connect external Redis
|
||||
|
|
|
|||
|
|
@ -237,13 +237,21 @@
|
|||
|
||||
{{- define "snippet.rabbitmq.env" -}}
|
||||
{{- if eq .Values.broker.type "rabbitmq" -}}
|
||||
{{- if and (not .Values.rabbitmq.enabled) (not .Values.externalRabbitmq.existingSecret) (not .Values.externalRabbitmq.usernameKey) .Values.externalRabbitmq.user }}
|
||||
- name: RABBITMQ_USERNAME
|
||||
value: {{ include "snippet.rabbitmq.user" . }}
|
||||
{{- else if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.existingSecret .Values.externalRabbitmq.usernameKey (not .Values.externalRabbitmq.user) }}
|
||||
- name: RABBITMQ_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "snippet.rabbitmq.password.secret.name" . }}
|
||||
key: {{ .Values.externalRabbitmq.usernameKey }}
|
||||
{{- end }}
|
||||
- name: RABBITMQ_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "snippet.rabbitmq.password.secret.name" . }}
|
||||
key: rabbitmq-password
|
||||
key: {{ include "snippet.rabbitmq.password.secret.key" . }}
|
||||
- name: RABBITMQ_HOST
|
||||
value: {{ include "snippet.rabbitmq.host" . }}
|
||||
- name: RABBITMQ_PORT
|
||||
|
|
@ -298,11 +306,21 @@
|
|||
{{- define "snippet.rabbitmq.password.secret.name" -}}
|
||||
{{- if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.password -}}
|
||||
{{ include "oncall.fullname" . }}-rabbitmq-external
|
||||
{{- else if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.existingSecret -}}
|
||||
{{ .Values.externalRabbitmq.existingSecret }}
|
||||
{{- else -}}
|
||||
{{ include "oncall.rabbitmq.fullname" . }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "snippet.rabbitmq.password.secret.key" -}}
|
||||
{{- if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.passwordKey -}}
|
||||
{{ .Values.externalRabbitmq.passwordKey }}
|
||||
{{- else -}}
|
||||
rabbitmq-password
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "snippet.redis.host" -}}
|
||||
{{- if and (not .Values.redis.enabled) .Values.externalRedis.host -}}
|
||||
{{- required "externalRedis.host is required if not redis.enabled" .Values.externalRedis.host | quote }}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ data:
|
|||
mariadb-root-password: {{ required "externalMysql.password is required if not mariadb.enabled" .Values.externalMysql.password | b64enc | quote }}
|
||||
{{- end }}
|
||||
---
|
||||
{{ if and (eq .Values.broker.type "rabbitmq") (not .Values.rabbitmq.enabled) -}}
|
||||
{{ if and (eq .Values.broker.type "rabbitmq") (not .Values.rabbitmq.enabled) (not .Values.externalRabbitmq.existingSecret) -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "oncall.fullname" . }}-rabbitmq-external
|
||||
type: Opaque
|
||||
data:
|
||||
rabbitmq-password: {{ required "externalRabbitmq.password is required if not rabbitmq.enabled" .Values.externalRabbitmq.password | b64enc | quote }}
|
||||
rabbitmq-password: {{ required "externalRabbitmq.password is required if not rabbitmq.enabled and not externalRabbitmq.existingSecret" .Values.externalRabbitmq.password | b64enc | quote }}
|
||||
{{- end }}
|
||||
---
|
||||
{{ if not .Values.redis.enabled -}}
|
||||
|
|
|
|||
|
|
@ -239,6 +239,12 @@ externalRabbitmq:
|
|||
password:
|
||||
protocol:
|
||||
vhost:
|
||||
# use an existing secret for the rabbitmq password
|
||||
existingSecret: ""
|
||||
# the key in the secret containing the rabbitmq password
|
||||
passwordKey: password
|
||||
# the key in the secret containing the rabbitmq username
|
||||
usernameKey: username
|
||||
|
||||
# Redis is included into this release for the convenience.
|
||||
# It is recommended to host it separately from this release
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue