diff --git a/.env b/.env deleted file mode 100644 index 1788051..0000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -COMPOSE_PROJECT_NAME=dispatch diff --git a/.env.example b/.env.example index 491b6f7..1e9b67d 100644 --- a/.env.example +++ b/.env.example @@ -1,77 +1,19 @@ -ANNUAL_COST_EMPLOYEE=650000 -BUSINESS_HOURS_YEAR=2080 +# General COMPOSE_PROJECT_NAME=dispatch -DATABASE_CREDENTIALS=creds +SECRET_KEY=REPLACEWITHSOMETHIINGSECRET +DISPATCH_JWT_SECRET=REPLACEWITHSOMETHIINGSECRET +DISPATCH_ENCRYPTION_KEY=REPLACEWITHSOMETHIINGSECRET + +# Database +# NOTE: Ensure that DATABASE_CREDENTIALS match the values passed to POSTGRES_USER and POSTGRES_PASSWORD +DATABASE_CREDENTIALS=dispatch:dispatch DATABASE_HOSTNAME=postgres DATABASE_NAME=dispatch DATABASE_PORT=5432 -DISPATCH_HELP_EMAIL=help@example.com -DISPATCH_HELP_SLACK_CHANNEL=#general -INCIDENT_DAILY_SUMMARY_ONCALL_SERVICE_ID=None -INCIDENT_DOCUMENT_INVESTIGATION_SHEET_ID="INCIDENT_DOCUMENT_INVESTIGATION_SHEET_ID" -INCIDENT_CONVERSATION_COMMANDS_REFERENCE_DOCUMENT_ID="INCIDENT_CONVERSATION_COMMANDS_REFERENCE_DOCUMENT_ID" -INCIDENT_FAQ_DOCUMENT_ID="INCIDENT_FAQ_DOCUMENT_ID" -INCIDENT_NOTIFICATION_CONVERSATIONS="" -INCIDENT_NOTIFICATION_DISTRIBUTION_LISTS="" -INCIDENT_PLUGIN_CONTACT_SLUG="slack-contact" -INCIDENT_PLUGIN_CONVERSATION_SLUG="slack-conversation" -INCIDENT_PLUGIN_DOCUMENT_RESOLVER_SLUG="dispatch-document-resolver" -INCIDENT_PLUGIN_DOCUMENT_SLUG="google-docs-document" -INCIDENT_PLUGIN_EMAIL_SLUG="google-gmail-conversation" -INCIDENT_PLUGIN_GROUP_SLUG="group-participant-group" -INCIDENT_PLUGIN_PARTICIPANT_SLUG="dispatch-participants" -INCIDENT_PLUGIN_STORAGE_SLUG="google-drive-storage" -INCIDENT_PLUGIN_TASK_SLUG="google-drive-task" -INCIDENT_PLUGIN_TICKET_SLUG="jira-ticket" -INCIDENT_RESOURCE_CONVERSATION_COMMANDS_REFERENCE_DOCUMENT="google-docs-conversation-commands-reference-document" -INCIDENT_RESOURCE_FAQ_DOCUMENT="google-docs-faq-document" -INCIDENT_RESOURCE_INCIDENT_REVIEW_DOCUMENT="google-docs-incident-review-document" -INCIDENT_RESOURCE_INCIDENT_TASK="google-docs-incident-task" -INCIDENT_RESOURCE_INVESTIGATION_DOCUMENT="google-docs-investigation-document" -INCIDENT_RESOURCE_INVESTIGATION_SHEET="google-docs-investigation-sheet" -INCIDENT_RESOURCE_NOTIFICATIONS_GROUP="google-group-participant-notifications-group" -INCIDENT_RESOURCE_TACTICAL_GROUP="google-group-participant-tactical-group" -INCIDENT_STORAGE_ARCHIVAL_FOLDER_ID=INCIDENT_STORAGE_ARCHIVAL_FOLDER_ID -INCIDENT_STORAGE_INCIDENT_REVIEW_FILE_ID=INCIDENT_STORAGE_INCIDENT_REVIEW_FILE_ID -JWKS_URL=https://site.com + +# Used by postgres docker POSTGRES_DB=dispatch POSTGRES_PASSWORD=dispatch POSTGRES_USER=dispatch -# Plugin-specific -# For configuration details, see: https://hawkins.gitbook.io/dispatch/configuration/app -# Incident configuration -INCIDENT_NOTIFICATION_CONVERSATIONS="" -INCIDENT_NOTIFICATION_DISTRIBUTION_LISTS="" -INCIDENT_STORAGE_ARCHIVAL_FOLDER_ID="" -INCIDENT_STORAGE_DRIVE_ID_SLUG="" -INCIDENT_STORAGE_INCIDENT_REVIEW_FILE_ID="" -INCIDENT_DOCUMENT_INVESTIGATION_SHEET_ID="" -INCIDENT_FAQ_DOCUMENT_ID="" - -# Plugin configuration - -# Slack -SLACK_APP_USER_SLUG="" -SLACK_API_BOT_TOKEN="" -SLACK_SIGNING_SECRET="" -SLACK_WORKSPACE_NAME="" - -# Google -GOOGLE_SERVICE_ACCOUNT_PROJECT_ID=id -GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY_ID=id -GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY=key -GOOGLE_SERVICE_ACCOUNT_CLIENT_EMAIL=info@example.com -GOOGLE_SERVICE_ACCOUNT_CLIENT_ID=id -GOOGLE_SERVICE_ACCOUNT_DELEGATED_ACCOUNT=account -GOOGLE_DEVELOPER_KEY=key -GOOGLE_DOMAIN=site.com - -# Jira -JIRA_URL="" -JIRA_PASSWORD="" -JIRA_USERNAME="" - -# PagerDuty -PAGERDUTY_API_KEY="" -PAGERDUTY_API_FROM_EMAIL="" +# For additional server configuration options see: https://hawkins.gitbook.io/dispatch/administration-guide/server diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..8e54217 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +mvilanova +kevgliss diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml new file mode 100644 index 0000000..ad042b2 --- /dev/null +++ b/.github/workflows/enforce-labels.yml @@ -0,0 +1,14 @@ +name: Enforce PR labels + +on: + pull_request: + types: [labeled, unlabeled, opened, edited, synchronize] +jobs: + enforce-label: + runs-on: ubuntu-latest + steps: + - uses: yogevbd/enforce-label-action@2.1.0 + with: + REQUIRED_LABELS_ANY: "bug,enhancement,documentation,feature,dependencies,skip-changelog" + REQUIRED_LABELS_ANY_DESCRIPTION: "Select at least one label ['bug','documentation','feature','dependencies','enhancement','skip-changelog']" + BANNED_LABELS: "banned" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..5244106 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,20 @@ +name: 'Close stale issues and pull requests' +on: + schedule: + - cron: "0 0 * * *" + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue is stale, because it has been open for 30 days with no activity. Remove the stale label or comment, or this will be closed in 5 days.' + close-issue-message: 'This issue was closed, because it has been stalled for 5 days with no activity.' + stale-pr-message: 'This PR is stale, because it has been open for 45 days with no activity. Remove the stale label or comment, or this will be closed in 10 days.' + close-pr-message: 'This PR was closed, because it has been stalled for 10 days with no activity.' + days-before-issue-stale: 30 + days-before-issue-close: 5 + days-before-pr-stale: 45 + days-before-pr-close: 10 diff --git a/.gitignore b/.gitignore index e640210..76ad4bb 100644 --- a/.gitignore +++ b/.gitignore @@ -63,4 +63,7 @@ docker-compose.override.yml *.tar data/ -.vscode/tags \ No newline at end of file +.vscode/tags + +.env +dispatch-sample-data.dump diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2838d81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Netflix, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 54c9e60..e4f0764 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,24 @@ +# 🚨 Notice: Dispatch is Being Archived 🚨 + +This repository will be **archived and marked as read-only on September 1, 2025**. After this date, no further changes, issues, or pull requests will be accepted. + +## 🙏 Thank You + +Since the first commit on **February 10, 2020**, Dispatch has grown into a sophisticated incident and signal management platform, thanks to the dedication and passion of its community. We are deeply grateful to the **[80 contributors](https://github.com/Netflix/dispatch/graphs/contributors)** who have shared their time, expertise, and creativity over the years. Your support has made Dispatch what it is today. + +## â„šī¸ What Does This Mean? + +- The codebase will remain publicly available in a **read-only** state. +- No new issues, pull requests, or discussions will be accepted. +- Existing issues and pull requests will be closed. +- We encourage users to fork the repository if they wish to continue development independently. + +Thank you again to everyone who has contributed, used, or supported Dispatch over the years! + +— The Dispatch Team at Netflix + +--- + # Dispatch Official bootstrap for running your own `Dispatch` with [Docker](https://www.docker.com/). @@ -17,6 +38,16 @@ To get started with all the defaults, simply clone the repo and run `./install.s There may need to be modifications to the included example config files (`.env`) to accommodate your needs or your environment (such as adding Google credentials). If you want to perform these, do them before you run the install script and copy them without the `.example` extensions in the name before running the `install.sh` script. +## Data + +By default Dispatch does not come with any data. If you're looking for some example data, please use the postgres dump file located [here](https://github.com/Netflix/dispatch/blob/main/data/dispatch-sample-data.dump) to load example data. + +Note: when running the `install.sh` file, you will be asked whether to load this database dump, or to initialize a new database. + +### Starting with a clean database + +If you decide to start with a clean database, you will need a user. To create a user, go to http://localhost:8000/default/auth/register. + ## Securing Dispatch with SSL/TLS If you'd like to protect your Dispatch install with SSL/TLS, there are @@ -26,3 +57,51 @@ and [Nginx](http://nginx.org/). You'll likely want to add this service to your ` ## Updating Dispatch The included `install.sh` script is meant to be idempotent and to bring you to the latest version. What this means is you can and should run `install.sh` to upgrade to the latest version available. + +### Upgrading from an older version of postgres + +If you are using an earlier version of `postgres` you may need to run manual steps to upgrade to the newest Postgres image. + +This assumes that you have not changed the default Postgres data path (`/var/lib/postgresql/data`) in your `docker-compose.yml`. + +If you have changed it, please replace all occurences of `/var/lib/postgresql/data` with your path. + +1. Make a backup of your Dispatch Postgres data dir. +2. Stop all Dispatch containers, except the postgres one (e.g. use `docker stop` and not `docker-compose stop`). +3. Create a new Postgres container which uses a different data directory: +``` +docker run -d \ + --name postgresnew \ + -e POSTGRES_DB=dispatch \ + -e POSTGRES_USER=dispatch \ + -e POSTGRES_PASSWORD=dispatch \ + -v /var/lib/postgresql/new:/var/lib/postgresql/data:rw \ + postgres:latest +``` +4. Use `pg_dumpall` to dump all data from the existing Postgres container to the new Postgres container (replace `DISPATCH_DATABASE_CONTAINER_NAME` (default is `postgres`) with the name of the old Postgres container): +``` +docker exec \ + DISPATCH_DATABASE_CONTAINER_NAME pg_dumpall -U postgres | \ + docker exec -i postgresnew psql -U postgres +``` +5. Stop and remove both Postgres containers: +``` +docker stop DISPATCH_DATABASE_CONTAINER_NAME postgresnew +docker rm DISPATCH_DATABASE_CONTAINER_NAME postgresnew +``` +6. Edit your `docker-compose.yml` to use the `postgres:latest` image for the `database` container. +7. Replace old Postgres data directory with upgraded data directory: +``` +mv /var/lib/postgresql/data /var/lib/postgresql/old +mv /var/lib/postgresql/new /var/lib/postgresql/data +``` +8. Delete the old existing containers: +``` +docker-compose rm +``` +9. Start Dispatch up again: +``` +docker-compose up +``` + +That should be it. Your Postgres data has now been updated to use the `postgres` image. diff --git a/docker-compose.yml b/docker-compose.yml index 7e83b86..8c4b4e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,38 +6,41 @@ services: <<: *restart_policy env_file: - .env - image: "postgres:9.6" + image: postgres:14.6 ports: - "5432:5432" volumes: - "dispatch-postgres:/var/lib/postgresql/data" - web: - <<: *restart_policy + core: + image: dispatch-local + env_file: + - .env build: # Pro-tip: point this to a relative directory containing the Dispatch # project root to pick up changes from your dev environment # (e.g., ../dispatch-root) - context: https://github.com/Netflix/dispatch.git#develop:. - image: dispatch-local-web + context: https://github.com/Netflix/dispatch.git#latest + web: + <<: *restart_policy + image: dispatch-local depends_on: - postgres + - core env_file: - .env - command: ["server", "start", "dispatch.main:app"] + command: ["server", "start", "dispatch.main:app", "--host=0.0.0.0"] + ports: + - "8000:8000" scheduler: <<: *restart_policy - build: - # Pro-tip: point this to a relative directory containing the Dispatch - # project root to pick up changes from your dev environment - # (e.g., ../dispatch-root) - context: https://github.com/Netflix/dispatch.git#develop:. - args: - DISPATCH_LIGHT_BUILD: "1" - image: dispatch-local-scheduler + image: dispatch-local depends_on: - postgres + - core env_file: - .env + environment: + - STATIC_DIR= command: ["scheduler", "start"] volumes: dispatch-postgres: diff --git a/docker/.env.example b/docker/.env.example deleted file mode 100644 index e69de29..0000000 diff --git a/install.sh b/install.sh index c903459..a9db10f 100755 --- a/install.sh +++ b/install.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -e +COMPOSE_DOCKER_CLI_BUILD=0 + MIN_DOCKER_VERSION='17.05.0' MIN_COMPOSE_VERSION='1.19.0' MIN_RAM=2400 # MB @@ -8,6 +10,11 @@ MIN_RAM=2400 # MB DISPATCH_CONFIG_ENV='./.env' DISPATCH_EXTRA_REQUIREMENTS='./requirements.txt' +COMPOSE_BUILD_ARGS="$(grep -E '^(VITE)' ${DISPATCH_CONFIG_ENV} | while read var ; do printf %b "--build-arg ${var} "; done)" + +DISPATCH_DB_SAMPLE_DATA_FILE='dispatch-sample-data.dump' +DISPATCH_DB_SAMPLE_DATA_URL="https://raw.githubusercontent.com/Netflix/dispatch/latest/data/${DISPATCH_DB_SAMPLE_DATA_FILE}" + DID_CLEAN_UP=0 # the cleanup function will be the exit point cleanup () { @@ -23,22 +30,41 @@ trap cleanup ERR INT TERM echo "Checking minimum requirements..." DOCKER_VERSION=$(docker version --format '{{.Server.Version}}') -COMPOSE_VERSION=$(docker-compose --version | sed 's/docker-compose version \(.\{1,\}\),.*/\1/') +COMPOSE_VERSION=$(docker-compose --version | grep -o "[0-9]\{1,2\}\.[0-9]\{1,2\}\.[0-9]\{1,2\}") RAM_AVAILABLE_IN_DOCKER=$(docker run --rm busybox free -m 2>/dev/null | awk '/Mem/ {print $2}'); # Compare dot-separated strings - function below is inspired by https://stackoverflow.com/a/37939589/808368 function ver () { echo "$@" | awk -F. '{ printf("%d%03d%03d", $1,$2,$3); }'; } -# Thanks to https://stackoverflow.com/a/25123013/90297 for the quick `sed` pattern function ensure_file_from_example { if [ -f "$1" ]; then echo "$1 already exists, skipped creation." else echo "Creating $1..." - cp -n $(echo "$1" | sed 's/\.[^.]*$/.example&/') "$1" + cp -n $(echo "$1".example) "$1" fi } +# Handle OSX sed +if [[ "$OSTYPE" == "darwin"* ]]; then + sed_suffix_arg="-i ''" +else + sed_suffix_arg="-i" +fi + +function fill_uninitialised_secret { + secret_name=$1 + if [ -z ${!secret_name} ] || [ ${!secret_name} == "REPLACEWITHSOMETHIINGSECRET" ]; then + echo "Generating ${secret_name}..." + declare ${secret_name}=$(openssl rand -hex 30) + sed $sed_suffix_arg "s/^${secret_name}=.*/${secret_name}=${!secret_name}/" $DISPATCH_CONFIG_ENV + echo "${secret_name} written to $DISPATCH_CONFIG_ENV" + else + echo "Leaving existing ${secret_name}..." + fi +} + + if [ $(ver $DOCKER_VERSION) -lt $(ver $MIN_DOCKER_VERSION) ]; then echo "FAIL: Expected minimum Docker version to be $MIN_DOCKER_VERSION but found $DOCKER_VERSION" exit -1 @@ -54,6 +80,11 @@ if [ "$RAM_AVAILABLE_IN_DOCKER" -lt "$MIN_RAM" ]; then exit -1 fi +echo "" +ensure_file_from_example $DISPATCH_CONFIG_ENV +ensure_file_from_example $DISPATCH_EXTRA_REQUIREMENTS +source $DISPATCH_CONFIG_ENV + # Clean up old stuff and ensure nothing is working while we install/update docker-compose down --rmi local --remove-orphans @@ -62,42 +93,33 @@ echo "Creating volumes for persistent storage..." echo "Created $(docker volume create --name=dispatch-postgres)." echo "" -ensure_file_from_example $DISPATCH_CONFIG_ENV -ensure_file_from_example $DISPATCH_EXTRA_REQUIREMENTS +fill_uninitialised_secret "SECRET_KEY" +fill_uninitialised_secret "DISPATCH_JWT_SECRET" echo "" -echo "Generating secret key..." -# This is to escape the secret key to be used in sed below -SECRET_KEY=$(head /dev/urandom | env LC_CTYPE=C tr -dc "a-z0-9@#%^&*(-_=+)" | head -c 50 | sed -e 's/[\/&]/\\&/g') -sed -i -e 's/^SECRET_KEY=.*$/SECRET_KEY= '"'$SECRET_KEY'"'/' $DISPATCH_CONFIG_ENV -echo "Secret key written to $DISPATCH_CONFIG_ENV" - -echo "" -echo "Building and tagging Docker images..." +echo "Pulling, building, and tagging Docker images..." echo "" -# Build the dispatch image first -# Once successfully built these lines can be commented out -docker-compose pull --ignore-pull-failures -docker-compose build --force-rm +docker-compose pull postgres +docker-compose build ${COMPOSE_BUILD_ARGS} --force-rm echo "" -echo "Docker images built." +echo "Docker images pulled and built." docker-compose up -d postgres # Very naively check whether there's an existing dispatch-postgres volume and the PG version in it if [[ $(docker volume ls -q --filter name=dispatch-postgres) && $(docker run --rm -v dispatch-postgres:/db busybox cat /db/PG_VERSION 2>/dev/null) == "9.5" ]]; then docker volume rm dispatch-postgres-new || true - # If this is Postgres 9.5 data, start upgrading it to 9.6 in a new volume + # If this is Postgres 9.5 data, start upgrading it to 12 in a new volume docker run --rm \ -v dispatch-postgres:/var/lib/postgresql/9.5/data \ - -v dispatch-postgres-new:/var/lib/postgresql/9.6/data \ - tianon/postgres-upgrade:9.5-to-9.6 + -v dispatch-postgres-new:/var/lib/postgresql/12/data \ + tianon/postgres-upgrade:9.5-to-12 # Get rid of the old volume as we'll rename the new one to that docker volume rm dispatch-postgres docker volume create --name dispatch-postgres # There's no rename volume in Docker so copy the contents from old to new name - # Also append the `host all all all trust` line as `tianon/postgres-upgrade:9.5-to-9.6` + # Also append the `host all all all trust` line as `tianon/postgres-upgrade:9.5-to-12` # doesn't do that automatically. docker run --rm -v dispatch-postgres-new:/from -v dispatch-postgres:/to alpine ash -c \ "cd /from ; cp -av . /to ; echo 'host all all all trust' >> /to/pg_hba.conf" @@ -107,13 +129,29 @@ fi echo "" echo "Setting up database..." -if [ $CI ]; then - docker-compose run web --help - docker-compose run web database upgrade --no-input -else - docker-compose run web --help - docker-compose run web database upgrade +if [ ! $CI ]; then + read -p "Do you want to load example data (WARNING: this will remove all existing database data) (y/N)?" CONT + if [ "$CONT" = "y" ]; then + echo "Downloading example data from Dispatch repository..." + curl -# -o "./$DISPATCH_DB_SAMPLE_DATA_FILE" "$DISPATCH_DB_SAMPLE_DATA_URL" + echo "Dropping database dispatch if it already exists..." + docker-compose run -e "PGPASSWORD=$POSTGRES_PASSWORD" --rm postgres dropdb -h $DATABASE_HOSTNAME -p $DATABASE_PORT -U $POSTGRES_USER $DATABASE_NAME --if-exists + echo "Creating dispatch database..." + docker-compose run -e "PGPASSWORD=$POSTGRES_PASSWORD" --rm postgres createdb -h $DATABASE_HOSTNAME -p $DATABASE_PORT -U $POSTGRES_USER $DATABASE_NAME + echo "Loading example data to the database..." + docker-compose run -e "PGPASSWORD=$POSTGRES_PASSWORD" -v "$(pwd)/$DISPATCH_DB_SAMPLE_DATA_FILE:/$DISPATCH_DB_SAMPLE_DATA_FILE:Z" --rm postgres psql -h $DATABASE_HOSTNAME -p $DATABASE_PORT -U $POSTGRES_USER -d $DATABASE_NAME -f "/$DISPATCH_DB_SAMPLE_DATA_FILE" + echo "Example data loaded. Navigate to /default/auth/register and create a new user." + else + echo "Initializing the database" + docker-compose run --rm web database init + fi fi +echo "Running standard database migrations..." +docker-compose run --rm web database upgrade + +echo "" +echo "Installing plugins..." +docker-compose run --rm web plugins install cleanup @@ -123,3 +161,15 @@ echo "You're all done! Run the following command to get Dispatch running:" echo "" echo " docker-compose up -d" echo "" +echo "Once running, access the Dispatch UI at:" +echo "" +echo " http://localhost:8000/default/auth/register" +echo "" +echo "After registering, run the command below to get owner rights for the user you just registered:" +echo "" +echo " docker exec -it dispatch-web-1 bash -c 'dispatch user update --role Owner --organization name-of-the-organization email-address-of-registered-user'" +echo "" +echo "In case you load the sample data, your organization name is: default" +echo "" +echo "----------------" +echo "" diff --git a/requirements.example.txt b/requirements.example.txt deleted file mode 100644 index 18c92b4..0000000 --- a/requirements.example.txt +++ /dev/null @@ -1 +0,0 @@ -# plugins here \ No newline at end of file diff --git a/requirements.txt.example b/requirements.txt.example new file mode 100644 index 0000000..a036261 --- /dev/null +++ b/requirements.txt.example @@ -0,0 +1 @@ +# plugins here