├── .dockerignore ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── README.md ├── environment.example ├── environment.nodocker.example ├── requirements.txt ├── run_tests.sh ├── scripts ├── check_db_isalive.py └── create_team_or_project.py ├── sentry_docker_conf.py ├── sentry_run └── tests ├── custom_settings ├── Dockerfile ├── conf │ └── sentry_customconf.py ├── docker-compose.yml └── test.sh ├── initial_team_project ├── Dockerfile ├── docker-compose.yml └── test.sh └── simple_services ├── Dockerfile ├── README.md ├── docker-compose.yml └── test.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | CHANGELOG.md 2 | README.md 3 | CONTRIBUTING.md 4 | environment.example 5 | environment.nodocker.example 6 | tests/ 7 | run_tests.sh 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | environment 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 2016-03-07 4 | 5 | - Upgraded to Sentry ``8.0`` 6 | 7 | ## 2015-12-18 8 | 9 | - added `CELERY_RESULT_SERIALIZER`, `CELERY_TASK_SERIALIZER` 10 | and `CELERY_ACCEPT_CONTENT` configs to avoid `C_FORCE_ROOT` env var 11 | (default values support `pickle` for backwards compatibility). 12 | 13 | ## 2015-11-16 14 | 15 | - updated ``Sentry`` to 7.7.4 16 | - merged forgotten changes to dev 17 | 18 | ## 2015-11-11 19 | 20 | - updated ``Sentry`` to 7.7.1 21 | - updated ``django-auth-ldap`` to 1.2.7 22 | - updated ``django-redis`` to 4.3.0 23 | - updated ``python-decouple`` to 3.0 24 | - fixed building dev version (8.0.0.dev0) (credit goes to: @yurtaev) 25 | - creating superuser via python script 26 | 27 | ## 2015-08-29 28 | 29 | - updated ``Sentry`` to 7.7.0 and dropped ``django-json`` fix 30 | 31 | ## 2015-08-26 32 | 33 | - updated ``Sentry`` to 7.6.2 34 | 35 | ## 2015-08-24 36 | 37 | - add `.dockerignore` file 38 | - updated ``django-cache-url`` to 1.0.0 (watch out for trailing `/`) 39 | - updated ``django-redis`` to 4.2.0 40 | 41 | ## 2015-08-20 42 | 43 | - Added `nestedGroupOfNames` `LDAP_GROUP_TYPE` 44 | - Make use of `LDAP_GROUP_STAFF` 45 | 46 | ## 2015-08-19 47 | 48 | - fix migration issue (https://github.com/getsentry/sentry/issues/1648) 49 | - allow for a simple database accessibility check (via ``SENTRY_DOCKER_DO_DB_CHECK`` env var) 50 | - updated ``Sentry`` to 7.5.6 51 | 52 | ## 2015-06-25 53 | 54 | - remove ``nydus`` as an explicit requirement (see #28) 55 | 56 | ## 2015-06-22 57 | 58 | - updated ``Sentry`` to 7.5.4 59 | 60 | ## 2015-06-08 61 | 62 | - revert django-redis to 3.8.4 due to #26 63 | 64 | ## 2015-05-20 65 | 66 | - updated ``requirements.txt`` (``django-redis``, ``hiredis`` and ``django-auth-ldap`` ) 67 | - added support for posixGroup in LDAP auth backend (credit goes to: @grundleborg) 68 | 69 | ## 2015-03-26 70 | 71 | - updated ``Sentry`` to 7.4.3 72 | 73 | ## 2015-03-17 74 | 75 | - Add support for REMOTE_USER authentication (credit goes to: @abesto) 76 | 77 | ## 2015-03-16 78 | 79 | - Add support for SENTRY_PUBLIC (credit goes to: @abesto) 80 | 81 | ## 2015-03-12 82 | 83 | - Add support for configuring time-series storage (credit goes to: 84 | @abesto) 85 | 86 | ## 2015-03-07 87 | 88 | - Properly pass SIGTERM to sentry process (credit goes to: @lorenz) 89 | - new Sentry 7.4.X 90 | - move from fig to docker-compose while testing 91 | - when ``SENTRY_USE_REDIS_BUFFERS`` is used then ``sentry.cache.redis.RedisCache`` is configured as a ``SENTRY_CACHE`` 92 | 93 | ## 2015-02-23 94 | 95 | - updated ``requirements.txt`` (``django-redis``) 96 | - new Sentry 7.3.X 97 | 98 | ## 2015-02-12 99 | 100 | - updated ``requirements.txt`` (``django-auth-ldap`` and ``hiredis``) 101 | - new Sentry 7.2.X 102 | 103 | ## 2015-01-27 104 | 105 | - new tag/branch ``7.1`` 106 | - updated ``requirements.txt`` (``django-redis``) 107 | 108 | ## 2015-01-08 109 | 110 | - updated ``requirements.txt`` (``django-redis``) 111 | 112 | ## 2015-01-04 113 | 114 | - updated ``requirements.txt`` (``django-auth-ldap``) 115 | - new Sentry 7.0.X and several new build tags on docker hub 116 | 117 | ## 2014-12-07 118 | 119 | - updated ``django-redis`` to 3.8.0 120 | - provide builds from sentry's master github branch 121 | 122 | ## 2014-12-01 123 | 124 | - added ``SENTRY_ALLOW_ORIGIN`` - thanks to @josh-devops-center 125 | 126 | ## 2014-11-30 127 | 128 | - FIX: determine platform when creating a project (via ``SENTRY_INITIAL_PLATFORM``) - thanks to @josh-devops-center 129 | 130 | ## 2014-11-20 131 | 132 | - added ``SENTRY_INTIAL_DOMAINS`` for allowed domains (see #7) 133 | - allow setting ``SENTRY_SECURE_PROXY_SSL_HEADER`` and ``SENTRY_USE_X_FORWARDED_HOST`` (see #6) 134 | 135 | ## 2014-11-05 136 | 137 | - update django-redis requirement 138 | - add some cleanup at the end of build process 139 | - add new env vars for initial team, project and project key (``SENTRY_INITIAL_*``) 140 | - add new command ``prepare`` for the wrapper script to just prepare the datbase 141 | and other stuff without running the http sevice. 142 | 143 | ## 2014-10-09 144 | 145 | - change the name of the config script (this is a possible *breaking change* 146 | but now you can easily extend this image and configuration) 147 | - make it possible to "test" this image 148 | 149 | ## 2014-10-06 150 | 151 | - updated ``requirements.txt`` (``django-auth-ldap`` and ``hiredis``) 152 | - added some contribution guidelines 153 | 154 | ## 2014-09-09 155 | 156 | - added new setting ``SENTRY_ALLOW_REGISTRATION`` (credit goes to: @lukas-hetzenecker) 157 | - added LDAP backend support (``SENTRY_USE_LDAP`` and ``LDAP_*`` settings) 158 | (credit goes to: @lukas-hetzenecker) 159 | 160 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you feel like contributing to this repo or you think that something 4 | is missing here please consider forking this repo and open a pull request. 5 | 6 | ## Guidelines 7 | 8 | All files in this repo shouldn't be Docker specific 9 | (besides ``Dockerfile`` of course :P). 10 | That is you should be able to use a local installation of 11 | sentry (after installing required system dependencies as stated in 12 | ``Dockerfile``) and use files in this repo as a starting point 13 | for your sentry installation (after tweaking some env var like for example 14 | ``SENTRY_DATA_DIR``) 15 | 16 | ## Tests 17 | 18 | If you want to add a feature that requires some testing 19 | you can do this by creating a directory lets say ``feature_X`` 20 | inside ``tests/`` directory. 21 | 22 | This directory has to contain at least one file called ``docker-compose.yml`` 23 | which should define at least one service called ``test``. 24 | This service should define a container which will run the check 25 | whether or not your feature works with this image. 26 | This could be any script like a simple netcat (nc) call to 27 | check if a port is open on a given host. 28 | 29 | To run the tests you have to install docker-compose: 30 | 31 | pip install docker-compose 32 | 33 | Go to [docker-compose](http://docs.docker.com/compose/) page for more info about 34 | how to install and use Compose. 35 | 36 | Then you can run ``./run_tests.sh tests/feature_X``. 37 | 38 | You can run all the tests by running ``run_tests.sh`` script 39 | with no arguments. 40 | 41 | Refer to ``tests/simple_services/`` for an example of a simple 42 | testing script and a configuration file. 43 | 44 | Unfortunately as for now you should provide some kind of 45 | timeout (210 seconds should be enough) to let other containers 46 | start properly (i.e. sentry could create the database tables etc.) 47 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | 3 | MAINTAINER Sławek Ehlert 4 | 5 | RUN pip install -U wheel pip setuptools 6 | 7 | RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get install -y -q libxslt1-dev libxml2-dev libpq-dev libldap2-dev libsasl2-dev libssl-dev 8 | 9 | RUN mkdir -p /conf /data /wheels 10 | 11 | ADD requirements.txt /conf/ 12 | 13 | RUN pip wheel --wheel-dir=/wheels -r /conf/requirements.txt && pip install --find-links=/wheels -r /conf/requirements.txt 14 | 15 | EXPOSE 9000 16 | 17 | VOLUME ["/data"] 18 | 19 | ADD sentry_docker_conf.py /conf/ 20 | ADD sentry_run /usr/local/bin/ 21 | 22 | ENTRYPOINT ["/usr/local/bin/sentry_run"] 23 | 24 | CMD ["start"] 25 | 26 | ADD scripts/create_team_or_project.py /conf/ 27 | ADD scripts/check_db_isalive.py /conf/ 28 | 29 | # some cleanup 30 | RUN apt-get clean 31 | RUN rm -f /wheels/* 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sentry in Docker 2 | ================== 3 | 4 | ## Maintenance 5 | 6 | Since Sentry now [officially supports installation via Docker](https://github.com/getsentry/onpremise) - 7 | **this repository will no longer be updated**. 8 | 9 | More info on Sentry's Docker installation https://docs.sentry.io/server/installation/docker/. 10 | 11 | ## Warning about build tags 12 | 13 | Latest changes introduced some new build tags: 14 | 15 | * **8.0** - current stable version (8.0.X) 16 | * **7.7** - old stable version (7.7.4) - no longer updated 17 | * **7.6** - old stable version (7.6.2) - no longer updated 18 | * **7.5** - old stable version (7.5.6) - no longer updated 19 | * **7.4** - old stable version (7.4.3) - no longer updated 20 | * **7.3** - old stable version (7.3.2) - no longer updated 21 | * **7.2** - old stable version (7.2.0) - no longer updated 22 | * **7.1** - old stable version (7.1.4) - no longer updated 23 | * **7.0** - older stable version (7.0.2) - no longer updated 24 | * **6.4** - even older stable version (6.4.4) - no longer updated 25 | * **dev** - current master on github (infrequent builds) 26 | * **latest** (the default one used earlier) - is now the same as **8.0** 27 | 28 | if you want to keep your builds same as before update your Dockerfiles and change 29 | ```FROM slafs/sentry``` to ```FROM slafs/sentry:6.4```. 30 | 31 | [![Requirements Status](https://requires.io/github/slafs/sentry-docker/requirements.png?branch=master)](https://requires.io/github/slafs/sentry-docker/requirements/?branch=master) 32 | 33 | This is my approach for running [Sentry](https://getsentry.com) inside [Docker](https://docker.com/). 34 | Almost everything here is configurable via environment variables (including DATABASES and CACHES settings). 35 | It can be easily configured to run with redis (cache, buffers and celery broker), postgres database, LDAP and REMOTE_USER authentication backends. 36 | 37 | ## Quickstart 38 | 39 | to run a Sentry instance with default settings (with sqlite, locmem cache and no celery) run: 40 | 41 | ``` 42 | docker run -d --name=sentry --volume=/tmp/sentry:/data -p 80:9000 -e SECRET_KEY=randomvalue -e SENTRY_URL_PREFIX=http://sentry.mydomain.com slafs/sentry 43 | ``` 44 | 45 | You can visit now http://sentry.mydomain.com (assuming ``sentry.mydomain.com`` 46 | is mapped to your docker host) and login with default credentials 47 | (username ``admin`` and password ``admin``) and create your first team and project. 48 | 49 | Your sqlite database file and gunicorn logs are available in ``/tmp/sentry`` directory. 50 | 51 | ## Contributing 52 | 53 | Try not to fork this repo just to create your own Docker image with some 54 | minor tweak. Please open an [issue on GitHub](https://github.com/slafs/sentry-docker/issues) 55 | and maybe we can include your use case directly within this image :). 56 | 57 | You can even write a test case for your feature ;). See 58 | [CONTRIBUTING.md](https://github.com/slafs/sentry-docker/blob/master/CONTRIBUTING.md). 59 | 60 | Also feel free to give [feedback and comments](https://github.com/slafs/sentry-docker/issues) 61 | about this image in general. 62 | 63 | ## Advanced usage 64 | 65 | Copy the file with environment variables ``environment.example`` e.g ``cp environment.example environment`` 66 | and after tweaking some values run sentry like this 67 | 68 | ``` 69 | docker run -d --name=sentry --volume=/tmp/sentry:/data -p 80:9000 --env-file=environment slafs/sentry 70 | ``` 71 | 72 | ``ENTRYPOINT`` for this image is a little wrapper script around default ``sentry`` executable. 73 | Default ``CMD`` is ``start`` which runs ``upgrade`` command (initializes and upgrades the database) 74 | and creates a default administrator (superuser) and then runs a http service (as in ``sentry --config=... start``). 75 | 76 | All commands and args are passed to the ``sentry`` executable. This means 77 | 78 | ``` 79 | docker run [docker options] slafs/sentry --help 80 | ``` 81 | 82 | refers to running: 83 | 84 | ``` 85 | sentry --config=/conf/sentry.conf.py --help 86 | ``` 87 | 88 | inside the container. 89 | 90 | ### Admin user 91 | 92 | You can specify a username, password and email address to create an initial sentry administrator. 93 | 94 | Add those variables to your environment file 95 | 96 | ``` 97 | SENTRY_ADMIN_USERNAME=slafs 98 | SENTRY_ADMIN_PASSWORD=mysecretpass 99 | SENTRY_ADMIN_EMAIL=slafs@foo.com 100 | ``` 101 | 102 | See [django docs](https://docs.djangoproject.com/en/1.5/ref/django-admin/#createsuperuser) for details about ``createsuperuser`` command. 103 | 104 | The default administrator username is ``admin`` with password ``admin`` (and ``root@localhost`` as email adress). 105 | 106 | ### Postgres 107 | 108 | It is recommended to run your sentry instance with PostgreSQL database. 109 | To link your sentry instance with a postgres container you can do it like this: 110 | 111 | 0. Pull an official PostgreSQL image: ``docker pull postgres`` (if you haven't already). 112 | 1. Run postgres container (from the official Docker image): ``docker run -d --name=postgres_container postgres``. 113 | 2. Add ``DATABASE_URL=postgres://postgres:@postgresdb/postgres`` to environment file. 114 | 3. Run sentry with linked postgres container: ``` 115 | docker run -d --name=sentry --volume=/tmp/sentry:/data -p 80:9000 --env-file=environment --link=postgres_container:postgresdb slafs/sentry``` 116 | 117 | Notice that an alias for your linked postgres container (``postgresdb``) is the same as a postgres host in ``DATABASE_URL`` variable. 118 | 119 | ``DATABASE_URL`` is a value that is parsed by an external app called [dj-database-url](https://github.com/kennethreitz/dj-database-url). 120 | 121 | 122 | ### Redis 123 | 124 | Redis container can be used to improve sentry performance in number of ways. It can be used as a: 125 | 126 | * cache backend, 127 | * sentry buffers, 128 | * celery broker. 129 | 130 | You can link your sentry instance with a redis container like this: 131 | 132 | 0. Pull an official Redis image: ``docker pull redis`` (if you haven't already). 133 | 1. Run redis container (from the official Docker image): ``docker run -d --name=redis_container redis`` 134 | 2. ``` 135 | docker run -d --name=sentry --volume=/tmp/sentry:/data -p 80:9000 --env-file=environment --link=postgres_container:postgresdb --link=redis_container:redis slafs/sentry``` 136 | 137 | If you want to use a different container alias for redis you should add ```SENTRY_REDIS_HOST=your_redis_alias``` to environment file. 138 | 139 | #### Cache with redis 140 | 141 | To use a redis cache backend add ``CACHE_URL=hiredis://redis:6379/2`` 142 | (make sure you won't have a trailing `/` in this setting) 143 | to environment file (where ``redis`` is the alias of your linked redis container). 144 | See [django-cache-url](https://github.com/ghickman/django-cache-url) docs for available formats. 145 | 146 | #### Sentry buffers with redis 147 | 148 | To use [sentry update buffers](https://docs.getsentry.com/on-premise/server/buffer/) 149 | with redis you must add ``SENTRY_USE_REDIS_BUFFERS=True`` to environment file. 150 | 151 | If you have many redis containers/hosts you can set a list of those hosts 152 | in ``SENTRY_REDIS_BUFFERS`` variable so they can be used by sentry. 153 | Like this: ``SENTRY_REDIS_BUFFERS=redis1:6380,redis2:6381``. 154 | 155 | See [sentry docs](https://docs.getsentry.com/on-premise/server/buffer/#redis) for details about redis buffer. 156 | 157 | #### Celery with redis (and postgres) 158 | 159 | To use Celery in sentry you must add ``CELERY_ALWAYS_EAGER=False`` to your environment file and run a celery worker like this: 160 | 161 | ``` 162 | docker run -d --name=sentry_celery_worker --link=redis_container:redis --link=postgres_container:postgresdb --volume=/tmp/sentry:/data --env-file=environment slafs/sentry celery worker -B 163 | ``` 164 | 165 | You can also set a different ``BROKER_URL`` via environment file by adding this: 166 | ``SENTRY_BROKER_URL=redis://otherredishost:6379/1`` 167 | 168 | You can run as many celery worker containers as you want but remember that only one of them should be run with ``-B`` option. 169 | 170 | If you're using default values for `CELERY_RESULT_SERIALIZER`, `CELERY_TASK_SERIALIZER` 171 | and `CELERY_ACCEPT_CONTENT` (default values support `pickle`) 172 | you have to set `C_FORCE_ROOT` env var (to say `1`) 173 | to be able to run celery as a `root` user. 174 | You can avoid this by setting those three to `json`. 175 | Refer to [Celery's serializer docs](docs.celeryproject.org/en/latest/userguide/security.html#serializers) 176 | for more info about security implications of using `pickle` as a task serialization format. 177 | 178 | #### Time-series storage with redis 179 | 180 | To have [time-series data](https://docs.getsentry.com/on-premise/server/tsdb/) you must add 181 | ``SENTRY_USE_REDIS_TSDB=True`` to the environment file. 182 | 183 | By default Redis time-series storage will use the Redis connection 184 | defined by ``SENTRY_REDIS_HOST`` and ``SENTRY_REDIS_PORT``. Similarly 185 | to configuring buffers, you can set ``SENTRY_REDIS_TSDBS`` to a list 186 | of Redis servers: ``SENTRY_REDIS_TSDBS=redis1:6379,redis2:6380`` 187 | 188 | ### Email 189 | 190 | You can configure all [email settings](https://docs.getsentry.com/on-premise/server/config/#smtp-server) 191 | by environment variables with ``SENTRY_`` prefix. 192 | You have to also change an email backend and set it 193 | to ``SENTRY_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend`` or something similar. 194 | 195 | ### LDAP 196 | With this image You should be able to easily configure LDAP authentication for your Sentry instance. 197 | To enable it add ``SENTRY_USE_LDAP=True`` to your ``environment`` file. 198 | Then set the needed options by adding env variables with ``LDAP_`` 199 | prefix (see the table below). LDAP authentication backend is provided by 200 | [django-auth-ldap](https://pythonhosted.org/django-auth-ldap/). 201 | 202 | ### REMOTE_USER 203 | To enable authentication via REMOTE_USER, add ``SENTRY_USE_REMOTE_USER=True`` to your ``environment`` file. 204 | See the ``AUTH_REMOTE_USER_*`` env variables below for further configuration. 205 | 206 | ## Available environment variables 207 | 208 | Refer to [sentry documentation](https://docs.getsentry.com/on-premise/server/config/), 209 | [django documentation](https://docs.djangoproject.com/en/1.6/ref/settings/), 210 | [celery documentation](http://docs.celeryproject.org/en/latest/) 211 | and [django-auth-ldap documentation](https://pythonhosted.org/django-auth-ldap/reference.html) 212 | for the meaning of each setting. 213 | 214 | Environment variable name | Django/Sentry setting | Type | Default value | Description 215 | --------------------------------|-----------------------------------------------|------|-------------------------------------------------------|------------------------------------------------------------------------ 216 | SECRET_KEY | SECRET_KEY | | **REQUIRED!** | set this to something random 217 | SENTRY_URL_PREFIX | SENTRY_URL_PREFIX | | **REQUIRED!** | no trailing slash! 218 | DATABASE_URL | DATABASES | | sqlite:////data/sentry.db | 219 | CACHE_URL | CACHES | | locmem:// | 220 | CELERY_ALWAYS_EAGER | CELERY_ALWAYS_EAGER | bool | True | 221 | SENTRY_BROKER_URL | BROKER_URL | | ``redis://:/1`` | 222 | CELERY_RESULT_SERIALIZER | CELERY_RESULT_SERIALIZER | | ``pickle`` | You may want change it to ``json``. See http://docs.celeryproject.org/en/stable/configuration.html#celery-result-serializer 223 | CELERY_TASK_SERIALIZER | CELERY_TASK_SERIALIZER | | ``pickle`` | You may want change it to ``json``. See http://docs.celeryproject.org/en/stable/configuration.html#celery-task-serializer 224 | CELERY_ACCEPT_CONTENT | CELERY_ACCEPT_CONTENT | list | ``pickle,json`` | Comma separated values. You may want change it to ``json``. See http://docs.celeryproject.org/en/stable/configuration.html#celery-accept-content 225 | SENTRY_REDIS_HOST | | | redis | 226 | SENTRY_REDIS_PORT | | int | 6379 | 227 | SENTRY_WEB_HOST | SENTRY_WEB_HOST | | 0.0.0.0 | 228 | SENTRY_WEB_PORT | SENTRY_WEB_PORT | int | 9000 | 229 | SENTRY_WORKERS | SENTRY_WEB_OPTIONS['workers'] | int | 3 | the number of gunicorn workers 230 | SENTRY_USE_REDIS_BUFFERS | | bool | False | 231 | SENTRY_REDIS_BUFFERS | SENTRY_REDIS_OPTIONS['hosts']* | list | ``:`` | comma separated list of redis hosts (``host1:port1,host2:port2,...``) 232 | SENTRY_USE_REDIS_TSDB | | bool | False | 233 | SENTRY_REDIS_TSDBS | SENTRY_TSDB_OPTIONS['hosts']* | list | ``:`` | comma separated list of redis hosts (``host1:port1,host2:port2,...``) 234 | SENTRY_EMAIL_BACKEND | EMAIL_BACKEND | | django.core.mail.backends.console.EmailBackend | 235 | SENTRY_EMAIL_HOST | EMAIL_HOST | | localhost | 236 | SENTRY_EMAIL_HOST_PASSWORD | EMAIL_HOST_PASSWORD | | '' | 237 | SENTRY_EMAIL_HOST_USER | EMAIL_HOST_USER | | '' | 238 | SENTRY_EMAIL_PORT | EMAIL_PORT | int | 25 | 239 | SENTRY_EMAIL_USE_TLS | EMAIL_USE_TLS | bool | False | 240 | SENTRY_SERVER_EMAIL | SERVER_EMAIL | | root@localhost | 241 | SENTRY_ALLOW_REGISTRATION | SENTRY_ALLOW_REGISTRATION | bool | False | 242 | SENTRY_ADMIN_USERNAME | | | admin | username for Sentry's superuser 243 | SENTRY_ADMIN_PASSWORD | | | admin | password for Sentry's superuser 244 | SENTRY_ADMIN_EMAIL | SENTRY_ADMIN_EMAIL | | root@localhost | email address for Sentry's superuser and a setting as of Sentry 7.3 245 | SENTRY_DATA_DIR | | | ``/data`` | custom location for logs and sqlite database 246 | TWITTER_CONSUMER_KEY | TWITTER_CONSUMER_KEY | | '' | 247 | TWITTER_CONSUMER_SECRET | TWITTER_CONSUMER_SECRET | | '' | 248 | FACEBOOK_APP_ID | FACEBOOK_APP_ID | | '' | 249 | FACEBOOK_API_SECRET | FACEBOOK_API_SECRET | | '' | 250 | GOOGLE_OAUTH2_CLIENT_ID | GOOGLE_OAUTH2_CLIENT_ID | | '' | 251 | GOOGLE_OAUTH2_CLIENT_SECRET | GOOGLE_OAUTH2_CLIENT_SECRET | | '' | 252 | GITHUB_APP_ID | GITHUB_APP_ID | | '' | 253 | GITHUB_API_SECRET | GITHUB_API_SECRET | | '' | 254 | TRELLO_API_KEY | TRELLO_API_KEY | | '' | 255 | TRELLO_API_SECRET | TRELLO_API_SECRET | | '' | 256 | BITBUCKET_CONSUMER_KEY | BITBUCKET_CONSUMER_KEY | | '' | 257 | BITBUCKET_CONSUMER_SECRET | BITBUCKET_CONSUMER_SECRET | | '' | 258 | SENTRY_USE_LDAP | | bool | False | if set to ``False`` all other LDAP settings are discarded 259 | LDAP_SERVER | AUTH_LDAP_SERVER_URI | | ``ldap://localhost`` | 260 | LDAP_BIND_DN | AUTH_LDAP_BIND_DN | | '' | 261 | LDAP_BIND_PASSWORD | AUTH_LDAP_BIND_PASSWORD | | '' | 262 | LDAP_USER_DN | AUTH_LDAP_USER_SEARCH* | | **REQUIRED!** if you want to use LDAP auth | first argument of LDAPSearch (base_dn) when searching for users 263 | LDAP_USER_FILTER | AUTH_LDAP_USER_SEARCH* | | ``(&(objectClass=inetOrgPerson)(cn=%(user)s))`` | third argument of LDAPSearch (filterstr) when searching for users 264 | LDAP_GROUP_DN | AUTH_LDAP_GROUP_SEARCH* | | '' | first argument of LDAPSearch (base_dn) when searching for groups 265 | LDAP_GROUP_FILTER | AUTH_LDAP_GROUP_SEARCH* | | ``(objectClass=groupOfUniqueNames)`` | third argument of LDAPSearch (filterstr) when searching for groups 266 | LDAP_GROUP_TYPE | AUTH_LDAP_GROUP_TYPE* | | '' | if set to 'groupOfUniqueNames' then ``AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType()``, if set to 'posixGroup' then ``AUTH_LDAP_GROUP_TYPE = PosixGroupType()``. 267 | LDAP_REQUIRE_GROUP | AUTH_LDAP_REQUIRE_GROUP | | None | 268 | LDAP_DENY_GROUP | AUTH_LDAP_DENY_GROUP | | None | 269 | LDAP_MAP_FIRST_NAME | AUTH_LDAP_USER_ATTR_MAP['first_name'] | | ``givenName`` | 270 | LDAP_MAP_LAST_NAME | AUTH_LDAP_USER_ATTR_MAP['last_name'] | | ``sn`` | 271 | LDAP_MAP_MAIL | AUTH_LDAP_USER_ATTR_MAP['email'] | | ``mail`` | 272 | LDAP_GROUP_ACTIVE | AUTH_LDAP_USER_FLAGS_BY_GROUP['is_active'] | | '' | 273 | LDAP_GROUP_STAFF | AUTH_LDAP_USER_FLAGS_BY_GROUP['is_staff'] | | '' | 274 | LDAP_GROUP_SUPERUSER | AUTH_LDAP_USER_FLAGS_BY_GROUP['is_superuser'] | | '' | 275 | LDAP_FIND_GROUP_PERMS | AUTH_LDAP_FIND_GROUP_PERMS | bool | False | 276 | LDAP_CACHE_GROUPS | AUTH_LDAP_CACHE_GROUPS | bool | True | 277 | LDAP_GROUP_CACHE_TIMEOUT | AUTH_LDAP_GROUP_CACHE_TIMEOUT | int | 3600 | 278 | LDAP_LOGLEVEL | | | ``DEBUG`` | django_auth_ldap logger level (other values: NOTSET (to disable), INFO, WARNING, ERROR or CRITICAL) 279 | SENTRY_USE_REMOTE_USER | | bool | False | use `REMOTE_USER` for authentication; useful if you're behind your own SSO 280 | AUTH_REMOTE_USER_HEADER | | | None | if set, this value will be read from the request object instead of `REMOTE_USER`, as described [here](https://docs.djangoproject.com/en/1.7/howto/auth-remote-user/). For example: `HTTP_X_SSO_USERNAME` 281 | SENTRY_INITIAL_TEAM | | | | convenient in development - creates an initial team inside Sentry DB with the given name 282 | SENTRY_INITIAL_PROJECT | | | | convenient in development - creates an initial project for the above team (owner for both is the created admin ) 283 | SENTRY_INITIAL_PLATFORM | | | 'python' | convenient in development - indicates a platform for the above initial project 284 | SENTRY_INITIAL_KEY | | | | convenient in development - updates a key for the above project so you can set DSN in your client. (e.g. ``public:secret``) 285 | SENTRY_INITIAL_DOMAINS | | | | convenient in development - updates allowed domains for usage with raven-js e.g. ``example.com *.example.com`` (space separated) 286 | SENTRY_SCRIPTS_DIR | | | | convenient in development - required for the wrapper and non Docker scenarios (you can leave this empty) 287 | SENTRY_SECURE_PROXY_SSL_HEADER | SECURE_PROXY_SSL_HEADER | | None | when running with SSL set this to 'HTTP_X_FORWARDED_PROTO,https' (comma separated) 288 | SENTRY_USE_X_FORWARDED_HOST | USE_X_FORWARDED_HOST | bool | False | when running behind proxy or with SSL set this to 'True' 289 | SENTRY_ALLOW_ORIGIN | SENTRY_ALLOW_ORIGIN | | None | allows JavaScript clients to submit cross-domain error reports. (e.g. ``"http://foo.example"`` 290 | SENTRY_BEACON | SENTRY_BEACON | bool | True | controls sending statistics to https://www.getsentry.com/remote/beacon/ 291 | SENTRY_PUBLIC | SENTRY_PUBLIC | bool | False | Should Sentry make all data publicly accessible? This should only be used if you’re installing Sentry behind your company’s firewall. 292 | SENTRY_DOCKER_DO_DB_CHECK | | any | | if this variable is set (to any non-empty value) the script (``sentry_run``) will check if DB is accessible before running migrations/service - helps to avoid nasty race conditions 293 | 294 | 295 | ## Extending the image ## 296 | 297 | If your use case is out the scope of this generic image, you can 298 | extend this image to include your custom packages, configuration etc. and 299 | still be able to take advantage of all features here. All you need to do is create 300 | your own image based on this one. 301 | 302 | For example to install and use a plugin like sentry-github 303 | and/or change a setting that isn't managed by this image you can have a following 304 | config script ``my_custom_settings.py``: 305 | 306 | # get all the configuration from the original image 307 | from sentry_docker_conf import * # noqa 308 | 309 | # change some settings - for example the port 310 | # (of course you can do this also by setting environment variable ``SENTRY_WEB_PORT``) 311 | SENTRY_WEB_PORT = 5000 312 | 313 | # configure sentry-github 314 | GITHUB_APP_ID = 'GitHub Application Client ID' 315 | GITHUB_API_SECRET = 'GitHub Application Client Secret' 316 | GITHUB_EXTENDED_PERMISSIONS = ['repo'] 317 | ... 318 | 319 | and a ``Dockerfile`` similar to this: 320 | 321 | # inherit from this image 322 | FROM slafs/sentry 323 | 324 | # who's the boss? :) 325 | MAINTAINER me 326 | 327 | # install your extra dependencies e.g. sentry-github 328 | # (there are some dependency issues with redis) 329 | RUN pip install -U sentry-github "redis<2.9.0" 330 | 331 | # add your custom settings file 332 | ADD my_custom_settings.py /conf/ 333 | 334 | # make sentry_docker_conf module importable from your custom script 335 | ENV PYTHONPATH /conf 336 | 337 | # use your custom settings file as a default config file for sentry to use 338 | ENV SENTRY_CONF_FILE /conf/my_custom_settings.py 339 | 340 | # expose the new port 341 | EXPOSE 5000 342 | 343 | 344 | Build your image: 345 | 346 | docker build -t my_custom_sentry_image . 347 | 348 | Now you can run your sentry instance just like before but with different image. 349 | So for example this: 350 | 351 | ``` 352 | docker run -d --name=... --volume=... -p 80:9000 -e SECRET_KEY=... -e SENTRY_URL_PREFIX=http://... slafs/sentry 353 | ``` 354 | 355 | becomes this: 356 | 357 | ``` 358 | docker run -d --name=... --volume=... -p 80:5000 -e SECRET_KEY=... -e SENTRY_URL_PREFIX=http://... my_custom_sentry_image 359 | ``` 360 | 361 | ### Image for development 362 | 363 | If you'd like to use a preconfigured image just to be able to use it in your 364 | development process (for example to check if your application is properly logging to sentry) 365 | you can also create your own image for this. 366 | 367 | Following ``Dockerfile`` should be OK:: 368 | 369 | # inherit from this image 370 | FROM slafs/sentry 371 | 372 | # who's the boss? :) 373 | MAINTAINER me 374 | 375 | ENV SECRET_KEY somethingsecret 376 | ENV SENTRY_URL_PREFIX http://sentry.domain.com 377 | 378 | ENV SENTRY_INITIAL_TEAM testteam 379 | ENV SENTRY_INITIAL_PROJECT testproject 380 | ENV SENTRY_INITIAL_KEY public:secret 381 | 382 | RUN /usr/local/bin/sentry_run prepare 383 | 384 | Now after building it (like in the above example) ``my_custom_sentry_image`` can 385 | be started without any env variables and you can use ``http://public:secret@sentry.domain.com:9000/2`` 386 | as your ``SENTRY_DSN`` setting for raven (or other sentry client of your choice). 387 | -------------------------------------------------------------------------------- /environment.example: -------------------------------------------------------------------------------- 1 | ### required settings 2 | 3 | SENTRY_URL_PREFIX= 4 | SECRET_KEY= 5 | 6 | ### other settings 7 | ### (https://docs.djangoproject.com/en/1.5/ref/settings/) 8 | ### (http://sentry.readthedocs.org/en/latest/config/index.html) 9 | 10 | ## celery 11 | #CELERY_ALWAYS_EAGER=False 12 | #SENTRY_BROKER_URL=redis://redis:6379/1 13 | #CELERY_RESULT_SERIALIZER=json 14 | #CELERY_TASK_SERIALIZER=json 15 | #CELERY_ACCEPT_CONTENT=json 16 | 17 | # if you're accepting pickled tasks (the default) you should enable this 18 | #C_FORCE_ROOT=1 19 | 20 | ## make everything "public" (readable by all logged in users) 21 | #SENTRY_PUBLIC=True 22 | 23 | ## postgres DB 24 | #DATABASE_URL=postgres://postgres:@postgres/postgres 25 | 26 | ## cache 27 | #CACHE_URL=hiredis://redis:6379/2 28 | 29 | ## redis buffers 30 | #SENTRY_USE_REDIS_BUFFERS=True 31 | #SENTRY_REDIS_BUFFERS=redis1:6379,redis2:6379 32 | 33 | ## redis time-series storage 34 | #SENTRY_USE_REDIS_TSDB=True 35 | #SENTRY_REDIS_TSDBS=redis1:6379,redis2:6379 36 | 37 | ## initial superuser 38 | #SENTRY_ADMIN_USERNAME=bob 39 | #SENTRY_ADMIN_PASSWORD=mysecretpass 40 | #SENTRY_ADMIN_EMAIL=bob@foo.com 41 | 42 | ## email settings 43 | #SENTRY_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend 44 | #SENTRY_EMAIL_HOST=localhost 45 | #SENTRY_EMAIL_HOST_PASSWORD='' 46 | #SENTRY_EMAIL_HOST_USER='' 47 | #SENTRY_EMAIL_PORT=25 48 | #SENTRY_EMAIL_USE_TLS=False 49 | #SENTRY_SERVER_EMAIL=root@localhost 50 | 51 | ## social auth 52 | #TWITTER_CONSUMER_KEY="" 53 | #TWITTER_CONSUMER_SECRET="" 54 | #FACEBOOK_APP_ID="" 55 | #FACEBOOK_API_SECRET="" 56 | #GOOGLE_OAUTH2_CLIENT_ID="" 57 | #GOOGLE_OAUTH2_CLIENT_SECRET="" 58 | #GITHUB_APP_ID="" 59 | #GITHUB_API_SECRET="" 60 | #TRELLO_API_KEY="" 61 | #TRELLO_API_SECRET="" 62 | #BITBUCKET_CONSUMER_KEY="" 63 | #BITBUCKET_CONSUMER_SECRET="" 64 | 65 | 66 | ## LDAP (https://pythonhosted.org/django-auth-ldap/reference.html) 67 | #SENTRY_USE_LDAP=True 68 | #LDAP_SERVER=ldap://localhost 69 | #LDAP_BIND_DN=cn=admin,dc=example,dc=com 70 | #LDAP_BIND_PASSWORD=ldapadminpassword 71 | #LDAP_USER_DN=REQUIRED! e.g. ou=users,dc=example,dc=com 72 | #LDAP_USER_FILTER=(&(objectClass=inetOrgPerson)(cn=%(user)s)) 73 | #LDAP_GROUP_DN=ou=django,ou=groups,dc=example,dc=com 74 | #LDAP_GROUP_FILTER=(objectClass=groupOfUniqueNames) 75 | #LDAP_REQUIRE_GROUP=cn=enabled,ou=django,ou=groups,dc=example,dc=com 76 | #LDAP_DENY_GROUP=cn=disabled,ou=django,ou=groups,dc=example,dc=com 77 | #LDAP_GROUP_TYPE='groupOfUniqueNames' 78 | #LDAP_MAP_FIRST_NAME=givenName 79 | #LDAP_MAP_LAST_NAME=sn 80 | #LDAP_MAP_MAIL=mail 81 | #LDAP_GROUP_ACTIVE=cn=active,ou=django,ou=groups,dc=example,dc=com 82 | #LDAP_GROUP_STAFF=cn=staff,ou=django,ou=groups,dc=example,dc=com 83 | #LDAP_GROUP_SUPERUSER=cn=superuser,ou=django,ou=groups,dc=example,dc=com 84 | #LDAP_FIND_GROUP_PERMS=False 85 | #LDAP_CACHE_GROUPS=True 86 | #LDAP_GROUP_CACHE_TIMEOUT=3600 87 | 88 | 89 | ## REMOTE_USER (https://docs.djangoproject.com/en/stable/howto/auth-remote-user/) 90 | #SENTRY_USE_REMOTE_USER=True 91 | #AUTH_REMOTE_USER_HEADER=HTTP_X_SSO_USERNAME 92 | 93 | ## others 94 | #SENTRY_ALLOW_REGISTRATION=True 95 | #SENTRY_DATA_DIR=/data 96 | #SENTRY_SCRIPTS_DIR=/conf 97 | #SENTRY_BEACON=False 98 | 99 | ## bootstraping a project 100 | #SENTRY_INITIAL_TEAM=testteam 101 | #SENTRY_INITIAL_PROJECT=testproject 102 | #SENTRY_INITIAL_KEY=public:secret 103 | #SENTRY_INITIAL_DOMAINS="domain.com *.domain.com" 104 | #SENTRY_DOCKER_DO_DB_CHECK=yes 105 | 106 | ## Proxy & SSL 107 | #SENTRY_SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https 108 | #SENTRY_USE_X_FORWARDED_HOST=True 109 | 110 | ## allows JavaScript clients to submit cross-domain error reports. 111 | #SENTRY_ALLOW_ORIGIN="http://foo.example" 112 | 113 | ## control python warnings. See https://docs.python.org/2/library/warnings.html for available values 114 | #PYTHONWARNINGS=ignore 115 | -------------------------------------------------------------------------------- /environment.nodocker.example: -------------------------------------------------------------------------------- 1 | ### a minimal set of settings for running without docker 2 | 3 | export SENTRY_URL_PREFIX=http://sentry.slafs.com 4 | export SECRET_KEY=secret 5 | export SENTRY_DATA_DIR=/tmp/sentry 6 | export SENTRY_SCRIPTS_DIR=./scripts 7 | export SENTRY_CONF_FILE=./sentry_docker_conf.py 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # env config 2 | python-decouple==3.0 3 | django-cache-url==1.0.0 4 | dj-database-url==0.3.0 5 | 6 | # cache with redis 7 | django-redis==4.3.0 8 | hiredis==0.2.0 9 | 10 | # sentry 11 | sentry[postgres]==8.0.6 12 | 13 | # ldap user store 14 | django-auth-ldap==1.2.7 15 | 16 | -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 4 | ## this is a simple script to run series of tests 5 | ## and check if this project is doing OK. 6 | ## 7 | 8 | #set -x 9 | 10 | DIR_TO_TEST=${1:-"./tests"} 11 | last_errorcode=0 12 | 13 | 14 | for composefile in $(find $DIR_TO_TEST -name docker-compose.yml); do 15 | echo -e "\033[33m-------------------------\033[0m" 16 | echo -e "\033[33mtrying $composefile\033[0m" 17 | echo -e "\033[33m-------------------------\033[0m" 18 | 19 | COMPOSE="docker-compose -f $composefile" 20 | 21 | $COMPOSE build 22 | $COMPOSE run --rm test 23 | exitcode=$? 24 | if [ "$exitcode" == "0" ]; then 25 | echo -e "\033[32mSUCCESS $composefile\033[0m" 26 | else 27 | last_errorcode=$exitcode 28 | echo -e "\033[31mFAILURE $composefile\033[0m" 29 | fi 30 | 31 | $COMPOSE stop 32 | $COMPOSE rm -v --force 33 | done 34 | 35 | if [ "$last_errorcode" == "0" ]; then 36 | echo -e "\033[32mSUCCESS\033[0m" 37 | else 38 | last_errorcode=$exitcode 39 | echo -e "\033[31mFAILURE\033[0m" 40 | fi 41 | 42 | exit $last_errorcode 43 | -------------------------------------------------------------------------------- /scripts/check_db_isalive.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | Simple script to determine if the database is already running 5 | """ 6 | from __future__ import print_function 7 | import sys 8 | import time 9 | 10 | # Bootstrap the Sentry environment 11 | from sentry.utils.runner import configure 12 | configure() 13 | 14 | # Do something crazy 15 | from django.db import connections, OperationalError 16 | 17 | 18 | def is_db_alive(conn): 19 | try: 20 | c = conn.cursor() # this will take some time if error 21 | except OperationalError: 22 | reachable = False 23 | else: 24 | reachable = True 25 | c.close() 26 | 27 | return reachable 28 | 29 | 30 | def main(): 31 | max_retries = 10 32 | sleep_time = 3 33 | 34 | if len(sys.argv) > 1: 35 | max_retries = int(sys.argv[1]) 36 | 37 | if len(sys.argv) > 2: 38 | sleep_time = int(sys.argv[2]) 39 | 40 | conn = connections['default'] 41 | 42 | for i in range(max_retries): 43 | 44 | if is_db_alive(conn): 45 | sys.exit(0) 46 | 47 | time.sleep(sleep_time) 48 | 49 | sys.exit(1) 50 | 51 | 52 | if __name__ == '__main__': 53 | main() 54 | -------------------------------------------------------------------------------- /scripts/create_team_or_project.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | from __future__ import print_function 4 | import sys 5 | 6 | # Bootstrap the Sentry environment 7 | from sentry.utils.runner import configure 8 | configure() 9 | 10 | # Do something crazy 11 | import sentry 12 | from sentry.models import Team, Project, ProjectKey, User, Organization 13 | from sentry.web.frontend.project_settings import OriginsField 14 | from django.forms import ValidationError 15 | from django.db.utils import IntegrityError 16 | 17 | SENTRY_VERSION = tuple(map(lambda x: int(x) if x.isdigit() else x, sentry.get_version().split('.'))) 18 | 19 | 20 | def mark_as_configured(): 21 | sentry.options.set('sentry:version-configured', sentry.get_version()) 22 | 23 | 24 | def create_team(admin_username, team_name, organization_name=None): 25 | user = User.objects.get(username=admin_username) 26 | if organization_name is None: 27 | organization_name = team_name 28 | org, new_org = Organization.objects.get_or_create(name=organization_name) 29 | org_member, member_created = org.members.through.objects.get_or_create(organization=org, user=user, 30 | defaults={'role': 'owner'}) 31 | team, new = Team.objects.get_or_create(name=team_name, 32 | defaults={'organization': org}) 33 | return team, new 34 | 35 | 36 | def create_admin(username, email, password): 37 | try: 38 | admin = User.objects.create_superuser(username=username, email=email, password=password) 39 | except IntegrityError: 40 | print('Superuser "{0}" is already present.'.format(username)) 41 | else: 42 | print('Superuser "{0}" created successfully.'.format(username)) 43 | return admin 44 | finally: 45 | mark_as_configured() 46 | 47 | 48 | def create_project(team_name, project_name): 49 | team = Team.objects.get(name=team_name) 50 | defaults = {'organization': team.organization} 51 | project, new = Project.objects.get_or_create(name=project_name, team=team, 52 | defaults=defaults) 53 | 54 | return project, new 55 | 56 | 57 | def enforce_key(project, key_string): 58 | key = ProjectKey.objects.get(project=project) 59 | public, secret = key_string.split(':') 60 | key.public_key = public 61 | key.secret_key = secret 62 | key.save() 63 | 64 | 65 | def update_origins(team_name, project_name, origins): 66 | ''' 67 | ``origins`` should be space separated 68 | ''' 69 | project = Project.objects.get(name=project_name, team__name=team_name) 70 | 71 | # prepare for input 72 | new_origins = "\n".join(origins.split()) 73 | origins_field = OriginsField() 74 | try: 75 | values = origins_field.clean(new_origins) 76 | except ValidationError as ex: 77 | print('x ! ' * 50) 78 | print('Something went wrong while updating allowed domains:') 79 | print(ex) 80 | print('x ! ' * 50) 81 | else: 82 | project.update_option('sentry:origins', values or []) 83 | 84 | 85 | def print_dsn(project): 86 | key = ProjectKey.objects.get(project=project) 87 | print('=' * 50) 88 | print('You have a project called {0}. You can use the following DSN' 89 | .format(project.name)) 90 | print('SENTRY_DSN = "{0}"'.format(key.get_dsn())) 91 | print('=' * 50) 92 | 93 | 94 | def main(): 95 | '''CLI usage: 96 | 97 | to create a team:: 98 | 99 | python create_team_or_project.py team adminusername teamname 100 | 101 | to create a project:: 102 | 103 | python create_team_or_project.py project teamname projectname 104 | 105 | to modify key for a project:: 106 | 107 | python create_team_or_project.py key teamname projectname public:secret 108 | 109 | to modify allowed domains for a project pass a space separated list like this:: 110 | 111 | python create_team_or_project.py origins teamname projectname 'example.com *.example.com' 112 | 113 | to create a superuser:: 114 | 115 | python create_team_or_project.py admin username email@foo.bar password 116 | ''' 117 | command = sys.argv[1] 118 | if command == 'team': 119 | admin_username = sys.argv[2] 120 | team_name = sys.argv[3] 121 | team, _ = create_team(admin_username, team_name) 122 | elif command in ('project', 'key'): 123 | team_name = sys.argv[2] 124 | project_name = sys.argv[3] 125 | project, proj_created = create_project(team_name, project_name) 126 | 127 | if command == 'key': 128 | key = sys.argv[4] 129 | enforce_key(project, key) 130 | print_dsn(project) 131 | elif proj_created is True: 132 | print_dsn(project) 133 | elif command in ('origins',): 134 | team_name = sys.argv[2] 135 | project_name = sys.argv[3] 136 | origins = sys.argv[4] 137 | update_origins(team_name, project_name, origins) 138 | elif command in ('admin',): 139 | username = sys.argv[2] 140 | email = sys.argv[3] 141 | password = sys.argv[4] 142 | create_admin(username, email, password) 143 | 144 | if __name__ == '__main__': 145 | main() 146 | -------------------------------------------------------------------------------- /sentry_docker_conf.py: -------------------------------------------------------------------------------- 1 | # This file is just Python, with a touch of Django which means you 2 | # you can inherit and tweak settings to your hearts content. 3 | from sentry.conf.server import * # noqa 4 | import os.path 5 | 6 | from decouple import config 7 | import dj_database_url 8 | import django_cache_url 9 | import functools 10 | 11 | CONF_ROOT = os.path.dirname(__file__) 12 | DATA_DIR = config('SENTRY_DATA_DIR', default='/data') 13 | DEFAULT_SQLITE_DB_PATH = os.path.join(DATA_DIR, 'sentry.db') 14 | 15 | REDIS_HOST = config('SENTRY_REDIS_HOST', default='redis') 16 | REDIS_PORT = config('SENTRY_REDIS_PORT', default=6379, cast=int) 17 | 18 | DATABASES = { 19 | 'default': dj_database_url.config(default='sqlite:///{0}'.format(DEFAULT_SQLITE_DB_PATH)) 20 | } 21 | 22 | if 'postgres' in DATABASES['default']['ENGINE']: 23 | DATABASES['default']['ENGINE'] = 'sentry.db.postgres' 24 | 25 | # You should not change this setting after your database has been created 26 | # unless you have altered all schemas first 27 | SENTRY_USE_BIG_INTS = config('SENTRY_USE_BIG_INTS', default=False, cast=bool) 28 | 29 | SENTRY_SINGLE_ORGANIZATION = config('SENTRY_SINGLE_ORGANIZATION', default=True, cast=bool) 30 | 31 | CACHES = {'default': django_cache_url.config() } 32 | SENTRY_CACHE = 'sentry.cache.django.DjangoCache' 33 | 34 | SENTRY_PUBLIC = config('SENTRY_PUBLIC', default=False, cast=bool) 35 | 36 | def nydus_config(from_env_var): 37 | """ 38 | Generate a Nydus Redis configuration from an ENV variable of the form "server:port,server:port..." 39 | Default to REDIS_HOST:REDIS_PORT if the ENV variable is not provided. 40 | """ 41 | redis_servers_cast = lambda x: list(r.split(':') for r in x.split(',')) 42 | servers = config(from_env_var, default='{0}:{1}'.format(REDIS_HOST, REDIS_PORT), cast=redis_servers_cast) 43 | _redis_hosts = {} 44 | 45 | for r_index, r_host_pair in enumerate(servers): 46 | _redis_hosts[r_index] = {'host': r_host_pair[0], 'port': int(r_host_pair[1])} 47 | 48 | return { 49 | 'hosts': _redis_hosts 50 | } 51 | 52 | 53 | ############################ 54 | # General Sentry options ## 55 | ############################ 56 | SENTRY_OPTIONS = { 57 | # You MUST configure the absolute URI root for Sentry: 58 | 'system.url-prefix': config('SENTRY_URL_PREFIX'), 59 | 'system.admin-email': config('SENTRY_ADMIN_EMAIL', default='root@localhost'), 60 | } 61 | 62 | ########### 63 | # Queue ## 64 | ########### 65 | 66 | # See http://sentry.readthedocs.org/en/latest/queue/index.html for more 67 | # information on configuring your queue broker and workers. Sentry relies 68 | # on a Python framework called Celery to manage queues. 69 | 70 | # You can enable queueing of jobs by turning off the always eager setting: 71 | CELERY_ALWAYS_EAGER = config('CELERY_ALWAYS_EAGER', default=True, cast=bool) 72 | DEFAULT_BROKER_URL = 'redis://{0}:{1}/1'.format(REDIS_HOST, REDIS_PORT) 73 | 74 | BROKER_URL = config('SENTRY_BROKER_URL', default=DEFAULT_BROKER_URL) 75 | 76 | CELERY_RESULT_SERIALIZER = config('CELERY_RESULT_SERIALIZER', default='pickle') 77 | CELERY_TASK_SERIALIZER = config('CELERY_TASK_SERIALIZER', default='pickle') 78 | CELERY_ACCEPT_CONTENT = config('CELERY_ACCEPT_CONTENT', default='pickle,json', cast=lambda x: x.split(',')) 79 | 80 | #################### 81 | # Update Buffers ## 82 | #################### 83 | 84 | # Buffers (combined with queueing) act as an intermediate layer between the 85 | # database and the storage API. They will greatly improve efficiency on large 86 | # numbers of the same events being sent to the API in a short amount of time. 87 | # (read: if you send any kind of real data to Sentry, you should enable buffers) 88 | 89 | # You'll need to install the required dependencies for Redis buffers: 90 | # pip install redis hiredis nydus 91 | # 92 | 93 | SENTRY_USE_REDIS_BUFFERS = config('SENTRY_USE_REDIS_BUFFERS', default=False, cast=bool) 94 | 95 | if SENTRY_USE_REDIS_BUFFERS: 96 | SENTRY_BUFFER = 'sentry.buffer.redis.RedisBuffer' 97 | SENTRY_REDIS_OPTIONS = nydus_config('SENTRY_REDIS_BUFFERS') 98 | SENTRY_CACHE = 'sentry.cache.redis.RedisCache' 99 | 100 | ####################### 101 | # Time-series Storage # 102 | ####################### 103 | # Sentry provides a service to store time-series data. Primarily this 104 | # is used to display aggregate information for events and projects, as 105 | # well as calculating (in real-time) the rates of events. 106 | 107 | SENTRY_USE_REDIS_TSDB = config('SENTRY_USE_REDIS_TSDB', default=False, cast=bool) 108 | 109 | if SENTRY_USE_REDIS_TSDB: 110 | SENTRY_TSDB = 'sentry.tsdb.redis.RedisTSDB' 111 | SENTRY_TSDB_OPTIONS = nydus_config('SENTRY_REDIS_TSDBS') 112 | 113 | ################ 114 | # Web Server ## 115 | ################ 116 | 117 | # If you're using a reverse proxy, you should enable the X-Forwarded-Proto 118 | # and X-Forwarded-Host headers, and uncomment the following settings 119 | SECURE_PROXY_SSL_HEADER = config('SENTRY_SECURE_PROXY_SSL_HEADER', default=None, cast=lambda x: tuple(x.split(',')) if x else None) 120 | USE_X_FORWARDED_HOST = config('SENTRY_USE_X_FORWARDED_HOST', default=False, cast=bool) 121 | 122 | SENTRY_WEB_HOST = config('SENTRY_WEB_HOST', default='0.0.0.0') 123 | SENTRY_WEB_PORT = config('SENTRY_WEB_PORT', default=9000, cast=int) 124 | SENTRY_WEB_OPTIONS = { 125 | 'workers': config('SENTRY_WORKERS', default=3, cast=int), # the number of gunicorn workers 126 | 'limit_request_line': 0, # required for raven-js 127 | 'secure_scheme_headers': {'X-FORWARDED-PROTO': 'https'}, 128 | 'errorlog' : os.path.join(DATA_DIR, 'gunicorn_error.log'), 129 | 'accesslog' : os.path.join(DATA_DIR, 'gunicorn_access.log'), 130 | } 131 | 132 | # allows JavaScript clients to submit cross-domain error reports. Useful for local development 133 | SENTRY_ALLOW_ORIGIN = config('SENTRY_ALLOW_ORIGIN', default=None) 134 | 135 | ################# 136 | # Mail Server ## 137 | ################# 138 | 139 | # For more information check Django's documentation: 140 | # https://docs.djangoproject.com/en/1.3/topics/email/?from=olddocs#e-mail-backends 141 | 142 | EMAIL_BACKEND = config('SENTRY_EMAIL_BACKEND', default='django.core.mail.backends.console.EmailBackend') 143 | 144 | EMAIL_HOST = config('SENTRY_EMAIL_HOST', default='localhost') 145 | EMAIL_HOST_PASSWORD = config('SENTRY_EMAIL_HOST_PASSWORD', default='') 146 | EMAIL_HOST_USER = config('SENTRY_EMAIL_HOST_USER', default='') 147 | EMAIL_PORT = config('SENTRY_EMAIL_PORT', default=25, cast=int) 148 | EMAIL_USE_TLS = config('SENTRY_EMAIL_USE_TLS', default=False, cast=bool) 149 | 150 | # The email address to send on behalf of 151 | SERVER_EMAIL = config('SENTRY_SERVER_EMAIL', default='root@localhost') 152 | 153 | ########### 154 | # etc. ## 155 | ########### 156 | 157 | SENTRY_FEATURES['auth:register'] = config('SENTRY_ALLOW_REGISTRATION', default=False, cast=bool) 158 | 159 | # If this file ever becomes compromised, it's important to regenerate your SECRET_KEY 160 | # Changing this value will result in all current sessions being invalidated 161 | SECRET_KEY = config('SECRET_KEY') 162 | 163 | # http://twitter.com/apps/new 164 | # It's important that input a callback URL, even if its useless. We have no idea why, consult Twitter. 165 | TWITTER_CONSUMER_KEY = config('TWITTER_CONSUMER_KEY', default='') 166 | TWITTER_CONSUMER_SECRET = config('TWITTER_CONSUMER_SECRET', default='') 167 | 168 | # http://developers.facebook.com/setup/ 169 | FACEBOOK_APP_ID = config('FACEBOOK_APP_ID', default='') 170 | FACEBOOK_API_SECRET = config('FACEBOOK_API_SECRET', default='') 171 | 172 | # http://code.google.com/apis/accounts/docs/OAuth2.html#Registering 173 | GOOGLE_OAUTH2_CLIENT_ID = config('GOOGLE_OAUTH2_CLIENT_ID', default='') 174 | GOOGLE_OAUTH2_CLIENT_SECRET = config('GOOGLE_OAUTH2_CLIENT_SECRET', default='') 175 | 176 | # https://github.com/settings/applications/new 177 | GITHUB_APP_ID = config('GITHUB_APP_ID', default='') 178 | GITHUB_API_SECRET = config('GITHUB_API_SECRET', default='') 179 | 180 | # https://trello.com/1/appKey/generate 181 | TRELLO_API_KEY = config('TRELLO_API_KEY', default='') 182 | TRELLO_API_SECRET = config('TRELLO_API_SECRET', default='') 183 | 184 | # https://confluence.atlassian.com/display/BITBUCKET/OAuth+Consumers 185 | BITBUCKET_CONSUMER_KEY = config('BITBUCKET_CONSUMER_KEY', default='') 186 | BITBUCKET_CONSUMER_SECRET = config('BITBUCKET_CONSUMER_SECRET', default='') 187 | 188 | # custom settings 189 | ALLOWED_HOSTS = ['*'] 190 | LOGGING['disable_existing_loggers'] = False 191 | 192 | SENTRY_BEACON = config('SENTRY_BEACON', default=True, cast=bool) 193 | 194 | #################### 195 | # LDAP settings ## 196 | #################### 197 | 198 | SENTRY_USE_LDAP = config('SENTRY_USE_LDAP', default=False, cast=bool) 199 | 200 | if SENTRY_USE_LDAP: 201 | import ldap 202 | from django_auth_ldap.config import LDAPSearch, GroupOfUniqueNamesType, PosixGroupType, NestedGroupOfNamesType 203 | 204 | AUTH_LDAP_SERVER_URI = config('LDAP_SERVER', default='ldap://localhost') 205 | 206 | AUTH_LDAP_BIND_DN = config('LDAP_BIND_DN', default='') 207 | AUTH_LDAP_BIND_PASSWORD = config('LDAP_BIND_PASSWORD', default='') 208 | 209 | AUTH_LDAP_USER_SEARCH = LDAPSearch( 210 | config('LDAP_USER_DN'), 211 | ldap.SCOPE_SUBTREE, 212 | config('LDAP_USER_FILTER', default='(&(objectClass=inetOrgPerson)(cn=%(user)s))') 213 | ) 214 | 215 | AUTH_LDAP_GROUP_SEARCH = LDAPSearch( 216 | config('LDAP_GROUP_DN', default=''), 217 | ldap.SCOPE_SUBTREE, 218 | config('LDAP_GROUP_FILTER', default='(objectClass=groupOfUniqueNames)') 219 | ) 220 | 221 | if config('LDAP_GROUP_TYPE', default='') == 'groupOfUniqueNames': 222 | AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType() 223 | elif config('LDAP_GROUP_TYPE', default='') == 'posixGroup': 224 | AUTH_LDAP_GROUP_TYPE = PosixGroupType() 225 | elif config('LDAP_GROUP_TYPE', default='') == 'nestedGroupOfNames': 226 | AUTH_LDAP_GROUP_TYPE = NestedGroupOfNamesType() 227 | 228 | AUTH_LDAP_REQUIRE_GROUP = config('LDAP_REQUIRE_GROUP', default=None) 229 | AUTH_LDAP_DENY_GROUP = config('LDAP_DENY_GROUP', default=None) 230 | 231 | AUTH_LDAP_USER_ATTR_MAP = { 232 | 'first_name': config('LDAP_MAP_FIRST_NAME', default='givenName'), 233 | 'last_name': config('LDAP_MAP_LAST_NAME', default='sn'), 234 | 'email': config('LDAP_MAP_MAIL', default='mail') 235 | } 236 | 237 | ldap_is_active = config('LDAP_GROUP_ACTIVE', default='') 238 | ldap_is_superuser = config('LDAP_GROUP_SUPERUSER', default='') 239 | ldap_is_staff = config('LDAP_GROUP_STAFF', default='') 240 | 241 | if ldap_is_active or ldap_is_superuser or ldap_is_staff: 242 | AUTH_LDAP_USER_FLAGS_BY_GROUP = { 243 | 'is_active': ldap_is_active, 244 | 'is_superuser': ldap_is_superuser, 245 | 'is_staff': ldap_is_staff, 246 | } 247 | 248 | AUTH_LDAP_FIND_GROUP_PERMS = config('LDAP_FIND_GROUP_PERMS', default=False, cast=bool) 249 | 250 | # Cache group memberships for an hour to minimize LDAP traffic 251 | AUTH_LDAP_CACHE_GROUPS = config('LDAP_CACHE_GROUPS', default=True, cast=bool) 252 | AUTH_LDAP_GROUP_CACHE_TIMEOUT = config('LDAP_GROUP_CACHE_TIMEOUT', default=3600, cast=int) 253 | 254 | AUTHENTICATION_BACKENDS = AUTHENTICATION_BACKENDS + ( 255 | 'django_auth_ldap.backend.LDAPBackend', 256 | ) 257 | 258 | # setup logging for django_auth_ldap 259 | import logging 260 | logger = logging.getLogger('django_auth_ldap') 261 | logger.addHandler(logging.StreamHandler()) 262 | ldap_loglevel = getattr(logging, config('LDAP_LOGLEVEL', default='DEBUG')) 263 | logger.setLevel(ldap_loglevel) 264 | 265 | ############################## 266 | # REMOTE_USER authentication # 267 | ############################## 268 | 269 | SENTRY_USE_REMOTE_USER = config('SENTRY_USE_REMOTE_USER', default=False, cast=bool) 270 | 271 | if SENTRY_USE_REMOTE_USER: 272 | AUTHENTICATION_BACKENDS += ('django.contrib.auth.backends.RemoteUserBackend',) 273 | 274 | AUTH_REMOTE_USER_HEADER = config('AUTH_REMOTE_USER_HEADER', default=None) 275 | if AUTH_REMOTE_USER_HEADER: 276 | # The lazy hack is required because importing RemoteUserMiddleware at load time leads to a circular import 277 | # The name is upper camel case because that's the only way to expose values from this config file 278 | def build_LAZY_CUSTOM_REMOTE_USER_MIDDLEWARE(header, *args, **kwargs): 279 | from django.contrib.auth.middleware import RemoteUserMiddleware 280 | class CustomRemoteUserMiddleware(RemoteUserMiddleware): 281 | pass 282 | CustomRemoteUserMiddleware.header = header 283 | return CustomRemoteUserMiddleware(*args, **kwargs) 284 | LAZY_CUSTOM_REMOTE_USER_MIDDLEWARE = functools.partial(build_LAZY_CUSTOM_REMOTE_USER_MIDDLEWARE, AUTH_REMOTE_USER_HEADER) 285 | MIDDLEWARE_CLASSES += ('sentry_config.LAZY_CUSTOM_REMOTE_USER_MIDDLEWARE',) 286 | else: 287 | MIDDLEWARE_CLASSES += ('django.contrib.auth.middleware.RemoteUserMiddleware',) 288 | -------------------------------------------------------------------------------- /sentry_run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SENTRY_CONF_FILE=${SENTRY_CONF_FILE:-/conf/sentry_docker_conf.py} 4 | 5 | # export env var for other scripts to work 6 | export SENTRY_CONF=$SENTRY_CONF_FILE 7 | SCRIPTS_DIR=${SENTRY_SCRIPTS_DIR:-/conf} 8 | 9 | # if starting the web worker then try to initialize DB and superuser 10 | if [ "$1" == "start" ] || [ "$1" == "prepare" ]; then 11 | 12 | # check DB health if "SENTRY_DOCKER_DO_DB_CHECK" is set 13 | if [ -n "$SENTRY_DOCKER_DO_DB_CHECK" ]; then 14 | python $SCRIPTS_DIR/check_db_isalive.py 10 3 15 | if [ "$?" != "0" ]; then 16 | echo "couldn't establish DB connection. exiting..." 17 | exit 1 18 | fi 19 | fi 20 | 21 | sentry --config=$SENTRY_CONF_FILE upgrade --noinput 22 | 23 | # create superuser 24 | python $SCRIPTS_DIR/create_team_or_project.py admin "${SENTRY_ADMIN_USERNAME:-admin}" "${SENTRY_ADMIN_EMAIL:-root@localhost}" "${SENTRY_ADMIN_PASSWORD:-admin}" 25 | 26 | if [ -n "$SENTRY_INITIAL_TEAM" ]; then 27 | python $SCRIPTS_DIR/create_team_or_project.py team ${SENTRY_ADMIN_USERNAME:-admin} $SENTRY_INITIAL_TEAM 28 | if [ -n "$SENTRY_INITIAL_PROJECT" ]; then 29 | python $SCRIPTS_DIR/create_team_or_project.py project $SENTRY_INITIAL_TEAM $SENTRY_INITIAL_PROJECT 30 | if [ -n "$SENTRY_INITIAL_KEY" ]; then 31 | python $SCRIPTS_DIR/create_team_or_project.py key $SENTRY_INITIAL_TEAM $SENTRY_INITIAL_PROJECT $SENTRY_INITIAL_KEY 32 | fi 33 | if [ -n "$SENTRY_INITIAL_DOMAINS" ]; then 34 | python $SCRIPTS_DIR/create_team_or_project.py origins $SENTRY_INITIAL_TEAM $SENTRY_INITIAL_PROJECT "$SENTRY_INITIAL_DOMAINS" 35 | fi 36 | fi 37 | fi 38 | fi 39 | 40 | if [ "$1" != "prepare" ]; then 41 | exec sentry --config=$SENTRY_CONF_FILE $@ 42 | fi 43 | 44 | -------------------------------------------------------------------------------- /tests/custom_settings/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | 3 | MAINTAINER Sławek Ehlert 4 | 5 | RUN apt-get -qq update && apt-get install -y -q netcat 6 | 7 | RUN mkdir /tests 8 | 9 | ADD test.sh /tests/ 10 | 11 | WORKDIR /tests 12 | 13 | CMD ["/bin/bash", "./test.sh"] 14 | -------------------------------------------------------------------------------- /tests/custom_settings/conf/sentry_customconf.py: -------------------------------------------------------------------------------- 1 | from sentry_docker_conf import * # noqa 2 | 3 | SENTRY_WEB_PORT = 9090 4 | -------------------------------------------------------------------------------- /tests/custom_settings/docker-compose.yml: -------------------------------------------------------------------------------- 1 | sentryweb: 2 | build: ../.. # this will use a main Dockerfile in this repo 3 | command: "start" 4 | volumes: 5 | - ./conf:/mycustomconfdir 6 | environment: 7 | - SECRET_KEY=123123123 8 | - SENTRY_URL_PREFIX=http://sentry.domain.com 9 | - PYTHONPATH=/conf/ 10 | - SENTRY_CONF_FILE=/mycustomconfdir/sentry_customconf.py 11 | 12 | expose: 13 | - "9090" 14 | 15 | test: 16 | build: . 17 | links: 18 | - sentryweb:sentryweb 19 | -------------------------------------------------------------------------------- /tests/custom_settings/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HAS_ERRORS=0 4 | TIMEOUT=210 # seconds 5 | 6 | echo 7 | echo "waiting for sentryweb:9090" 8 | 9 | trap "exit" INT 10 | for i in $(seq 1 $TIMEOUT); do 11 | nc -w 5 -z sentryweb 9090 12 | RET=$? 13 | HAS_ERRORS=$RET 14 | if [ "$RET" != "0" ]; then 15 | echo -n "." 16 | sleep 1 17 | else 18 | echo "sentryweb:9090 OK" 19 | break 20 | fi 21 | done 22 | 23 | exit $HAS_ERRORS 24 | -------------------------------------------------------------------------------- /tests/initial_team_project/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | 3 | MAINTAINER Sławek Ehlert 4 | 5 | RUN apt-get -qq update && apt-get install -y -q netcat 6 | 7 | RUN mkdir /tests 8 | 9 | ADD test.sh /tests/ 10 | 11 | RUN pip install raven 12 | 13 | WORKDIR /tests 14 | 15 | CMD ["/bin/bash", "./test.sh"] 16 | -------------------------------------------------------------------------------- /tests/initial_team_project/docker-compose.yml: -------------------------------------------------------------------------------- 1 | sentryweb: 2 | build: ../.. # this will use a main Dockerfile in this repo 3 | command: "start" 4 | environment: 5 | - SECRET_KEY=123123123 6 | - SENTRY_URL_PREFIX=http://sentryweb 7 | - SENTRY_INITIAL_TEAM=testteam 8 | - SENTRY_INITIAL_PROJECT=testproject 9 | - SENTRY_INITIAL_KEY=pub:sec 10 | 11 | test: 12 | build: . 13 | environment: 14 | - SENTRY_DSN=http://pub:sec@sentryweb:9000/2 15 | links: 16 | - sentryweb:sentryweb 17 | -------------------------------------------------------------------------------- /tests/initial_team_project/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | HAS_ERRORS=0 5 | TIMEOUT=210 # seconds 6 | 7 | echo 8 | echo "waiting for sentryweb:9000" 9 | 10 | trap "exit" INT 11 | for i in $(seq 1 $TIMEOUT); do 12 | nc -w 5 -z sentryweb 9000 13 | RET=$? 14 | HAS_ERRORS=$RET 15 | if [ "$RET" != "0" ]; then 16 | echo -n "." 17 | sleep 1 18 | else 19 | echo "sentryweb:9000 OK" 20 | sleep 2 21 | raven test 22 | HAS_ERRORS=$? 23 | break 24 | fi 25 | done 26 | 27 | exit $HAS_ERRORS 28 | -------------------------------------------------------------------------------- /tests/simple_services/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | 3 | MAINTAINER Sławek Ehlert 4 | 5 | RUN apt-get -qq update && apt-get install -y -q netcat 6 | 7 | RUN mkdir /tests 8 | 9 | ADD test.sh /tests/ 10 | 11 | WORKDIR /tests 12 | 13 | CMD ["/bin/bash", "./test.sh"] 14 | -------------------------------------------------------------------------------- /tests/simple_services/README.md: -------------------------------------------------------------------------------- 1 | Simple tests 2 | ============= 3 | 4 | This directory contains a simple script that tests 5 | if all linked containers are accessible on the given ports. 6 | 7 | The script is run inside a container (described by a 8 | ``Dockerfile`` in this directory). 9 | 10 | Go to https://docs.docker.com/compose/ for more info about `docker-compose`. 11 | -------------------------------------------------------------------------------- /tests/simple_services/docker-compose.yml: -------------------------------------------------------------------------------- 1 | redis: 2 | image: redis 3 | 4 | db: 5 | image: postgres 6 | 7 | sentrycelery: &DEFAULT 8 | build: ../.. # this will use a main Dockerfile in this repo 9 | command: "celery worker -B -l INFO" 10 | links: 11 | - redis:redis 12 | - db:postgresdb 13 | environment: 14 | - SECRET_KEY=123123123 15 | - SENTRY_URL_PREFIX=http://sentry.slafs.com 16 | - DATABASE_URL=postgres://postgres:@postgresdb/postgres 17 | - CELERY_ALWAYS_EAGER=False 18 | - CACHE_URL=hiredis://redis:6379/2 19 | - SENTRY_DOCKER_DO_DB_CHECK=yes 20 | 21 | sentryweb: 22 | <<: *DEFAULT # "inherit" from the configuration above 23 | command: "start" 24 | 25 | # this container will run during testing 26 | # so we have to link all the other ones 27 | # and then they can be build/run automatically 28 | test: 29 | build: . 30 | links: 31 | - redis:redis 32 | - db:postgresdb 33 | - sentryweb:sentryweb 34 | - sentrycelery:sentrycelery 35 | -------------------------------------------------------------------------------- /tests/simple_services/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HAS_ERRORS=0 4 | TIMEOUT=210 # seconds 5 | 6 | declare -A services 7 | services[redis]=6379 8 | services[postgresdb]=5432 9 | services[sentryweb]=9000 10 | 11 | echo 12 | echo "waiting for services" 13 | 14 | trap "exit" INT 15 | for service in ${!services[@]}; do # loop through all services 16 | 17 | port=${services[${service}]} 18 | 19 | echo "trying $service:$port" 20 | for i in $(seq 1 $TIMEOUT); do 21 | 22 | nc -w 5 -z $service $port 2>&1 23 | RET_CODE=$? 24 | if [ "$RET_CODE" -ne "0" ]; then 25 | echo -n "." 26 | sleep 1 27 | else 28 | echo "$service:$port OK" 29 | break 30 | fi 31 | 32 | done 33 | 34 | # after a timeout (or break) check if there still were errors 35 | if [ "$RET_CODE" -ne "0" ]; then 36 | HAS_ERRORS=$RET_CODE 37 | fi 38 | 39 | done 40 | 41 | exit $HAS_ERRORS 42 | --------------------------------------------------------------------------------