rails-infrastructure 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|