Skip to content

Commit

Permalink
Merge pull request #114 from fly-apps/single-database-url-secret
Browse files Browse the repository at this point in the history
Enable DATABASE_URL to control the placement of all of the databases
  • Loading branch information
rubys authored Sep 24, 2024
2 parents 8599053 + 02de62d commit a84f7f3
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 3 deletions.
29 changes: 29 additions & 0 deletions lib/generators/dockerfile_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ def generate_app

template "docker-compose.yml.erb", "docker-compose.yml" if options.compose

template "database.yml.erb", "config/database.yml" if fix_database_config

if using_litefs?
template "litefs.yml.erb", "config/litefs.yml"

Expand Down Expand Up @@ -1450,4 +1452,31 @@ def fly_make_toml

toml
end

# if there are multiple production databases defined, allow them all to be
# configured via DATABASE_URL.
def fix_database_config
yaml = IO.read("config/database.yml")

production = YAML.load(yaml, aliases: true)["production"]
return unless production.is_a?(Hash) && production.values.all?(Hash)
return if production.keys == [ "primary" ]

section = yaml[/^(production:.*?)(^\S|\z)/m, 1]

replacement = section.gsub(/( ).*?\n((\1\s+).*?\n)*/) do |subsection|
spaces = $3
name = subsection[/\w+/]

if /^ +url:/.match?(subsection)
subsection
elsif name == "primary"
subsection + spaces + %(url: <%= ENV["DATABASE_URL"] %>\n)
else
subsection + spaces + %(url: <%= URI.parse(ENV["DATABASE_URL"]).tap { |url| url.path += "_#{name}" } if ENV["DATABASE_URL"] %>\n)
end
end

yaml.sub(section, replacement)
end
end
1 change: 1 addition & 0 deletions lib/generators/templates/database.yml.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= fix_database_config %>
10 changes: 10 additions & 0 deletions test/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ def check_entrypoint
assert_equal expected, results
end

def check_database_config
results = IO.read("config/database.yml")

IO.write("#{@results}/database.yml", results) if @capture

expected = IO.read("#{@results}/database.yml")

assert_equal expected, results
end

def teardown
return if ENV["TEST_KEEP"]
Dir.chdir ".."
Expand Down
4 changes: 2 additions & 2 deletions test/results/postgresql/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ USER rails:rails
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]
EXPOSE 80
CMD ["bundle", "exec", "thrust", "./bin/rails", "server"]
102 changes: 102 additions & 0 deletions test/results/postgresql/database.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# PostgreSQL. Versions 9.3 and up are supported.
#
# Install the pg driver:
# gem install pg
# On macOS with Homebrew:
# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On Windows:
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem "pg"
#
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>


development:
<<: *default
database: test_postgresql_development

# The specified database role being used to connect to PostgreSQL.
# To create additional roles in PostgreSQL see `$ createuser --help`.
# When left blank, PostgreSQL will use the default role. This is
# the same name as the operating system user running Rails.
#username: test_postgresql

# The password associated with the PostgreSQL role (username).
#password:

# Connect on a TCP socket. Omitted by default since the client uses a
# domain socket that doesn't need configuration. Windows does not have
# domain sockets, so uncomment these lines.
#host: localhost

# The TCP port the server listens on. Defaults to 5432.
# If your server runs on a different port number, change accordingly.
#port: 5432

# Schema search path. The server defaults to $user,public
#schema_search_path: myapp,sharedapp,public

# Minimum log levels, in increasing order:
# debug5, debug4, debug3, debug2, debug1,
# log, notice, warning, error, fatal, and panic
# Defaults to warning.
#min_messages: notice

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: test_postgresql_test

# As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password or a full connection URL as an environment
# variable when you boot the app. For example:
#
# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# If the connection URL is provided in the special DATABASE_URL environment
# variable, Rails will automatically merge its configuration values on top of
# the values provided in this file. Alternatively, you can specify a connection
# URL environment variable explicitly:
#
# production:
# url: <%= ENV["MY_APP_DATABASE_URL"] %>
#
# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full overview on how database connection configuration can be specified.
#
production:
primary: &primary_production
<<: *default
database: test_postgresql_production
username: test_postgresql
password: <%= ENV["TEST_POSTGRESQL_DATABASE_PASSWORD"] %>
url: <%= ENV["DATABASE_URL"] %>
cache:
<<: *primary_production
database: test_postgresql_production_cache
migrations_paths: db/cache_migrate
url: <%= URI.parse(ENV["DATABASE_URL"]).tap { |url| url.path += "_cache" } if ENV["DATABASE_URL"] %>
queue:
<<: *primary_production
database: test_postgresql_production_queue
migrations_paths: db/queue_migrate
url: <%= URI.parse(ENV["DATABASE_URL"]).tap { |url| url.path += "_queue" } if ENV["DATABASE_URL"] %>
cable:
<<: *primary_production
database: test_postgresql_production_cable
migrations_paths: db/cable_migrate
url: <%= URI.parse(ENV["DATABASE_URL"]).tap { |url| url.path += "_cable" } if ENV["DATABASE_URL"] %>
3 changes: 2 additions & 1 deletion test/test_postgres.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
require_relative "base"

class TestPostgresql < TestBase
@rails_options = "--database=postgresql"
@rails_options = "--database=postgresql --main"
@generate_options = "--compose"

def test_postgresql
check_dockerfile
check_compose
check_database_config
end
end

0 comments on commit a84f7f3

Please sign in to comment.