Backup/Restore (#256)
* lifecycle: move s3 backup settings to s3 name * providers/oauth2: fix for alerting for missing certificatekeypair * lifecycle: add backup commands see #252 * lifecycle: install postgres-client for 11 and 12 * root: migrate to DBBACKUP_STORAGE_OPTIONS, add region setting * lifecycle: auto-clean last backups * helm: add s3 region parameter, add cronjob for backups * docs: add backup docs * root: remove backup scheduled task for now
This commit is contained in:
parent
195d8fe71f
commit
9fb1ac98ec
|
@ -16,7 +16,11 @@ COPY --from=locker /app/requirements.txt /
|
||||||
COPY --from=locker /app/requirements-dev.txt /
|
COPY --from=locker /app/requirements-dev.txt /
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends postgresql-client-11 build-essential && \
|
apt-get install -y --no-install-recommends curl ca-certificates gnupg && \
|
||||||
|
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
|
||||||
|
echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends postgresql-client-12 postgresql-client-11 build-essential && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
pip install -r /requirements.txt --no-cache-dir && \
|
pip install -r /requirements.txt --no-cache-dir && \
|
||||||
apt-get remove --purge -y build-essential && \
|
apt-get remove --purge -y build-essential && \
|
||||||
|
|
|
@ -37,6 +37,8 @@ services:
|
||||||
- traefik.port=8000
|
- traefik.port=8000
|
||||||
- traefik.docker.network=internal
|
- traefik.docker.network=internal
|
||||||
- traefik.frontend.rule=PathPrefix:/
|
- traefik.frontend.rule=PathPrefix:/
|
||||||
|
volumes:
|
||||||
|
- ./backups:/backups
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
worker:
|
worker:
|
||||||
|
@ -50,6 +52,8 @@ services:
|
||||||
PASSBOOK_REDIS__HOST: redis
|
PASSBOOK_REDIS__HOST: redis
|
||||||
PASSBOOK_POSTGRESQL__HOST: postgresql
|
PASSBOOK_POSTGRESQL__HOST: postgresql
|
||||||
PASSBOOK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
PASSBOOK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||||
|
volumes:
|
||||||
|
- ./backups:/backups
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
static:
|
static:
|
||||||
|
|
|
@ -4,7 +4,7 @@ For a mid to high-load installation, Kubernetes is recommended. passbook is inst
|
||||||
|
|
||||||
This installation automatically applies database migrations on startup. After the installation is done, you can use `pbadmin` as username and password.
|
This installation automatically applies database migrations on startup. After the installation is done, you can use `pbadmin` as username and password.
|
||||||
|
|
||||||
```
|
```yaml
|
||||||
###################################
|
###################################
|
||||||
# Values directly affecting passbook
|
# Values directly affecting passbook
|
||||||
###################################
|
###################################
|
||||||
|
@ -35,8 +35,21 @@ config:
|
||||||
# access_key: access-key
|
# access_key: access-key
|
||||||
# secret_key: secret-key
|
# secret_key: secret-key
|
||||||
# bucket: s3-bucket
|
# bucket: s3-bucket
|
||||||
|
# region: eu-central-1
|
||||||
# host: s3-host
|
# host: s3-host
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
annotations: {}
|
||||||
|
# kubernetes.io/ingress.class: nginx
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
path: /
|
||||||
|
hosts:
|
||||||
|
- passbook.k8s.local
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - passbook.k8s.local
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
# Values controlling dependencies
|
# Values controlling dependencies
|
||||||
###################################
|
###################################
|
||||||
|
@ -57,16 +70,4 @@ redis:
|
||||||
enabled: false
|
enabled: false
|
||||||
# https://stackoverflow.com/a/59189742
|
# https://stackoverflow.com/a/59189742
|
||||||
disableCommands: []
|
disableCommands: []
|
||||||
|
|
||||||
ingress:
|
|
||||||
annotations: {}
|
|
||||||
# kubernetes.io/ingress.class: nginx
|
|
||||||
# kubernetes.io/tls-acme: "true"
|
|
||||||
path: /
|
|
||||||
hosts:
|
|
||||||
- passbook.k8s.local
|
|
||||||
tls: []
|
|
||||||
# - secretName: chart-example-tls
|
|
||||||
# hosts:
|
|
||||||
# - passbook.k8s.local
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
# Backup and restore
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
|
||||||
|
Local backups are only supported for docker-compose installs. If you want to backup a Kubernetes instance locally, use an S3-compatible server such as [minio](https://min.io/)
|
||||||
|
|
||||||
|
### Backup
|
||||||
|
|
||||||
|
Local backups can be created by running the following command in your passbook installation directory
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose run --rm server backup
|
||||||
|
```
|
||||||
|
|
||||||
|
This will dump the current database into the `./backups` folder. By defaults, the last 10 Backups are kept.
|
||||||
|
|
||||||
|
To schedule these backups, use the following snippet in a crontab
|
||||||
|
|
||||||
|
```
|
||||||
|
0 0 * * * bash -c "cd <passbook install location> && docker-compose run --rm server backup" >/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! notice
|
||||||
|
|
||||||
|
passbook does support automatic backups on a schedule, however this is currently not recommended, as there is no way to monitor these scheduled tasks.
|
||||||
|
|
||||||
|
### Restore
|
||||||
|
|
||||||
|
Run this command in your passbook installation directory
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose run --rm server backup
|
||||||
|
```
|
||||||
|
|
||||||
|
This will prompt you to restore from your last backup. If you want to restore from a specific file, use the `-i` flag with the filename:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose run --rm server backup -i default-2020-10-03-115557.psql
|
||||||
|
```
|
||||||
|
|
||||||
|
After you've restored the backup, it is recommended to restart all services with `docker-compose restart`.
|
||||||
|
|
||||||
|
### S3 Configuration
|
||||||
|
|
||||||
|
!!! notice
|
||||||
|
|
||||||
|
To trigger backups with S3 enabled, use the same commands as above.
|
||||||
|
|
||||||
|
#### S3 Preparation
|
||||||
|
|
||||||
|
passbook expects the bucket you select to already exist. The IAM User given to passbook should have the following permissions
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Sid": "VisualEditor0",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"s3:PutObject",
|
||||||
|
"s3:GetObjectAcl",
|
||||||
|
"s3:GetObject",
|
||||||
|
"s3:ListBucket",
|
||||||
|
"s3:DeleteObject",
|
||||||
|
"s3:PutObjectAcl"
|
||||||
|
],
|
||||||
|
"Principal": {
|
||||||
|
"AWS": "arn:aws:iam::example-AWS-account-ID:user/example-user-name"
|
||||||
|
},
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::example-bucket-name/*",
|
||||||
|
"arn:aws:s3:::example-bucket-name"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### docker-compose
|
||||||
|
|
||||||
|
Set the following values in your `.env` file.
|
||||||
|
|
||||||
|
```
|
||||||
|
PASSBOOK_POSTGRESQL__S3_BACKUP__ACCESS_KEY=
|
||||||
|
PASSBOOK_POSTGRESQL__S3_BACKUP__SECRET_KEY=
|
||||||
|
PASSBOOK_POSTGRESQL__S3_BACKUP__BUCKET=
|
||||||
|
PASSBOOK_POSTGRESQL__S3_BACKUP__REGION=
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to backup to an S3-compatible server, like [minio](https://min.io/), use this setting:
|
||||||
|
|
||||||
|
```
|
||||||
|
PASSBOOK_POSTGRESQL__S3_BACKUP__HOST=http://play.min.io
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Kubernetes
|
||||||
|
|
||||||
|
Simply enable these options in your values.yaml file
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Enable Database Backups to S3
|
||||||
|
backup:
|
||||||
|
access_key: access-key
|
||||||
|
secret_key: secret-key
|
||||||
|
bucket: s3-bucket
|
||||||
|
region: eu-central-1
|
||||||
|
host: s3-host
|
||||||
|
```
|
||||||
|
|
||||||
|
Afterwards, run a `helm upgrade` to update the ConfigMap. Because passbook-scheduled backups are not recommended currently, a Kubernetes CronJob is created that runs the backup daily.
|
|
@ -7,10 +7,11 @@ data:
|
||||||
POSTGRESQL__NAME: "{{ .Values.postgresql.postgresqlDatabase }}"
|
POSTGRESQL__NAME: "{{ .Values.postgresql.postgresqlDatabase }}"
|
||||||
POSTGRESQL__USER: "{{ .Values.postgresql.postgresqlUsername }}"
|
POSTGRESQL__USER: "{{ .Values.postgresql.postgresqlUsername }}"
|
||||||
{{- if .Values.backup }}
|
{{- if .Values.backup }}
|
||||||
POSTGRESQL__BACKUP__ACCESS_KEY: "{{ .Values.backup.access_key }}"
|
POSTGRESQL__S3_BACKUP__ACCESS_KEY: "{{ .Values.backup.access_key }}"
|
||||||
POSTGRESQL__BACKUP__SECRET_KEY: "{{ .Values.backup.secret_key }}"
|
POSTGRESQL__S3_BACKUP__SECRET_KEY: "{{ .Values.backup.secret_key }}"
|
||||||
POSTGRESQL__BACKUP__BUCKET: "{{ .Values.backup.bucket }}"
|
POSTGRESQL__S3_BACKUP__BUCKET: "{{ .Values.backup.bucket }}"
|
||||||
POSTGRESQL__BACKUP__HOST: "{{ .Values.backup.host }}"
|
POSTGRESQL__S3_BACKUP__REGION: "{{ .Values.backup.region }}"
|
||||||
|
POSTGRESQL__S3_BACKUP__HOST: "{{ .Values.backup.host }}"
|
||||||
{{- end}}
|
{{- end}}
|
||||||
REDIS__HOST: "{{ .Release.Name }}-redis-master"
|
REDIS__HOST: "{{ .Release.Name }}-redis-master"
|
||||||
ERROR_REPORTING__ENABLED: "{{ .Values.config.error_reporting.enabled }}"
|
ERROR_REPORTING__ENABLED: "{{ .Values.config.error_reporting.enabled }}"
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
{{- if .Values.backup }}
|
||||||
|
apiVersion: batch/v1beta1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: {{ include "passbook.fullname" . }}-backup
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ include "passbook.name" . }}
|
||||||
|
helm.sh/chart: {{ include "passbook.chart" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
schedule: "0 0 * * *"
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.name }}:{{ .Values.image.tag }}"
|
||||||
|
args: [server]
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: {{ include "passbook.fullname" . }}-config
|
||||||
|
prefix: PASSBOOK_
|
||||||
|
env:
|
||||||
|
- name: PASSBOOK_SECRET_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ include "passbook.fullname" . }}-secret-key"
|
||||||
|
key: "secret_key"
|
||||||
|
- name: PASSBOOK_REDIS__PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Release.Name }}-redis"
|
||||||
|
key: "redis-password"
|
||||||
|
- name: PASSBOOK_POSTGRESQL__PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Release.Name }}-postgresql"
|
||||||
|
key: "postgresql-password"
|
||||||
|
{{- end}}
|
|
@ -28,8 +28,21 @@ config:
|
||||||
# access_key: access-key
|
# access_key: access-key
|
||||||
# secret_key: secret-key
|
# secret_key: secret-key
|
||||||
# bucket: s3-bucket
|
# bucket: s3-bucket
|
||||||
|
# region: eu-central-1
|
||||||
# host: s3-host
|
# host: s3-host
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
annotations: {}
|
||||||
|
# kubernetes.io/ingress.class: nginx
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
path: /
|
||||||
|
hosts:
|
||||||
|
- passbook.k8s.local
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - passbook.k8s.local
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
# Values controlling dependencies
|
# Values controlling dependencies
|
||||||
###################################
|
###################################
|
||||||
|
@ -50,15 +63,3 @@ redis:
|
||||||
enabled: false
|
enabled: false
|
||||||
# https://stackoverflow.com/a/59189742
|
# https://stackoverflow.com/a/59189742
|
||||||
disableCommands: []
|
disableCommands: []
|
||||||
|
|
||||||
ingress:
|
|
||||||
annotations: {}
|
|
||||||
# kubernetes.io/ingress.class: nginx
|
|
||||||
# kubernetes.io/tls-acme: "true"
|
|
||||||
path: /
|
|
||||||
hosts:
|
|
||||||
- passbook.k8s.local
|
|
||||||
tls: []
|
|
||||||
# - secretName: chart-example-tls
|
|
||||||
# hosts:
|
|
||||||
# - passbook.k8s.local
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash -e
|
#!/bin/bash -e
|
||||||
python -m lifecycle.wait_for_db
|
python -m lifecycle.wait_for_db
|
||||||
printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@"
|
printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr
|
||||||
if [[ "$1" == "server" ]]; then
|
if [[ "$1" == "server" ]]; then
|
||||||
gunicorn -c /lifecycle/gunicorn.conf.py passbook.root.asgi:application
|
gunicorn -c /lifecycle/gunicorn.conf.py passbook.root.asgi:application
|
||||||
elif [[ "$1" == "worker" ]]; then
|
elif [[ "$1" == "worker" ]]; then
|
||||||
|
@ -9,6 +9,12 @@ elif [[ "$1" == "migrate" ]]; then
|
||||||
# Run system migrations first, run normal migrations after
|
# Run system migrations first, run normal migrations after
|
||||||
python -m lifecycle.migrate
|
python -m lifecycle.migrate
|
||||||
python -m manage migrate
|
python -m manage migrate
|
||||||
|
elif [[ "$1" == "backup" ]]; then
|
||||||
|
python -m manage dbbackup --clean
|
||||||
|
elif [[ "$1" == "restore" ]]; then
|
||||||
|
python -m manage dbrestore ${@:2}
|
||||||
|
elif [[ "$1" == "bash" ]]; then
|
||||||
|
/bin/bash
|
||||||
else
|
else
|
||||||
python -m manage "$@"
|
python -m manage "$@"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -57,6 +57,8 @@ nav:
|
||||||
- Ubuntu Landscape: integrations/services/ubuntu-landscape/index.md
|
- Ubuntu Landscape: integrations/services/ubuntu-landscape/index.md
|
||||||
- Sonarr: integrations/services/sonarr/index.md
|
- Sonarr: integrations/services/sonarr/index.md
|
||||||
- Tautulli: integrations/services/tautulli/index.md
|
- Tautulli: integrations/services/tautulli/index.md
|
||||||
|
- Maintenance:
|
||||||
|
- Backups: maintenance/backups/index.md
|
||||||
- Upgrading:
|
- Upgrading:
|
||||||
- to 0.9: upgrading/to-0.9.md
|
- to 0.9: upgrading/to-0.9.md
|
||||||
- to 0.10: upgrading/to-0.10.md
|
- to 0.10: upgrading/to-0.10.md
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
"""passbook misc tasks"""
|
|
||||||
from django.core import management
|
|
||||||
from structlog import get_logger
|
|
||||||
|
|
||||||
from passbook.root.celery import CELERY_APP
|
|
||||||
|
|
||||||
LOGGER = get_logger()
|
|
||||||
|
|
||||||
|
|
||||||
@CELERY_APP.task()
|
|
||||||
def backup_database(): # pragma: no cover
|
|
||||||
"""Backup database"""
|
|
||||||
management.call_command("dbbackup")
|
|
||||||
LOGGER.info("Successfully backed up database.")
|
|
|
@ -12,7 +12,7 @@ from passbook.providers.oauth2.generators import (
|
||||||
generate_client_id,
|
generate_client_id,
|
||||||
generate_client_secret,
|
generate_client_secret,
|
||||||
)
|
)
|
||||||
from passbook.providers.oauth2.models import OAuth2Provider, ScopeMapping
|
from passbook.providers.oauth2.models import JWTAlgorithms, OAuth2Provider, ScopeMapping
|
||||||
|
|
||||||
|
|
||||||
class OAuth2ProviderForm(forms.ModelForm):
|
class OAuth2ProviderForm(forms.ModelForm):
|
||||||
|
@ -32,7 +32,10 @@ class OAuth2ProviderForm(forms.ModelForm):
|
||||||
|
|
||||||
def clean_jwt_alg(self):
|
def clean_jwt_alg(self):
|
||||||
"""Ensure that when RS256 is selected, a certificate-key-pair is selected"""
|
"""Ensure that when RS256 is selected, a certificate-key-pair is selected"""
|
||||||
if "rsa_key" not in self.cleaned_data:
|
if (
|
||||||
|
self.data["rsa_key"] == ""
|
||||||
|
and self.cleaned_data["jwt_alg"] == JWTAlgorithms.RS256
|
||||||
|
):
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
_("RS256 requires a Certificate-Key-Pair to be selected.")
|
_("RS256 requires a Certificate-Key-Pair to be selected.")
|
||||||
)
|
)
|
||||||
|
|
|
@ -272,7 +272,7 @@ CELERY_BEAT_SCHEDULE = {
|
||||||
"options": {"queue": "passbook_scheduled"},
|
"options": {"queue": "passbook_scheduled"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CELERY_CREATE_MISSING_QUEUES = True
|
CELERY_TASK_CREATE_MISSING_QUEUES = True
|
||||||
CELERY_TASK_DEFAULT_QUEUE = "passbook"
|
CELERY_TASK_DEFAULT_QUEUE = "passbook"
|
||||||
CELERY_BROKER_URL = (
|
CELERY_BROKER_URL = (
|
||||||
f"redis://:{CONFIG.y('redis.password')}@{CONFIG.y('redis.host')}"
|
f"redis://:{CONFIG.y('redis.password')}@{CONFIG.y('redis.host')}"
|
||||||
|
@ -284,24 +284,25 @@ CELERY_RESULT_BACKEND = (
|
||||||
)
|
)
|
||||||
|
|
||||||
# Database backup
|
# Database backup
|
||||||
if CONFIG.y("postgresql.backup"):
|
DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage"
|
||||||
|
DBBACKUP_STORAGE_OPTIONS = {"location": "./backups" if DEBUG else "/backups"}
|
||||||
|
DBBACKUP_CONNECTOR_MAPPING = {
|
||||||
|
"django_prometheus.db.backends.postgresql": "dbbackup.db.postgresql.PgDumpConnector"
|
||||||
|
}
|
||||||
|
if CONFIG.y("postgresql.s3_backup"):
|
||||||
DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||||
DBBACKUP_CONNECTOR_MAPPING = {
|
DBBACKUP_STORAGE_OPTIONS = {
|
||||||
"django_prometheus.db.backends.postgresql": "dbbackup.db.postgresql.PgDumpConnector"
|
"access_key": CONFIG.y("postgresql.s3_backup.access_key"),
|
||||||
|
"secret_key": CONFIG.y("postgresql.s3_backup.secret_key"),
|
||||||
|
"bucket_name": CONFIG.y("postgresql.s3_backup.bucket"),
|
||||||
|
"region_name": CONFIG.y("postgresql.s3_backup.region", "eu-central-1"),
|
||||||
|
"default_acl": "private",
|
||||||
|
"endpoint_url": CONFIG.y("postgresql.s3_backup.host"),
|
||||||
}
|
}
|
||||||
AWS_ACCESS_KEY_ID = CONFIG.y("postgresql.backup.access_key")
|
|
||||||
AWS_SECRET_ACCESS_KEY = CONFIG.y("postgresql.backup.secret_key")
|
|
||||||
AWS_STORAGE_BUCKET_NAME = CONFIG.y("postgresql.backup.bucket")
|
|
||||||
AWS_S3_ENDPOINT_URL = CONFIG.y("postgresql.backup.host")
|
|
||||||
AWS_DEFAULT_ACL = None
|
|
||||||
j_print(
|
j_print(
|
||||||
"Database backup to S3 is configured.", host=CONFIG.y("postgresql.backup.host")
|
"Database backup to S3 is configured.",
|
||||||
|
host=CONFIG.y("postgresql.s3_backup.host"),
|
||||||
)
|
)
|
||||||
# Add automatic task to backup
|
|
||||||
CELERY_BEAT_SCHEDULE["db_backup"] = {
|
|
||||||
"task": "passbook.lib.tasks.backup_database",
|
|
||||||
"schedule": crontab(minute=0, hour=0), # Run every day, midnight
|
|
||||||
}
|
|
||||||
|
|
||||||
# Sentry integration
|
# Sentry integration
|
||||||
_ERROR_REPORTING = CONFIG.y_bool("error_reporting.enabled", False)
|
_ERROR_REPORTING = CONFIG.y_bool("error_reporting.enabled", False)
|
||||||
|
@ -400,6 +401,7 @@ _LOGGING_HANDLER_MAP = {
|
||||||
"urllib3": "WARNING",
|
"urllib3": "WARNING",
|
||||||
"websockets": "WARNING",
|
"websockets": "WARNING",
|
||||||
"daphne": "WARNING",
|
"daphne": "WARNING",
|
||||||
|
"dbbackup": "ERROR",
|
||||||
}
|
}
|
||||||
for handler_name, level in _LOGGING_HANDLER_MAP.items():
|
for handler_name, level in _LOGGING_HANDLER_MAP.items():
|
||||||
# pyright: reportGeneralTypeIssues=false
|
# pyright: reportGeneralTypeIssues=false
|
||||||
|
|
Reference in New Issue