Permalink
Browse files

feat(database): support null database driver

Fixes #98
  • Loading branch information...
nickmarden committed Aug 24, 2017
1 parent 89ce561 commit 29e104024815cffda010ebd6868f72e6cbeb7d99
View
@@ -124,3 +124,22 @@ suites:
adapter: 'null'
webserver:
adapter: 'null'
- name: maximum_override
data_bags_path: "test/integration/data_bags/maximum_override"
run_list:
- recipe[opsworks_ruby::setup]
- recipe[opsworks_ruby::deploy]
attributes:
deploy:
other_project:
database:
adapter: 'null'
framework:
adapter: 'rails'
assets_precompilation_command: '/bin/true'
appserver:
adapter: 'unicorn'
webserver:
adapter: 'apache2'
'ruby-ng':
ruby_version: '2.3'
@@ -117,9 +117,11 @@ database
- ``app['database']['adapter']``
- **Supported values:** ``mariadb``, ``mysql``, ``postgresql``, ``sqlite3``
- **Supported values:** ``mariadb``, ``mysql``, ``postgresql``, ``sqlite3``, ``null``
- **Default:** ``sqlite3``
- ActiveRecord adapter which will be used for database connection.
- ActiveRecord adapter which will be used for database connection. ``null`` means
that no database will be configured, and is currently only tested with the ``rails``
framework.
- ``app['database']['username']``
@@ -38,6 +38,14 @@ def applicable_for_configuration?
app['data_sources'].first['arn'] == options[:rds]['rds_db_instance_arn']
end
def can_migrate?
true
end
def url(_deploy_dir)
"#{out[:adapter]}://#{out[:username]}:#{out[:password]}@#{out[:host]}/#{out[:database]}"
end
protected
def app_engine
@@ -0,0 +1,16 @@
# frozen_string_literal: true
module Drivers
module Db
class Null < Base
adapter :null
allowed_engines :null
output filter: []
defaults username: nil, password: nil, host: nil, database: nil
def can_migrate?
false
end
end
end
end
@@ -12,6 +12,10 @@ def out
output[:database] ||= 'db/data.sqlite3'
handle_output(output)
end
def url(deploy_dir)
"sqlite://#{deploy_dir}/shared/#{out[:database]}"
end
end
end
end
@@ -20,7 +20,7 @@ def deploy_before_migrate
end
def deploy_before_symlink
link_sqlite_database unless out[:migrate]
link_sqlite_database unless migrate?
end
def deploy_before_restart
@@ -39,6 +39,10 @@ def raw_out
def validate_app_engine; end
def migrate?
applicable_databases.any?(&:can_migrate?) && out[:migrate]
end
protected
def assets_precompile
@@ -79,24 +83,17 @@ def link_sqlite_database
not_if { ::File.exist?(::File.join(release_path, relative_db_path)) }
end
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
def database_url
deploy_to = deploy_dir(app)
database_url = "sqlite://#{deploy_to}/shared/db/#{app['shortname']}_#{deploy_env}.sqlite"
Array.wrap(options[:databases]).each do |db|
next unless db.applicable_for_configuration?
database_url =
"#{db.out[:adapter]}://#{db.out[:username]}:#{db.out[:password]}@#{db.out[:host]}/#{db.out[:database]}"
database_url = "sqlite://#{deploy_to}/shared/#{db.out[:database]}" if db.out[:adapter].start_with?('sqlite')
end
applicable_databases.first.try(:url, deploy_to) ||
"sqlite://#{deploy_to}/shared/db/#{app['shortname']}_#{deploy_env}.sqlite"
end
database_url
def applicable_databases
Array.wrap(options[:databases]).select(&:applicable_for_configuration?)
end
# rubocop:enable Metrics/AbcSize
def environment
app['environment'].merge(out[:deploy_environment])
@@ -9,7 +9,7 @@ class Rails < Drivers::Framework::Base
migrate migration_command deploy_environment assets_precompile assets_precompilation_command
envs_in_console
]
packages debian: 'zlib1g-dev', rhel: 'zlib-devel'
packages debian: %w[libxml2-dev tzdata zlib1g-dev], rhel: %w[libxml2-devel tzdata zlib-devel]
log_paths lambda { |context|
File.join(context.send(:deploy_dir, context.app), 'shared', 'log', '*.log')
}
@@ -34,7 +34,7 @@ def deploy_after_restart
private
def database_yml(db)
return unless db.applicable_for_configuration?
return unless db.applicable_for_configuration? && db.can_migrate?
database = db.out
deploy_environment = deploy_env
View
@@ -60,7 +60,7 @@
end
migration_command(framework.out[:migration_command]) if framework.out[:migration_command]
migrate framework.out[:migrate]
migrate framework.migrate?
before_migrate do
perform_bundle_install(shared_path, bundle_env)
@@ -72,7 +72,7 @@
end
before_symlink do
perform_bundle_install(shared_path, bundle_env) unless framework.out[:migrate]
perform_bundle_install(shared_path, bundle_env) unless framework.migrate?
fire_hook(
:deploy_before_symlink, context: self, items: databases + [scm, framework, appserver, worker, webserver]
@@ -952,6 +952,35 @@
JSON.parse({ development: db_config, production: db_config, staging: db_config }.to_json).to_yaml
)
end
context '"null" database adapter' do
let(:supplied_node) do
node(deploy: {
dummy_project: {
database: {
adapter: 'null'
},
global: { environment: 'production' },
framework: { adapter: 'rails' }
}
})
end
before do
stub_search(:aws_opsworks_app, '*:*').and_return([aws_opsworks_app(data_sources: [])])
stub_search(:aws_opsworks_rds_db_instance, '*:*').and_return([])
end
it 'does not create a database.yml file' do
db_config = Drivers::Db::Null.new(chef_run, aws_opsworks_app(data_sources: [])).out
expect(db_config[:adapter]).to eq 'null'
expect(db_config[:username]).not_to be
expect(db_config[:password]).not_to be
expect(db_config[:host]).not_to be
expect(db_config[:database]).not_to be
expect(chef_run).not_to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/database.yml")
end
end
end
context 'empty node[\'deploy\']' do
@@ -0,0 +1,34 @@
{
"app_id": "3aef37c1-7e2b-4255-bbf1-03e06f07701a",
"app_source": {
"password": "3aa161d358a167204502",
"revision": "master",
"type": "git",
"url": "https://github.com/RapidRiverSoftware/dumber-app",
"user": "dummy"
},
"attributes": {
"auto_bundle_on_deploy": true,
"aws_flow_ruby_settings": {},
"document_root": "",
"rails_env": null
},
"data_sources": [],
"domains": [
"other-project.example.com",
"other_project"
],
"enable_ssl": true,
"environment": {
"ENV_VAR1": "test"
},
"name": "Dummy app",
"shortname": "other_project",
"ssl_configuration": {
"certificate": "-----BEGIN CERTIFICATE-----\nMIICkzCCAfwCCQCs8PFrlPxmzTANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMC\nVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExGDAWBgNVBAcTD1NpbGxpY29uIFZhbGxl\neTEWMBQGA1UEChQNb3Bzd29ya3NfcnVieTEWMBQGA1UEAxQNKi5leGFtcGxlLmNv\nbTEfMB0GCSqGSIb3DQEJARYQaWdvckByemVnb2NraS5wbDAeFw0xNjEwMjUxMzU4\nNDVaFw0xNzEwMjUxMzU4NDVaMIGNMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2Fs\naWZvcm5pYTEYMBYGA1UEBxMPU2lsbGljb24gVmFsbGV5MRYwFAYDVQQKFA1vcHN3\nb3Jrc19ydWJ5MRYwFAYDVQQDFA0qLmV4YW1wbGUuY29tMR8wHQYJKoZIhvcNAQkB\nFhBpZ29yQHJ6ZWdvY2tpLnBsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDF\nkSHFW+Vaffu/IHps5m5H/U+zeuIUuc/STWTzo82b+8Lv47n3jYB8Rx98Ti8lcPLW\nAIfRSo0pKry9vMYUNbzq+5bEoyfJWWnFgKlHwL5Znl2104Go9sjGHOcnggTFxoH+\n3GbBlM122h2aaxNDn3BLpvlCbfWRkyuZBJRYJ8BDAwIDAQABMA0GCSqGSIb3DQEB\nBQUAA4GBAJvYjvy/bK+8bFKt/EelhSWM/+/YWxQeH6WyKVkKCFu8SAcudtIUN0+b\nmgtpX8hLR7OfJ1QGHbj50USBvMcZcXPseSA9tl3uVsFeIHpVIJDzwcXd2UIklqa0\nTWWRQeP80euInTpyMZ3nygG48O00WGDV081UMS0mLUxAKVeLdUJA\n-----END CERTIFICATE-----\n",
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQDFkSHFW+Vaffu/IHps5m5H/U+zeuIUuc/STWTzo82b+8Lv47n3\njYB8Rx98Ti8lcPLWAIfRSo0pKry9vMYUNbzq+5bEoyfJWWnFgKlHwL5Znl2104Go\n9sjGHOcnggTFxoH+3GbBlM122h2aaxNDn3BLpvlCbfWRkyuZBJRYJ8BDAwIDAQAB\nAoGAC5gWyUQ5U3QtP+wiAx4KvsLI2JmPhvPYlFjiYcHtIQhHSlis4zA0qBZsbJkR\n/zp/pbtmPQwI+K9/YAsh/LGionUEfNyM4m3tuvLY860AqTlD4fCFANvLEXX4ryGq\n4Jjy8Vsq8+Yf9+Ej2VaKBR2TJJxczdgeDii2t74f+Y44DeECQQD+aBRGl18yfk5Y\nkrSWA1vnG7Nnd1eh0WXN1wUVq1/wgt8P2Ejuwyf2KrKgYoUOBfSL+p9mwsO6cR4X\ns9YJTRKJAkEAxs3qM7YoM2xFuohcuMCzTb+7kpV5nahZc0NyipFtCUfKU0JAqgr5\nN5HTQ756s3pvoifkVNE0b14xpnj1Qmt2KwJBALWlCH0SjXUW+8eAEBJgGZlcjO7e\nJiKyyRZ8ZPQA5cJrHutISWK40uqPt/SOA2Rs2hur+W48t9WB+LOBwtvnPMkCQFyX\n84j6QmcQ+rkSYf0640hHENoI/IfNrTveIi8f5KT55uY4aV3JlqGnLbrTsNp/IBdq\ndRJ8DewA9ycOF01EN9kCQEJVMn/cgbTT4hNyte2ycyHxTSh1h5ImipV8khcopanV\naSxsp8mM4JwGSzWtfF9+EMVymZ2OsH7oSYfawzKjSGg=\n-----END RSA PRIVATE KEY-----\n"
},
"type": "other",
"deploy": true,
"id": "other_project"
}
@@ -0,0 +1,142 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'opsworks_ruby::setup' do
describe package('ruby2.3') do
it { should be_installed }
end
describe package('libsqlite3-dev') do
it { should_not be_installed }
end
describe package('git') do
it { should be_installed }
end
describe package('apache2') do
it { should be_installed }
end
describe package('redis-server') do
it { should_not be_installed }
end
describe file('/usr/local/bin/bundle') do
it { should be_symlink }
end
end
describe 'opsworks_ruby::configure' do
context 'webserver' do
describe file('/etc/logrotate.d/other_project-apache2-production') do
its(:content) do
should include '"/var/log/apache2/other-project.example.com.access.log" ' \
'"/var/log/apache2/other-project.example.com.error.log" {'
end
its(:content) { should include ' daily' }
its(:content) { should include ' rotate 30' }
its(:content) { should include ' missingok' }
its(:content) { should include ' compress' }
its(:content) { should include ' delaycompress' }
its(:content) { should include ' notifempty' }
its(:content) { should include ' copytruncate' }
its(:content) { should include ' sharedscripts' }
end
describe file('/etc/apache2/ssl/other-project.example.com.key') do
its(:content) { should include '-----BEGIN RSA PRIVATE KEY-----' }
end
describe file('/etc/apache2/ssl/other-project.example.com.crt') do
its(:content) { should include '-----BEGIN CERTIFICATE-----' }
end
describe file('/etc/apache2/ssl/other-project.example.com.ca') do
it { should_not exist }
end
describe file('/etc/apache2/ssl/other-project.example.com.dhparams.pem') do
it { should_not exist }
end
describe file('/etc/apache2/sites-enabled/other_project.conf') do
it { should be_symlink }
end
describe file('/etc/apache2/sites-available/other_project.conf') do
its(:content) { should include '<Proxy balancer://unicorn_other_project_example_com>' }
its(:content) { should include 'SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH' }
its(:content) { should include 'DocumentRoot /srv/www/other_project/current/public' }
end
end
context 'appserver' do
describe file('/srv/www/other_project/shared/config/unicorn.conf') do
its(:content) { should include ':backlog => 1024' }
its(:content) { should include ':tries => 5' }
its(:content) { should include 'listen "127.0.0.1:3000"' }
end
describe file('/srv/www/other_project/shared/scripts/unicorn.service') do
its(:content) { should include 'ENV[\'ENV_VAR1\'] = "test"' }
its(:content) { should include 'ENV[\'HOME\'] = "/home/deploy"' }
its(:content) { should include 'ENV[\'USER\'] = "deploy"' }
its(:content) { should include 'PID_PATH="/srv/www/other_project/shared/pids/unicorn.pid"' }
its(:content) { should include 'def unicorn_running?' }
end
end
context 'framework' do
describe file('/etc/logrotate.d/other_project-rails-production') do
its(:content) { should include '"/srv/www/other_project/shared/log/*.log" {' }
its(:content) { should include ' daily' }
its(:content) { should include ' rotate 30' }
its(:content) { should include ' missingok' }
its(:content) { should include ' compress' }
its(:content) { should include ' delaycompress' }
its(:content) { should include ' notifempty' }
its(:content) { should include ' copytruncate' }
its(:content) { should include ' sharedscripts' }
end
describe file('/srv/www/other_project/shared/config/.env.production') do
it { should_not exist }
end
end
end
describe 'opsworks_ruby::deploy' do
context 'scm' do
describe file('/tmp/ssh-git-wrapper.sh') do
its(:content) { should include 'exec ssh -o UserKnownHostsFile=/dev/null' }
end
describe file('/srv/www/other_project/current/.git') do
it { should_not exist }
end
end
context 'webserver' do
describe service('apache2') do
it { should be_running }
end
end
context 'appserver' do
describe command('pgrep -f unicorn | tr \'\n\' \' \'') do
its(:stdout) { should match(/(?:[0-9]+ ){2}/) }
end
end
context 'framework' do
describe file('/srv/www/other_project/shared/config/database.yml') do
it { should_not exist }
end
describe file('/srv/www/other_project/current/config/database.yml') do
it { should be_symlink }
end
end
end

0 comments on commit 29e1040

Please sign in to comment.