Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: external database #2

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
68 changes: 60 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# dokku-discourse

![Test](https://github.com/badsyntax/dokku-discourse/workflows/Test/badge.svg)
![Publish](https://github.com/badsyntax/dokku-discourse/workflows/Publish/badge.svg)
![Test](https://github.com/digital-sustainability/dokku-discourse/workflows/Test/badge.svg)
![Publish](https://github.com/digital-sustainability/dokku-discourse/workflows/Publish/badge.svg)

Manages discourse apps on your dokku server.

## Plugin installation

```sh
# For dokku >= v0.22.0
dokku plugin:install https://github.com/badsyntax/dokku-discourse.git
dokku plugin:install https://github.com/digital-sustainability/dokku-discourse.git

# For dokku < v0.22.0
dokku plugin:install https://github.com/badsyntax/dokku-discourse.git --committish 0.2.1
dokku plugin:install https://github.com/digital-sustainability/dokku-discourse.git --committish 0.2.1
```

## Plugin update
Expand All @@ -36,16 +36,65 @@ discourse:list # Lists discourse apps

### Create a new discourse app

Each discourse app is a separate _standalone_ discourse instance.
#### Standaone

To setup a new discourse app as a separate _standalone_ discourse instance run

```sh
dokku discourse:create discourse-app
```

and choose _false_ in the first prompt.

*A new docker image will be built and this process can take some time.*

You'll be prompted for various discourse configuration values.

#### External Database

To setup a new discourse app with an external database first create a container

```sh
dokku apps:create discourse-app
```

use [dokku-postgres](https://github.com/dokku/dokku-postgres) to create a new postgres service

```sh
dokku postgres:create discourse-db
```

link the container with the postgres service

```sh
dokku postgres:link discourse-db discourse-app
```

this will set an env DATABASE_URL with the following structure:

```sh
postgres://postgres:<DATABSE_PASSWORD>@dokku-postgres-discourse-db:5432/discourse_db
```

you'll be asked to specify a docker link during setup, to get the necessary information run

```sh
dokku docker-options:report discourse-app
```
you should get something like:

```sh
--link dokku.postgres.discourse-db:dokku-postgres-discourse-db
```

finally start the setup and choose _true_ in the first prompt

```sh
dokku discourse:create discourse-app
```

use the database information from `DATABASE_URL` and `docker-options` to complete the setup.

Data will be stored in location `/var/lib/dokku/data/storage/APP_NAME`.

Once your app is built & deployed, you can treat it as any other dokku app. You should use the [dokku-letsencrypt](https://github.com/dokku/dokku-letsencrypt) plugin for adding TLS.
Expand All @@ -54,11 +103,13 @@ Continue with the offical [discourse install instructions](https://github.com/di

### Customise the discourse container config

A discourse container config file is created when a discourse app is created. The config is based on [standalone.yml](https://github.com/discourse/discourse_docker/blob/master/samples/standalone.yml).
A discourse container config file is created when a discourse app is created. Depeding on your chooise the config is based on [standalone.yml](https://github.com/discourse/discourse_docker/blob/master/samples/standalone.yml) or [web_only](https://github.com/discourse/discourse_docker/blob/master/samples/web_only.yml) including the redis template.

You can edit the config at `/home/dokku/APP_NAME/discourse_standalone.yml` or `/home/dokku/APP_NAME/discourse_web_and_redis.yml`. Don't make any changes to the `volumes` section, but feel free to change anything else.

You can edit the config at `/home/dokku/APP_NAME/discourse_standalone.yml`. Don't make any changes to the `volumes` section, but feel free to change anything else.
*Important:* Changes to the `env` section will overwritten.

After making change be sure to run `dokku discourse:create <app>` to rebuild and re-deploy the discourse app.
After making change be sure to run `dokku discourse:create <app>` to rebuild and re-deploy the discourse app.

### Upgrade a discourse app

Expand Down Expand Up @@ -138,6 +189,7 @@ To complete the restoration, you'll need install plugins that were previously in

- https://medium.com/batary/deploying-discourse-with-dokku-5eec28e2ad8b
- https://gist.github.com/julienma/a101a72fdd97932bf28909633f45c7be
- https://github.com/badsyntax/dokku-discourse

## Development

Expand Down
27 changes: 27 additions & 0 deletions containers/set-links
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/python3

import sys
from yaml import load, dump

try:
from yaml import CLoader as Loader, CDumper as Dumper
except ImportError:
from yaml import Loader, Dumper

if __name__ == "__main__":
config_file = sys.argv[1]
alias = sys.argv[2]
name = sys.argv[3]

with open(config_file, "r") as f:
data = load(f, Loader=Loader)
links = [
{
"link": {
"alias": alias,
"name": name,
}
},
]
data['links'] = links
print(dump(data, Dumper=Dumper))
43 changes: 33 additions & 10 deletions containers/update-env
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,40 @@ if __name__ == "__main__":
smtp_port = sys.argv[5]
smtp_user_name = sys.argv[6]
smtp_password = sys.argv[7]
db_host = sys.argv[8]
db_port = sys.argv[9]
db_name = sys.argv[10]
db_username = sys.argv[11]
db_password = sys.argv[12]

with open(config_file, "r") as f:
data = load(f, Loader=Loader)
data["env"] = {
"LANG": lang,
"DISCOURSE_DEFAULT_LOCALE": default_locale,
"DISCOURSE_HOSTNAME": hostname,
"DISCOURSE_DEVELOPER_EMAILS": developer_emails,
"DISCOURSE_SMTP_ADDRESS": smtp_address,
"DISCOURSE_SMTP_PORT": smtp_port,
"DISCOURSE_SMTP_USER_NAME": smtp_user_name,
"DISCOURSE_SMTP_PASSWORD": smtp_password,
}
if db_host == "":
data["env"] = {
"LANG": lang,
"DISCOURSE_DEFAULT_LOCALE": default_locale,
"DISCOURSE_HOSTNAME": hostname,
"DISCOURSE_DEVELOPER_EMAILS": developer_emails,
"DISCOURSE_SMTP_ADDRESS": smtp_address,
"DISCOURSE_SMTP_PORT": smtp_port,
"DISCOURSE_SMTP_USER_NAME": smtp_user_name,
"DISCOURSE_SMTP_PASSWORD": smtp_password,
}
else:
data["env"] = {
"LANG": lang,
"DISCOURSE_DEFAULT_LOCALE": default_locale,
"DISCOURSE_HOSTNAME": hostname,
"DISCOURSE_DEVELOPER_EMAILS": developer_emails,
"DISCOURSE_SMTP_ADDRESS": smtp_address,
"DISCOURSE_SMTP_PORT": smtp_port,
"DISCOURSE_SMTP_USER_NAME": smtp_user_name,
"DISCOURSE_SMTP_PASSWORD": smtp_password,
"DISCOURSE_DB_HOST": db_host,
"DISCOURSE_DB_PORT": db_port,
"DISCOURSE_DB_NAME": db_name,
"DISCOURSE_DB_PASSWORD": db_password,
"DISCOURSE_DB_USERNAME": db_username,
}

print(dump(data, Dumper=Dumper))
32 changes: 32 additions & 0 deletions containers/web_and_redis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
templates:
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
params:
db_default_text_search_config: "pg_catalog.english"
links:
link: { alias: '', name: '' }
env:
LANG: en_US.UTF-8
DISCOURSE_DEFAULT_LOCALE: en
DISCOURSE_HOSTNAME: 'discourse.dokku.me'
DISCOURSE_DEVELOPER_EMAILS: 'me@example.com,you@example.com'
DISCOURSE_SMTP_ADDRESS: smtp.example.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: user@example.com
DISCOURSE_SMTP_PASSWORD: pa$$word
DISCOURSE_DB_HOST: localhost
DISCOURSE_DB_PORT: 5432
DISCOURSE_DB_NAME: discourse
DISCOURSE_DB_USERNAME: postgres
DISCOURSE_DB_PASSWORD: pa$$word

hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone https://github.com/discourse/docker_manager.git
run:
- exec: echo "Beginning of custom commands"
- exec: echo "End of custom commands"
33 changes: 30 additions & 3 deletions functions
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ discourse_create_app() {
SMTP_ADDRESS="$4" \
SMTP_PORT="$5" \
SMTP_USERNAME="$6" \
SMTP_PASSWORD="$7"
SMTP_PASSWORD="$7" \
DB_HOST="$8" \
DB_PORT="$9"
DB_NAME="${10}" \
DB_USERNAME="${11}" \
DB_PASSWORD="${12}" \

## TODO: call plugin functions instead of dokku
if grep -qxF "$(dokku apps:list 2> /dev/null)" <<< "$APP_NAME"; then
Expand All @@ -21,16 +26,32 @@ discourse_create_app() {
echo "$APP_NAME" >> "$DISCOURSE_APPS"
fi

[[ -z "$APP_NAME" ]] && dokku_log_fail "Missing app argument"
WEB_ONLY=$(fn-get-input "Setup with an external database?" "false")

if [ "$WEB_ONLY" = "true" ]; then
export CONTAINER_TYPE="web_and_redis"
export DISCOURSE_CONTAINER_CONFIG_NAME="discourse_$CONTAINER_TYPE"
fi

fn-create-default-discourse-container-config "$APP_NAME"

[[ -z "$APP_NAME" ]] && dokku_log_fail "Missing app argument"
[[ -z "$HOSTNAME" ]] && HOSTNAME=$(fn-get-input "Hostname for your Discourse?" "$(fn-get-env-config DISCOURSE_HOSTNAME)")
[[ -z "$DEVELOPER_EMAILS" ]] && DEVELOPER_EMAILS=$(fn-get-input "Email address for admin account(s)?" "$(fn-get-env-config DISCOURSE_DEVELOPER_EMAILS)")
[[ -z "$SMTP_ADDRESS" ]] && SMTP_ADDRESS=$(fn-get-input "SMTP server address?" "$(fn-get-env-config DISCOURSE_SMTP_ADDRESS)")
[[ -z "$SMTP_PORT" ]] && SMTP_PORT=$(fn-get-input "SMTP port?" "$(fn-get-env-config DISCOURSE_SMTP_PORT)")
[[ -z "$SMTP_USERNAME" ]] && SMTP_USERNAME=$(fn-get-input "SMTP user name?" "$(fn-get-env-config DISCOURSE_SMTP_USER_NAME)")
[[ -z "$SMTP_PASSWORD" ]] && SMTP_PASSWORD=$(fn-get-input "SMTP password?" "$(fn-get-env-config DISCOURSE_SMTP_PASSWORD)")

if [ "$WEB_ONLY" = "true" ]; then
[[ -z "$DB_HOST" ]] && DB_HOST=$(fn-get-input "Postgres server address?" "$(fn-get-env-config DISCOURSE_DB_HOST)")
[[ -z "$DB_PORT" ]] && DB_PORT=$(fn-get-input "Postgres server port?" "$(fn-get-env-config DISCOURSE_DB_PORT)")
[[ -z "$DB_NAME" ]] && DB_NAME=$(fn-get-input "Postgres database name?" "$(fn-get-env-config DISCOURSE_DB_NAME)")
[[ -z "$DB_USERNAME" ]] && DB_USERNAME=$(fn-get-input "Postgres database user name?" "$(fn-get-env-config DISCOURSE_DB_USERNAME)")
[[ -z "$DB_PASSWORD" ]] && DB_PASSWORD=$(fn-get-input "Postgres database password?" "$(fn-get-env-config DISCOURSE_DB_PASSWORD)")
[[ -z "$DB_LINK" ]] && DB_LINK=$(fn-get-input "Postgres container link" "")
fi

local APP_STORAGE_ROOT="$STORAGE_ROOT/$APP_NAME"

fn-update-discourse-container-config "$APP_NAME" \
Expand All @@ -40,7 +61,13 @@ discourse_create_app() {
"$SMTP_ADDRESS" \
"$SMTP_PORT" \
"$SMTP_USERNAME" \
"$SMTP_PASSWORD"
"$SMTP_PASSWORD" \
"$DB_HOST" \
"$DB_PORT" \
"$DB_NAME" \
"$DB_USERNAME" \
"$DB_PASSWORD" \
"$DB_LINK"

fn-update-discourse-build-files

Expand Down
40 changes: 36 additions & 4 deletions internal-functions
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ fn-update-discourse-build-files() {
fi
}

fn-update-discourse-config-set-links() {
declare APP_NAME="$1" APP_STORAGE_ROOT="$2" DB_HOST="$3" DB_LINK="$4"
local CONFIG_FILE_PATH="$DOKKU_ROOT/$APP_NAME/$DISCOURSE_CONTAINER_CONFIG_NAME.yml"
local SET_VOLUMES_BIN_PATH="$PLUGIN_AVAILABLE_PATH/discourse/containers/set-links"
local UPDATED_CONFIG
UPDATED_CONFIG=$("$SET_VOLUMES_BIN_PATH" "$CONFIG_FILE_PATH" "$DB_HOST" $DB_LINK"" 2> /dev/null)
[[ -z "$UPDATED_CONFIG" ]] && dokku_log_fail "Error setting links in config"
echo "$UPDATED_CONFIG" > "$CONFIG_FILE_PATH"
dokku_log_info1 "Updated '$APP_NAME' discourse links"
}

fn-update-discourse-config-set-volumes() {
declare APP_NAME="$1" APP_STORAGE_ROOT="$2"
local CONFIG_FILE_PATH="$DOKKU_ROOT/$APP_NAME/$DISCOURSE_CONTAINER_CONFIG_NAME.yml"
Expand All @@ -56,11 +67,17 @@ fn-update-discourse-config-env() {
SMTP_ADDRESS="$4" \
SMTP_PORT="$5" \
SMTP_USER_NAME="$6" \
SMTP_PASSWORD="$7"
SMTP_PASSWORD="$7" \
DB_HOST="$8" \
DB_PORT="$9"
DB_NAME="${10}" \
DB_USERNAME="${11}" \
DB_PASSWORD="${12}"

local CONFIG_FILE_PATH="$DOKKU_ROOT/$APP_NAME/$DISCOURSE_CONTAINER_CONFIG_NAME.yml"
local UPDATE_ENV_BIN_PATH="$PLUGIN_AVAILABLE_PATH/discourse/containers/update-env"
local UPDATED_CONFIG
UPDATED_CONFIG=$("$UPDATE_ENV_BIN_PATH" "$CONFIG_FILE_PATH" "$HOSTNAME" "$DEVELOPER_EMAILS" "$SMTP_ADDRESS" "$SMTP_PORT" "$SMTP_USER_NAME" "$SMTP_PASSWORD" 2> /dev/null)
UPDATED_CONFIG=$("$UPDATE_ENV_BIN_PATH" "$CONFIG_FILE_PATH" "$HOSTNAME" "$DEVELOPER_EMAILS" "$SMTP_ADDRESS" "$SMTP_PORT" "$SMTP_USER_NAME" "$SMTP_PASSWORD" "$DB_HOST" "$DB_PORT" "$DB_NAME" "$DB_USERNAME" "$DB_PASSWORD" 2> /dev/null)
[[ -z "$UPDATED_CONFIG" ]] && dokku_log_fail "Error setting env in config"
echo "$UPDATED_CONFIG" > "$CONFIG_FILE_PATH"
dokku_log_info1 "Updated '$APP_NAME' discourse env"
Expand All @@ -83,7 +100,13 @@ fn-update-discourse-container-config() {
SMTP_ADDRESS="$5" \
SMTP_PORT="$6" \
SMTP_USER_NAME="$7" \
SMTP_PASSWORD="$8"
SMTP_PASSWORD="$8" \
DB_HOST="$9" \
DB_PORT="${10}"
DB_NAME="${11}" \
DB_USERNAME="${12}" \
DB_PASSWORD="${13}" \
DB_LINK="${14}"

fn-update-discourse-config-env \
"$APP_NAME" \
Expand All @@ -92,10 +115,19 @@ fn-update-discourse-container-config() {
"$SMTP_ADDRESS" \
"$SMTP_PORT" \
"$SMTP_USER_NAME" \
"$SMTP_PASSWORD"
"$SMTP_PASSWORD" \
"$DB_HOST" \
"$DB_PORT" \
"$DB_NAME" \
"$DB_USERNAME" \
"$DB_PASSWORD"

fn-update-discourse-config-set-volumes "$APP_NAME" "$APP_STORAGE_ROOT"

if [ $CONTAINER_TYPE = "web_and_redis" ]; then
fn-update-discourse-config-set-links "$APP_NAME" "$APP_STORAGE_ROOT" "$DB_HOST" "$DB_LINK"
fi

local CONFIG_FILE_PATH="$DOKKU_ROOT/$APP_NAME/$DISCOURSE_CONTAINER_CONFIG_NAME.yml"
dokku_log_info2 "Container config updated at location $CONFIG_FILE_PATH"
}
Expand Down