Skip to content

Commit

Permalink
feat: allow Pact Broker to run on Heroku
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed May 6, 2020
1 parent ba1f1e1 commit bf006c7
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 22 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ If you want to run the container as a standalone instance, then the `dius/pact-b

For a postgres or mysql database:

You can either set the PACT_BROKER_DATABASE_URL in the format `driver://username:password@host:port/database` (eg. `postgres://user1:pass1@myhost/mydb`) or, you can set the credentials individually using the following environment variables:

* PACT_BROKER_DATABASE_ADAPTER (optional, defaults to 'postgres', see note below.)
* PACT_BROKER_DATABASE_USERNAME
* PACT_BROKER_DATABASE_PASSWORD
* PACT_BROKER_DATABASE_HOST
* PACT_BROKER_DATABASE_NAME
* PACT_BROKER_DATABASE_PORT (optional, defaults to the default port for the specified adapter)
* PACT_BROKER_DATABASE_SSLMODE (optional, possible values: 'disable', 'allow', 'prefer', 'require', 'verify-ca', or 'verify-full' to choose how to treat SSL (only respected if using the postgres database adapter). See https://www.postgresql.org/docs/9.1/libpq-ssl.html for more information.)

Adapter can be 'postgres' (recommended) or 'mysql2' (please note that future JSON search features may not be supported on mysql).

Expand All @@ -46,6 +47,10 @@ For an sqlite database (only recommended for investigation/spikes, as it will be
* PACT_BROKER_DATABASE_ADAPTER (set to 'sqlite')
* PACT_BROKER_DATABASE_NAME (arbitrary name eg. pact_broker.sqlite)

You can additionally set:

* PACT_BROKER_DATABASE_SSLMODE (optional, possible values: 'disable', 'allow', 'prefer', 'require', 'verify-ca', or 'verify-full' to choose how to treat SSL (only respected if using the postgres database adapter). See https://www.postgresql.org/docs/9.1/libpq-ssl.html for more information.)

3. Test the pact broker environment by executing [script/test.sh][test-script]

## Notes
Expand Down Expand Up @@ -130,6 +135,10 @@ See [pact-broker-openshift][pact-broker-openshift] for an example config file.

Don't call your service "pact_broker" as it will create an environment called `PACT_BROKER_PORT` which will clash with the docker images own environment variables. See this issue: https://github.com/pact-foundation/pact-broker-docker/issues/7

## Running on Heroku

Heroku provides the database connection string as the environment variable `$DATABASE_URL`. To tell the Pact Broker to use this environment variable rather than `$PACT_BROKER_DATABASE_URL`, set the environment variable `PACT_BROKER_DATABASE_URL_ENVIRONMENT_VARIABLE_NAME=DATABASE_URL`.

## Database migrations

The Pact Broker auto migrates on startup, and will always do so in a way that is backwards compatible, to support architectures that run multiple instances of the application at a time (eg. AWS auto scaling).
Expand Down
11 changes: 7 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ services:
depends_on:
- postgres
environment:
PACT_BROKER_DATABASE_USERNAME: postgres
PACT_BROKER_DATABASE_PASSWORD: password
PACT_BROKER_DATABASE_HOST: postgres
PACT_BROKER_DATABASE_NAME: postgres
PACT_BROKER_DATABASE_URL_ENVIRONMENT_VARIABLE_NAME: DATABASE_URL
DATABASE_URL: "postgres://postgres:password@postgres/postgres"
# PACT_BROKER_DATABASE_USERNAME: postgres
# PACT_BROKER_DATABASE_PASSWORD: password
# PACT_BROKER_DATABASE_HOST: postgres
# PACT_BROKER_DATABASE_NAME: postgres
PACT_BROKER_PORT: "9292"
PACT_BROKER_LOG_LEVEL: INFO

# Nginx is not necessary, but demonstrates how
# one might use a reverse proxy in front of the broker,
Expand Down
49 changes: 32 additions & 17 deletions pact_broker/database_connection.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
require 'sequel'
require_relative 'database_logger'

def create_database_connection(logger)
database_adapter = ENV.fetch('PACT_BROKER_DATABASE_ADAPTER','') != '' ? ENV['PACT_BROKER_DATABASE_ADAPTER'] : 'postgres'
DB_ENV_VAR_NAME = ENV.fetch('PACT_BROKER_DATABASE_URL_ENVIRONMENT_VARIABLE_NAME', 'PACT_BROKER_DATABASE_URL')
URL = ENV[DB_ENV_VAR_NAME]
SSL_MODE = ENV.fetch('PACT_BROKER_DATABASE_SSLMODE','')
ADAPTER = ENV.fetch('PACT_BROKER_DATABASE_ADAPTER','') != '' ? ENV['PACT_BROKER_DATABASE_ADAPTER'] : 'postgres'
USERNAME = ENV['PACT_BROKER_DATABASE_USERNAME']
PASSWORD = ENV['PACT_BROKER_DATABASE_PASSWORD']
HOST = ENV['PACT_BROKER_DATABASE_HOST']
NAME = ENV['PACT_BROKER_DATABASE_NAME']
PORT = ENV['PACT_BROKER_DATABASE_PORT']

config = {
adapter: database_adapter,
user: ENV['PACT_BROKER_DATABASE_USERNAME'],
password: ENV['PACT_BROKER_DATABASE_PASSWORD'],
host: ENV['PACT_BROKER_DATABASE_HOST'],
database: ENV['PACT_BROKER_DATABASE_NAME'],
encoding: 'utf8'
def create_database_connection(logger)
non_credential_options = {
encoding: 'utf8',
logger: DatabaseLogger.new(logger)
}
non_credential_options[:sslmode] = SSL_MODE if SSL_MODE != ''

if ENV.fetch('PACT_BROKER_DATABASE_SSLMODE','') != ''
config[:sslmode] = ENV['PACT_BROKER_DATABASE_SSLMODE']
end
connection = if URL
uri = URI(URL)
uri.password = "*****"
logger.info "Connecting to database #{uri} with config: #{non_credential_options}"
Sequel.connect(URL, non_credential_options)
else
config = {
adapter: ADAPTER,
user: USERNAME,
password: PASSWORD,
host: HOST,
database: NAME,
}.merge(non_credential_options)

if ENV['PACT_BROKER_DATABASE_PORT'] =~ /^\d+$/
config[:port] = ENV['PACT_BROKER_DATABASE_PORT'].to_i
config[:port] = PORT.to_i if PORT =~ /^\d+$/

logger.info "Connecting to database with config: #{config.merge(password: "*****")}"
Sequel.connect(config)
end

##
Expand All @@ -38,9 +55,7 @@ def create_database_connection(logger)
# -1 means that connections will be validated every time, which avoids errors
# when databases are restarted and connections are killed. This has a performance
# penalty, so consider increasing this timeout if building a frequently accessed service.
logger.info "Connecting to database with config: #{config.merge(password: "*****")}"
config[:logger] = DatabaseLogger.new(logger)
connection = Sequel.connect(config)

connection.extension(:connection_validator)
connection.pool.connection_validation_timeout = -1
connection
Expand Down

0 comments on commit bf006c7

Please sign in to comment.