rails-infrastructure 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +80 -0
- data/Rakefile +7 -0
- data/examples/infrastructure/databases.yml +29 -0
- data/examples/infrastructure/environment.yml +2 -0
- data/examples/infrastructure/server.yml +9 -0
- data/examples/infrastructure/servers/unicorn.rb +69 -0
- data/examples/infrastructure/servers/unicorn.yml.erb +13 -0
- data/examples/infrastructure/version.yml +2 -0
- data/examples/infrastructure.yml +11 -0
- data/lib/infrastructure/configurable.rb +51 -0
- data/lib/infrastructure/configuration.rb +93 -0
- data/lib/infrastructure/constants.rb +5 -0
- data/lib/infrastructure/databases.rb +117 -0
- data/lib/infrastructure/environment.rb +16 -0
- data/lib/infrastructure/path.rb +7 -0
- data/lib/infrastructure/railtie.rb +68 -0
- data/lib/infrastructure/server.rb +7 -0
- data/lib/infrastructure/version.rb +23 -0
- data/lib/infrastructure.rb +25 -0
- data/lib/rails-infrastructure.rb +2 -0
- data/lib/tasks/databases.rake +148 -0
- data/lib/tasks/environment.rake +19 -0
- data/lib/tasks/server.rake +73 -0
- data/lib/tasks/version.rake +23 -0
- data/rails-infrastructure.gemspec +28 -0
- data/test/infrastructure/configurable_test.rb +94 -0
- data/test/infrastructure/configuration_test.yml.erb +5 -0
- data/test/infrastructure/database_test.rb +108 -0
- data/test/infrastructure/environment_test.rb +23 -0
- data/test/infrastructure/paths_test.rb +9 -0
- data/test/infrastructure/server_test.rb +9 -0
- data/test/infrastructure/version_test.rb +23 -0
- data/test/infrastructure_test.rb +26 -0
- data/test/test_helper.rb +2 -0
- metadata +163 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ae39560352b96bff043a01081b3f177ef773939a
|
4
|
+
data.tar.gz: c047a2e92b7238608c753f7854bac01fcba115e6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 78f4f9ee3fedc2482bc7ac0f5aca68d8896c75785b837a3187559681cffdbb1d9b27c7d2ffe6e0e4c4f8a45b12448e942fdccc9455fd708992d05955909bf85b
|
7
|
+
data.tar.gz: c3f63bece8638110c4045238aef75ec528fb710c113b9d7c3bd0f5f325023e8e2b9711084193122fe75fb17f7e943a9948aeacf2b7b590e36417221e52c53d9a
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
infrastructure
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0.0-p247
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Griffith Chaffee
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
= Rails::Infrastructure
|
2
|
+
|
3
|
+
This gem provides several much needed enhancements to the rails framework
|
4
|
+
|
5
|
+
1. Multi database support and management
|
6
|
+
2. Environment management
|
7
|
+
3. Version managment
|
8
|
+
4. Path managment
|
9
|
+
5. Server management
|
10
|
+
6. Useful configuration module mixin
|
11
|
+
7. Rails configuration constant
|
12
|
+
|
13
|
+
= Getting Started
|
14
|
+
|
15
|
+
# Gemfile
|
16
|
+
gem 'rails-infrastructure'
|
17
|
+
|
18
|
+
Copy examples into config directory
|
19
|
+
|
20
|
+
# example layout
|
21
|
+
config/infrastructure.yml
|
22
|
+
config/infrastructure/version.yml
|
23
|
+
config/infrastructure/environment.yml
|
24
|
+
config/infrastructure/server.yml
|
25
|
+
config/infrastructure/servers/unicorn.yml.erb
|
26
|
+
...
|
27
|
+
|
28
|
+
== Muli Database Support
|
29
|
+
|
30
|
+
Infrastructure::Databases
|
31
|
+
|
32
|
+
This class provides all the required functions for connecting and working with multiple databases through ActiveRecord. There several rake tasks preconfigured to replace their rails countarparts.
|
33
|
+
|
34
|
+
rake database:create[id] # Create database if it does not exist
|
35
|
+
rake database:drop[id,force] # Drop database if exists
|
36
|
+
rake database:migrate[id,version] # Migrate database
|
37
|
+
rake database:reset[id,force] # Drop, create, then migrate database
|
38
|
+
rake database:reset:seed[force] # Reset then seed database
|
39
|
+
rake database:rollback[id,version] # Rollback database
|
40
|
+
rake database:seed[id] # Seed database
|
41
|
+
rake databases:create # Create all databases that dont exist
|
42
|
+
rake databases:drop[force] # Drop all databases that exist
|
43
|
+
rake databases:migrate[version] # Migrate all databases
|
44
|
+
rake databases:reset[force] # Drop, create, migrate all databases
|
45
|
+
rake databases:reset:seed[force] # Reset then seed all databases
|
46
|
+
rake databases:rollback[version] # Rollback all databases
|
47
|
+
rake databases:seed[force] # Seed all databases
|
48
|
+
|
49
|
+
== Environment Management
|
50
|
+
|
51
|
+
Infrastructure::Environment
|
52
|
+
|
53
|
+
rake environment:current # display current environment
|
54
|
+
rake environment:development # Change to development environment
|
55
|
+
rake environment:production # Change to production environment
|
56
|
+
rake environment:test # Change to test environment
|
57
|
+
|
58
|
+
== Version Management
|
59
|
+
|
60
|
+
Infrastructure::Version
|
61
|
+
|
62
|
+
rake version:bump:major # Bump major version
|
63
|
+
rake version:bump:minor # Bump minor version
|
64
|
+
rake version:bump:tiny # Bump tiny version
|
65
|
+
rake version:current # display current version
|
66
|
+
|
67
|
+
== Server Management
|
68
|
+
|
69
|
+
Infrastructure::Server
|
70
|
+
|
71
|
+
rake server:unicorn:kill # Kill unicorn server
|
72
|
+
rake server:unicorn:restart # Restart unicorn server
|
73
|
+
rake server:unicorn:start # Start unicorn server
|
74
|
+
rake server:unicorn:stop # Stop unicorn server
|
75
|
+
rake server:unicorn:tail # Tail unicorn server log file
|
76
|
+
|
77
|
+
== Path Management
|
78
|
+
|
79
|
+
Infrastructure::Path
|
80
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
---
|
2
|
+
system:
|
3
|
+
database: postgres
|
4
|
+
|
5
|
+
defaults:
|
6
|
+
adapter: postgresql
|
7
|
+
encoding: unicode
|
8
|
+
username: root
|
9
|
+
password: toor
|
10
|
+
pool: 5
|
11
|
+
host: localhost
|
12
|
+
|
13
|
+
test:
|
14
|
+
defaults:
|
15
|
+
id: test
|
16
|
+
test: {}
|
17
|
+
|
18
|
+
development:
|
19
|
+
defaults:
|
20
|
+
id: dev1
|
21
|
+
dev1: {}
|
22
|
+
dev2: {}
|
23
|
+
|
24
|
+
production:
|
25
|
+
defaults:
|
26
|
+
id: demo
|
27
|
+
demo: {}
|
28
|
+
best: {}
|
29
|
+
other: {}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.expand_path('../../../application', __FILE__)
|
2
|
+
|
3
|
+
config = Inf.server.unicorn
|
4
|
+
|
5
|
+
# workers
|
6
|
+
worker_processes config.workers
|
7
|
+
|
8
|
+
# worker response timeout
|
9
|
+
timeout config.timeout
|
10
|
+
|
11
|
+
# iisten on interface
|
12
|
+
listen "#{config.interface}:#{config.port}", backlog: config.backlog
|
13
|
+
# listen on socket
|
14
|
+
listen config.socket_file, backlog: config.backlog
|
15
|
+
# pid file
|
16
|
+
pid config.pid_file
|
17
|
+
|
18
|
+
# logs
|
19
|
+
stderr_path = config.log_file
|
20
|
+
stdout_path = config.log_file
|
21
|
+
logger = Logger.new config.log_file
|
22
|
+
logger logger
|
23
|
+
|
24
|
+
# general
|
25
|
+
check_client_connection false
|
26
|
+
preload_app true
|
27
|
+
|
28
|
+
if GC.respond_to?(:copy_on_write_friendly=)
|
29
|
+
GC.copy_on_write_friendly = true
|
30
|
+
end
|
31
|
+
|
32
|
+
before_fork do |server, worker|
|
33
|
+
ActiveRecord::Base.connection.disconnect!
|
34
|
+
old_pid_file = config.pid_file + '.oldbin'
|
35
|
+
if File.exists? old_pid_file
|
36
|
+
begin
|
37
|
+
Process.kill 'QUIT', File.read(old_pid_file).strip.to_i
|
38
|
+
rescue Errno::ENOENT, Errno::ESRCH
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
after_fork do |server, worker|
|
44
|
+
ActiveRecord::Base.establish_connection
|
45
|
+
begin
|
46
|
+
uid, gid = Process.euid, Process.egid
|
47
|
+
user config.user, config.group
|
48
|
+
target_uid = Etc.getpwnam(config.user).uid
|
49
|
+
target_gid = Etc.getgrnam(config.group).gid
|
50
|
+
worker.tmp.chown target_uid, target_gid
|
51
|
+
if uid != target_uid || gid != target_gid
|
52
|
+
Process.initgroups config.user, target_gid
|
53
|
+
Process::GID.change_privilege target_gid
|
54
|
+
Process::UID.change_privilege target_uid
|
55
|
+
end
|
56
|
+
rescue ArgumentError => error
|
57
|
+
if error.message.include? "can't find user"
|
58
|
+
unless Rails.env.production?
|
59
|
+
logger.info { "Could not change to user/group #{config.user}:#{config.group} but ignoring because environment is not production" }
|
60
|
+
else
|
61
|
+
logger.fatal { "Could not change to user/group #{config.user}:#{config.group}" }
|
62
|
+
Process.kill 'QUIT', server.pid.to_i
|
63
|
+
end
|
64
|
+
else
|
65
|
+
logger.fatal { "#{error.class}: #{error.message}\n" + error.backtrace.join("\n") }
|
66
|
+
Process.kill 'QUIT', server.pid.to_i
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
---
|
2
|
+
config_file: <%= Inf.path.rails.infrastructure_servers_dir + '/unicorn.rb' %>
|
3
|
+
socket_file: <%= Inf.path.rails.tmp_sockets_dir + '/unicorn.sock' %>
|
4
|
+
pid_file: <%= Inf.path.rails.tmp_pids_dir + '/unicorn.pid' %>
|
5
|
+
log_file: <%= Inf.path.rails.log_dir + "/unicorn.#{Inf.environment.to_s}.log" %>
|
6
|
+
workers: <%= Inf.environment.production? ? 16 : 4 %>
|
7
|
+
user: unicorn
|
8
|
+
group: unicorn
|
9
|
+
timeout: 15
|
10
|
+
backlog: 1024
|
11
|
+
stop: kill
|
12
|
+
stop_signal: QUIT
|
13
|
+
start: unicorn_rails -c <%= Inf.path.rails.infrastructure_servers_dir + '/unicorn.rb' %> -D
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Infrastructure
|
2
|
+
module Configurable
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend Forwardable
|
6
|
+
base.send :def_delegators, :configuration, :assign, :fetch, :configure, :each
|
7
|
+
base.send :def_delegators, :configuration, :load_config, :load_config_if_exists, :save_config
|
8
|
+
end
|
9
|
+
|
10
|
+
def configuration
|
11
|
+
@configuration ||= Configuration.new self
|
12
|
+
end
|
13
|
+
|
14
|
+
def callback(key, *params, &block)
|
15
|
+
callbacks[key] << block if block
|
16
|
+
callbacks[key] += Array(params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def callbacks
|
20
|
+
@callbacks ||= {
|
21
|
+
before_configure: [],
|
22
|
+
after_configure: [],
|
23
|
+
before_assignment: [
|
24
|
+
-> (key, value) { configuration_accessor key unless respond_to? key }
|
25
|
+
],
|
26
|
+
after_assignment: []
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def configuration_accessor(key)
|
31
|
+
self.class.send(:define_method, key) { configuration.send(key) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def before_assignment(*params)
|
35
|
+
callbacks[:before_assignment].each { |block| block.call *params }
|
36
|
+
end
|
37
|
+
|
38
|
+
def after_assignment(*params)
|
39
|
+
callbacks[:after_assignment].each { |block| block.call *params }
|
40
|
+
end
|
41
|
+
|
42
|
+
def before_configure(*params)
|
43
|
+
callbacks[:before_configure].each { |block| block.call *params }
|
44
|
+
end
|
45
|
+
|
46
|
+
def after_configure(*params)
|
47
|
+
callbacks[:after_configure].each { |block| block.call *params }
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class Infrastructure
|
2
|
+
class Configuration
|
3
|
+
attr_reader :attributes
|
4
|
+
|
5
|
+
def initialize(base, config = {})
|
6
|
+
@base = base
|
7
|
+
@attributes = Hash.new
|
8
|
+
assign config
|
9
|
+
end
|
10
|
+
|
11
|
+
def configure(&block)
|
12
|
+
raise "configure expects a block" unless block
|
13
|
+
before_configure
|
14
|
+
instance_eval &block
|
15
|
+
after_configure
|
16
|
+
end
|
17
|
+
|
18
|
+
def config
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_config_if_exists(path_to_config_file, &block)
|
23
|
+
if File.exists? path_to_config_file
|
24
|
+
load_config path_to_config_file, &block
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_config(path_to_config_file, &block)
|
29
|
+
assign YAML.load(ERB.new(File.read(path_to_config_file)).result)
|
30
|
+
block.call if block
|
31
|
+
end
|
32
|
+
|
33
|
+
def save_config(path_to_config_file)
|
34
|
+
File.open(path_to_config_file, 'w') do |file|
|
35
|
+
file.write to_h(stringify_keys: true).to_yaml
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_h(params = {})
|
40
|
+
attributes = @attributes.dup
|
41
|
+
if params[:stringify_keys]
|
42
|
+
attributes.keys.each { |key| attributes[key.to_s] = attributes.delete(key) unless key.is_a?(String) }
|
43
|
+
attributes.each { |key, value| attributes[key] = value.to_h(params) if value.is_a? Configuration }
|
44
|
+
else
|
45
|
+
attributes.each { |key, value| attributes[key] = value.to_h(params) if value.is_a? Configuration }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def fetch(key)
|
50
|
+
@attributes[key.to_sym]
|
51
|
+
end
|
52
|
+
|
53
|
+
def before_configure(*params)
|
54
|
+
@base.before_configure *params
|
55
|
+
end
|
56
|
+
|
57
|
+
def after_configure(*params)
|
58
|
+
@base.after_configure *params
|
59
|
+
end
|
60
|
+
|
61
|
+
def before_assignment(*params)
|
62
|
+
@base.before_assignment *params
|
63
|
+
end
|
64
|
+
|
65
|
+
def after_assignment(*params)
|
66
|
+
@base.after_assignment *params
|
67
|
+
end
|
68
|
+
|
69
|
+
def assign(key, value = nil)
|
70
|
+
if key.is_a?(Hash)
|
71
|
+
key.each { |k,v| assign k, v }
|
72
|
+
else
|
73
|
+
key = key.to_sym
|
74
|
+
before_assignment key, value
|
75
|
+
@attributes[key] = value.is_a?(Hash) ? Configuration.new(self, value) : value
|
76
|
+
after_assignment key, value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def method_missing(method, *params, &block)
|
81
|
+
if @attributes.keys.include? method
|
82
|
+
fetch method
|
83
|
+
elsif method.to_s.end_with? '='
|
84
|
+
assign method.to_s[0..-2], params.first
|
85
|
+
elsif @attributes.respond_to? method
|
86
|
+
@attributes.send method, *params, &block
|
87
|
+
else
|
88
|
+
super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|