mirror of https://github.com/zulip/zulip.git
puppet: Add a sentry release class.
This installs the Sentry CLI, and uses it to send API events to Sentry when a release is started and completed.
This commit is contained in:
parent
bcd190ecf2
commit
3109d40b21
|
@ -89,7 +89,58 @@ process](install-existing-server.md).
|
||||||
|
|
||||||
Zulip's upgrades have a hook system which allows for arbitrary
|
Zulip's upgrades have a hook system which allows for arbitrary
|
||||||
user-configured actions to run before and after an upgrade; see the
|
user-configured actions to run before and after an upgrade; see the
|
||||||
[upgrading documentation](upgrade.md#deployment-hooks) for details.
|
[upgrading documentation](upgrade.md#deployment-hooks) for details on
|
||||||
|
how to write your own.
|
||||||
|
|
||||||
|
Zulip also provides and optional deploy hook for Sentry.
|
||||||
|
|
||||||
|
### Sentry deploy hook
|
||||||
|
|
||||||
|
Zulip can use its deploy hooks to create [Sentry
|
||||||
|
releases][sentry-release], which can help associate Sentry [error
|
||||||
|
logging][sentry-error] with specific releases. If you are deploying
|
||||||
|
Zulip from Git, it can be aware of which Zulip commits are associated
|
||||||
|
with the release, and help identify which commits might be relevant to
|
||||||
|
an error.
|
||||||
|
|
||||||
|
To do so:
|
||||||
|
|
||||||
|
1. Enable [Sentry error logging][sentry-error].
|
||||||
|
2. Add a new [internal Sentry integration][sentry-internal] named
|
||||||
|
"Release annotator".
|
||||||
|
3. Grant the internal integration the [permissions][sentry-perms] of
|
||||||
|
"Admin" on "Release".
|
||||||
|
4. Add `, zulip::hooks::sentry` to the `puppet_classes` line in `/etc/zulip/zulip.conf`
|
||||||
|
5. Add a `[sentry]` section to `/etc/zulip/zulip.conf`:
|
||||||
|
```ini
|
||||||
|
[sentry]
|
||||||
|
organization = your-organization-name
|
||||||
|
project = your-project-name
|
||||||
|
```
|
||||||
|
6. Add the [authentication token] for your internal Sentry integration
|
||||||
|
to your `/etc/zulip/zulip-secrets.conf`:
|
||||||
|
```ini
|
||||||
|
# Replace with your own token, found in Sentry
|
||||||
|
sentry_release_auth_token = 6c12f890c1c864666e64ee9c959c4552b3de473a076815e7669f53793fa16afc
|
||||||
|
```
|
||||||
|
7. As root, run `/home/zulip/deployments/current/scripts/zulip-puppet-apply`.
|
||||||
|
|
||||||
|
If you are deploying Zulip from Git, you will also need to:
|
||||||
|
|
||||||
|
1. In your Zulip project, add the [GitHub integration][sentry-github].
|
||||||
|
2. Configure the `zulip/zulip` GitHub project for your Sentry project.
|
||||||
|
You should do this even if you are deploying a private fork of
|
||||||
|
Zulip.
|
||||||
|
3. Additionally grant the internal integration "Read & Write" on
|
||||||
|
"Organization"; this is necessary to associate the commits with the
|
||||||
|
release.
|
||||||
|
|
||||||
|
[sentry-release]: https://docs.sentry.io/product/releases/
|
||||||
|
[sentry-error]: ../subsystems/logging.md#sentry-error-logging
|
||||||
|
[sentry-github]: https://docs.sentry.io/product/integrations/source-code-mgmt/github/
|
||||||
|
[sentry-internal]: https://docs.sentry.io/product/integrations/integration-platform/internal-integration/
|
||||||
|
[sentry-perms]: https://docs.sentry.io/product/integrations/integration-platform/#permissions
|
||||||
|
[sentry-tokens]: https://docs.sentry.io/product/integrations/integration-platform/internal-integration#auth-tokens
|
||||||
|
|
||||||
## Running Zulip's service dependencies on different machines
|
## Running Zulip's service dependencies on different machines
|
||||||
|
|
||||||
|
@ -844,3 +895,13 @@ Because Camo includes logic to deny access to private subnets, routing
|
||||||
its requests through Smokescreen is generally not necessary. Set to
|
its requests through Smokescreen is generally not necessary. Set to
|
||||||
true or false to override the default, which uses the proxy only if
|
true or false to override the default, which uses the proxy only if
|
||||||
it is not the default of Smokescreen on a local host.
|
it is not the default of Smokescreen on a local host.
|
||||||
|
|
||||||
|
### `[sentry]`
|
||||||
|
|
||||||
|
#### `organization`
|
||||||
|
|
||||||
|
The Sentry organization used for the [Sentry deploy hook](#sentry-deploy-hook).
|
||||||
|
|
||||||
|
#### `project`
|
||||||
|
|
||||||
|
The Sentry project used for the [Sentry deploy hook](#sentry-deploy-hook).
|
||||||
|
|
|
@ -223,6 +223,9 @@ is called, sorted in alphabetical order, from the working directory of
|
||||||
the new version, with arguments of the old and new Zulip versions. If
|
the new version, with arguments of the old and new Zulip versions. If
|
||||||
they exit with non-0 exit code, the upgrade will abort.
|
they exit with non-0 exit code, the upgrade will abort.
|
||||||
|
|
||||||
|
See the [deploy documentation](deployment.md#deployment-hooks) for
|
||||||
|
hooks included with Zulip.
|
||||||
|
|
||||||
## Preserving local changes to service configuration files
|
## Preserving local changes to service configuration files
|
||||||
|
|
||||||
:::{warning}
|
:::{warning}
|
||||||
|
|
|
@ -61,8 +61,12 @@ You can enable it by:
|
||||||
/home/zulip/deployments/current/scripts/restart-server
|
/home/zulip/deployments/current/scripts/restart-server
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You may also want to enable Zulip's [Sentry deploy
|
||||||
|
hook][sentry-deploy-hook].
|
||||||
|
|
||||||
[sentry-project]: https://docs.sentry.io/product/projects/
|
[sentry-project]: https://docs.sentry.io/product/projects/
|
||||||
[sentry-dsn]: https://docs.sentry.io/product/sentry-basics/dsn-explainer/
|
[sentry-dsn]: https://docs.sentry.io/product/sentry-basics/dsn-explainer/
|
||||||
|
[sentry-relase-hook]: ../production/deployment.md#sentry-deploy-hook
|
||||||
|
|
||||||
### Backend logging
|
### Backend logging
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
# Arguments: OLD_COMMIT NEW_COMMIT ...where both are `git describe`
|
||||||
|
# output or tag names. The CWD will be the new deploy directory.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
if ! grep -q 'SENTRY_DSN' /etc/zulip/settings.py; then
|
||||||
|
echo "sentry: No DSN configured! Set SENTRY_DSN in /etc/zulip/settings.py"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! SENTRY_AUTH_TOKEN=$(crudini --get /etc/zulip/zulip-secrets.conf secrets sentry_release_auth_token); then
|
||||||
|
echo "sentry: No release auth token set! Set sentry_release_auth_token in /etc/zulip/zulip-secrets.conf"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! SENTRY_ORG=$(crudini --get /etc/zulip/zulip.conf sentry organization); then
|
||||||
|
echo "sentry: No organization set! Set sentry.organization in /etc/zulip/zulip.conf"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! SENTRY_PROJECT=$(crudini --get /etc/zulip/zulip.conf sentry project); then
|
||||||
|
echo "sentry: No project set! Set setry.project in /etc/zulip/zulip.conf"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! which sentry-cli >/dev/null; then
|
||||||
|
echo "sentry: No sentry-cli installed!"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -f ./sentry-release ]; then
|
||||||
|
echo "sentry: No Sentry sentry-release file found!"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
SENTRY_RELEASE=$(cat ./sentry-release)
|
||||||
|
|
||||||
|
ENVIRONMENT=$(crudini --get /etc/zulip/zulip.conf machine deploy_type || echo "development")
|
||||||
|
|
||||||
|
echo "sentry: Adding deploy of '$ENVIRONMENT' and finalizing release"
|
||||||
|
|
||||||
|
export SENTRY_AUTH_TOKEN
|
||||||
|
sentry-cli releases --org="$SENTRY_ORG" --project="$SENTRY_PROJECT" deploys "$SENTRY_RELEASE" new \
|
||||||
|
--env "$ENVIRONMENT" \
|
||||||
|
--started "$(stat -c %Y ./sentry-release)" \
|
||||||
|
--finished "$(date +%s)" \
|
||||||
|
--name "$(hostname --fqdn)"
|
||||||
|
sentry-cli releases --org="$SENTRY_ORG" --project="$SENTRY_PROJECT" finalize "$SENTRY_RELEASE"
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
# Arguments: OLD_COMMIT NEW_COMMIT ...where both are `git describe`
|
||||||
|
# output or tag names. The CWD will be the new deploy directory.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
if ! grep -q 'SENTRY_DSN' /etc/zulip/settings.py; then
|
||||||
|
echo "sentry: No DSN configured! Set SENTRY_DSN in /etc/zulip/settings.py"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! SENTRY_AUTH_TOKEN=$(crudini --get /etc/zulip/zulip-secrets.conf secrets sentry_release_auth_token); then
|
||||||
|
echo "sentry: No release auth token set! Set sentry_release_auth_token in /etc/zulip/zulip-secrets.conf"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! SENTRY_ORG=$(crudini --get /etc/zulip/zulip.conf sentry organization); then
|
||||||
|
echo "sentry: No organization set! Set sentry.organization in /etc/zulip/zulip.conf"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! SENTRY_PROJECT=$(crudini --get /etc/zulip/zulip.conf sentry project); then
|
||||||
|
echo "sentry: No project set! Set setry.project in /etc/zulip/zulip.conf"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! which sentry-cli >/dev/null; then
|
||||||
|
echo "sentry: No sentry-cli installed!"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
NEW_VERSION="$2"
|
||||||
|
|
||||||
|
MERGE_BASE=""
|
||||||
|
if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null || true)" = "true" ]; then
|
||||||
|
# Extract the merge-base that tools/cache-zulip-git-version
|
||||||
|
# encoded into ./zulip-git-version, and turn it from a `git
|
||||||
|
# describe` into a commit hash
|
||||||
|
MERGE_BASE_DESCRIBED=$(head -n2 ./zulip-git-version | tail -1)
|
||||||
|
if [[ "$MERGE_BASE_DESCRIBED" =~ ^.*-g([0-9a-f]{7,})$ ]]; then
|
||||||
|
MERGE_BASE=$(git rev-parse "${BASH_REMATCH[1]}")
|
||||||
|
else
|
||||||
|
MERGE_BASE=$(git rev-parse "$MERGE_BASE_DESCRIBED")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
SENTRY_RELEASE="zulip-server@$NEW_VERSION"
|
||||||
|
echo "$SENTRY_RELEASE" >./sentry-release
|
||||||
|
|
||||||
|
echo "sentry: Creating release $SENTRY_RELEASE"
|
||||||
|
|
||||||
|
export SENTRY_AUTH_TOKEN
|
||||||
|
sentry-cli releases --org="$SENTRY_ORG" --project="$SENTRY_PROJECT" new "$SENTRY_RELEASE"
|
||||||
|
|
||||||
|
if [ -n "$MERGE_BASE" ]; then
|
||||||
|
echo "sentry: Setting commit range based on merge-base to upstream of $MERGE_BASE"
|
||||||
|
sudo -u zulip --preserve-env=SENTRY_AUTH_TOKEN sentry-cli releases --org="$SENTRY_ORG" --project="$SENTRY_PROJECT" set-commits "$SENTRY_RELEASE" --commit="zulip/zulip@$MERGE_BASE"
|
||||||
|
fi
|
|
@ -85,6 +85,15 @@ class zulip::common {
|
||||||
|
|
||||||
### zulip_ops packages
|
### zulip_ops packages
|
||||||
|
|
||||||
|
# https://release-registry.services.sentry.io/apps/sentry-cli/latest
|
||||||
|
'sentry-cli' => {
|
||||||
|
'version' => '2.11.0',
|
||||||
|
'sha256' => {
|
||||||
|
'amd64' => 'bc8f5f223fa688b3ad963c60a729f02aa8f5b17525de66fb3abf86800977ff6e',
|
||||||
|
'aarch64' => 'c62c5c1259307611e78af4f24a4c30162cff8adb0f021d363b307c42cded5c70',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
# https://grafana.com/grafana/download?edition=oss
|
# https://grafana.com/grafana/download?edition=oss
|
||||||
'grafana' => {
|
'grafana' => {
|
||||||
'version' => '9.3.4',
|
'version' => '9.3.4',
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
# @summary Install sentry-cli binary and pre/post deploy hooks
|
||||||
|
#
|
||||||
|
class zulip::hooks::sentry {
|
||||||
|
include zulip::hooks::base
|
||||||
|
$version = $zulip::common::versions['sentry-cli']['version']
|
||||||
|
$bin = "/srv/zulip-sentry-cli-${version}"
|
||||||
|
|
||||||
|
$arch = $::os['architecture'] ? {
|
||||||
|
'amd64' => 'x86_64',
|
||||||
|
'aarch64' => 'aarch64',
|
||||||
|
}
|
||||||
|
|
||||||
|
zulip::external_dep { 'sentry-cli':
|
||||||
|
version => $version,
|
||||||
|
url => "https://downloads.sentry-cdn.com/sentry-cli/${version}/sentry-cli-Linux-${arch}",
|
||||||
|
}
|
||||||
|
|
||||||
|
file { '/usr/local/bin/sentry-cli':
|
||||||
|
ensure => link,
|
||||||
|
target => $bin,
|
||||||
|
}
|
||||||
|
|
||||||
|
file { '/etc/zulip/hooks/pre-deploy.d/sentry.hook':
|
||||||
|
ensure => file,
|
||||||
|
mode => '0755',
|
||||||
|
owner => 'zulip',
|
||||||
|
group => 'zulip',
|
||||||
|
source => 'puppet:///modules/zulip/hooks/pre-deploy.d/sentry.hook',
|
||||||
|
tag => ['hooks'],
|
||||||
|
}
|
||||||
|
file { '/etc/zulip/hooks/post-deploy.d/sentry.hook':
|
||||||
|
ensure => file,
|
||||||
|
mode => '0755',
|
||||||
|
owner => 'zulip',
|
||||||
|
group => 'zulip',
|
||||||
|
source => 'puppet:///modules/zulip/hooks/post-deploy.d/sentry.hook',
|
||||||
|
tag => ['hooks'],
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
|
@ -9,6 +10,7 @@ from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
||||||
from sentry_sdk.utils import capture_internal_exceptions
|
from sentry_sdk.utils import capture_internal_exceptions
|
||||||
|
|
||||||
from version import ZULIP_VERSION
|
from version import ZULIP_VERSION
|
||||||
|
from zproject.config import DEPLOY_ROOT
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from sentry_sdk._types import Event, Hint
|
from sentry_sdk._types import Event, Hint
|
||||||
|
@ -58,10 +60,15 @@ def add_context(event: "Event", hint: "Hint") -> Optional["Event"]:
|
||||||
def setup_sentry(dsn: Optional[str], environment: str) -> None:
|
def setup_sentry(dsn: Optional[str], environment: str) -> None:
|
||||||
if not dsn:
|
if not dsn:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
sentry_release = ZULIP_VERSION
|
||||||
|
if os.path.exists(os.path.join(DEPLOY_ROOT, "sentry-release")):
|
||||||
|
with open(os.path.join(DEPLOY_ROOT, "sentry-release")) as sentry_release_file:
|
||||||
|
sentry_release = sentry_release_file.readline().strip()
|
||||||
sentry_sdk.init(
|
sentry_sdk.init(
|
||||||
dsn=dsn,
|
dsn=dsn,
|
||||||
environment=environment,
|
environment=environment,
|
||||||
release=ZULIP_VERSION,
|
release=sentry_release,
|
||||||
integrations=[
|
integrations=[
|
||||||
DjangoIntegration(),
|
DjangoIntegration(),
|
||||||
RedisIntegration(),
|
RedisIntegration(),
|
||||||
|
|
Loading…
Reference in New Issue