Skip to content
This repository has been archived by the owner on Dec 31, 2022. It is now read-only.

Commit

Permalink
feat(appserver): "Thin" support added
Browse files Browse the repository at this point in the history
Resolves #39
  • Loading branch information
Igor Rzegocki committed Sep 2, 2016
1 parent f6e80ad commit 9667939
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 10 deletions.
14 changes: 13 additions & 1 deletion README.md
Expand Up @@ -28,6 +28,7 @@ then [add recipes to the corresponding OpsWorks actions](#recipes).
* App server
* Null (no appserver)
* Puma
* Thin
* Unicorn
* Web server
* Null (no webserver)
Expand Down Expand Up @@ -164,7 +165,7 @@ and `Puma` are supported.

* `app['appserver']['adapter']`
* **Default:** `unicorn`
* **Supported values:** `puma`, `unicorn`, `null`
* **Supported values:** `puma`, `thin`, `unicorn`, `null`
* Server on the application side, which will receive requests from webserver
in front. `null` means no appserver enabled.
* `app['appserver']['application_yml']`
Expand Down Expand Up @@ -219,6 +220,17 @@ and `Puma` are supported.
* [`app['appserver']['worker_processes']`](https://github.com/puma/puma/blob/c169853ff233dd3b5c4e8ed17e84e1a6d8cb565c/examples/config.rb#L107)
* **Default:** `4`

#### thin

* `app['appserver']['max_connections']`
* **Default:** `1024`
* `app['appserver']['max_persistent_connections']`
* **Default:** `512`
* `app['appserver']['timeout']`
* **Default:** `60`
* `app['appserver']['worker_processes']`
* **Default:** `4`

### webserver

Webserver configuration. Proxy passing to application is handled out-of-the-box.
Expand Down
15 changes: 10 additions & 5 deletions attributes/default.rb
Expand Up @@ -44,6 +44,16 @@
default['defaults']['appserver']['timeout'] = 60
default['defaults']['appserver']['worker_processes'] = 4

## puma

default['defaults']['appserver']['log_requests'] = false
default['defaults']['appserver']['thread_min'] = 0
default['defaults']['appserver']['thread_max'] = 16

## thin
default['defaults']['appserver']['max_connections'] = 1024
default['defaults']['appserver']['max_persistent_connections'] = 512

## unicorn

default['defaults']['appserver']['accept_filter'] = 'httpready'
Expand All @@ -53,11 +63,6 @@
default['defaults']['appserver']['tcp_nopush'] = false
default['defaults']['appserver']['tries'] = 5

## puma
default['defaults']['appserver']['log_requests'] = false
default['defaults']['appserver']['thread_min'] = 0
default['defaults']['appserver']['thread_max'] = 16

# webserver
## common

Expand Down
27 changes: 27 additions & 0 deletions libraries/drivers_appserver_thin.rb
@@ -0,0 +1,27 @@
# frozen_string_literal: true
module Drivers
module Appserver
class Thin < Drivers::Appserver::Base
adapter :thin
allowed_engines :thin
output filter: [:max_connections, :max_persistent_connections, :timeout, :worker_processes]

def add_appserver_config(context)
opts = { environment: app['environment'], deploy_dir: deploy_dir(app), out: out,
deploy_env: globals[:environment] }

context.template File.join(opts[:deploy_dir], File.join('shared', 'config', 'thin.yml')) do
owner node['deployer']['user']
group www_group
mode '0644'
source 'thin.yml.erb'
variables opts
end
end

def appserver_command(_context)
'thin -C #{ROOT_PATH}/shared/config/thin.yml'
end
end
end
end
5 changes: 5 additions & 0 deletions libraries/drivers_base.rb
Expand Up @@ -19,6 +19,11 @@ def self.adapter(adapter = nil)
(@adapter || self.class.name.underscore).to_s
end

def self.adapters(options = { include_null: false })
adapters = descendants.select { |descendant| descendant.respond_to?(:adapter) }.map(&:adapter)
options[:include_null] ? adapters : adapters - ['null']
end

# Dummy methods for children to redefine
def setup(_context)
end
Expand Down
2 changes: 1 addition & 1 deletion libraries/drivers_webserver_nginx.rb
Expand Up @@ -90,7 +90,7 @@ def add_dhparams(context)
def add_appserver_config(context)
opts = { application: app, deploy_dir: deploy_dir(app), out: out,
name: Drivers::Appserver::Factory.build(app, node).adapter }
return unless %w(unicorn puma).include?(opts[:name]) # @todo
return unless Drivers::Appserver::Base.adapters.include?(opts[:name])

context.template "/etc/nginx/sites-available/#{app['shortname']}" do
owner 'root'
Expand Down
3 changes: 2 additions & 1 deletion spec/fixtures/node.rb
Expand Up @@ -36,7 +36,8 @@ def node(override = {})
adapter: 'unicorn',
delay: 3,
thread_min: 0,
thread_max: 16
thread_max: 16,
max_connections: 4096
},
webserver: {
adapter: 'nginx',
Expand Down
97 changes: 95 additions & 2 deletions spec/unit/recipes/configure_spec.rb
Expand Up @@ -409,13 +409,23 @@
end
end

context 'Sqlite3' do
context 'Sqlite3 + Thin' do
let(:dummy_node) do
node(deploy: { dummy_project: { database: { adapter: 'sqlite3' }, environment: 'staging' } })
node(
deploy: {
dummy_project: {
database: { adapter: 'sqlite3' },
environment: 'staging',
appserver: node['deploy']['dummy_project']['appserver'].merge('adapter' => 'thin'),
webserver: node['deploy']['dummy_project']['webserver']
}
}
)
end
let(:chef_run) do
ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04') do |solo_node|
solo_node.set['deploy'] = dummy_node['deploy']
solo_node.set['nginx'] = node['nginx']
end.converge(described_recipe)
end

Expand All @@ -433,6 +443,89 @@
JSON.parse({ development: db_config, production: db_config, staging: db_config }.to_json).to_yaml
)
end

it 'creates proper thin.yml file' do
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/thin.yml")
.with_content('servers: 4')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/thin.yml")
.with_content('environment: "staging"')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/thin.yml")
.with_content('max_conns: 4096')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/thin.yml")
.with_content('timeout: 60')
end

it 'creates proper thin.service file' do
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/thin.service")
.with_content("APP_NAME=\"#{aws_opsworks_app['shortname']}\"")
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/thin.service")
.with_content("ROOT_PATH=\"/srv/www/#{aws_opsworks_app['shortname']}\"")
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/thin.service")
.with_content('DEPLOY_ENV="staging"')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/thin.service")
.with_content('thin -C #{ROOT_PATH}/shared/config/thin.yml')
end

it 'defines thin service' do
service = chef_run.service("thin_#{aws_opsworks_app['shortname']}")
expect(service).to do_nothing
expect(service.start_command)
.to eq "/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/thin.service start"
expect(service.stop_command)
.to eq "/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/thin.service stop"
expect(service.restart_command)
.to eq "/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/thin.service restart"
expect(service.status_command)
.to eq "/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/thin.service status"
end

it 'creates nginx thin proxy handler config' do
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('upstream thin_dummy-project.example.com {')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('client_max_body_size 125m;')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('client_body_timeout 30;')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('keepalive_timeout 15;')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('ssl_certificate_key /etc/nginx/ssl/dummy-project.example.com.key;')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('ssl_dhparam /etc/nginx/ssl/dummy-project.example.com.dhparams.pem;')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('ssl_ecdh_curve secp384r1;')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('ssl_stapling on;')
expect(chef_run)
.not_to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('ssl_session_tickets off;')
expect(chef_run)
.to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('extra_config {}')
expect(chef_run)
.not_to render_file("/etc/nginx/sites-available/#{aws_opsworks_app['shortname']}")
.with_content('extra_config_ssl {}')
expect(chef_run).to create_link("/etc/nginx/sites-enabled/#{aws_opsworks_app['shortname']}")
end
end

context 'No RDS (Database defined in node)' do
Expand Down
15 changes: 15 additions & 0 deletions templates/default/thin.yml.erb
@@ -0,0 +1,15 @@
---
user: "<%= node['deployer']['user'] %>"
pid: "<%= @deploy_dir %>/shared/pids/thin.pid"
timeout: <%= @out[:timeout] %>
wait: <%= @out[:timeout] %>
log: "<%= @deploy_dir %>/shared/log/thin.log"
max_conns: <%= @out[:max_connections] %>
environment: "<%= @deploy_env %>"
max_persistent_conns: <%= @out[:max_persistent_connections] %>
servers: <%= @out[:worker_processes] %>
threaded: true
no-epoll: true
daemonize: true
socket: "<%= @deploy_dir %>/shared/sockets/thin.sock"
chdir: "<%= @deploy_dir %>/current"

0 comments on commit 9667939

Please sign in to comment.