rails-infrastructure 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.rdoc +80 -0
  8. data/Rakefile +7 -0
  9. data/examples/infrastructure/databases.yml +29 -0
  10. data/examples/infrastructure/environment.yml +2 -0
  11. data/examples/infrastructure/server.yml +9 -0
  12. data/examples/infrastructure/servers/unicorn.rb +69 -0
  13. data/examples/infrastructure/servers/unicorn.yml.erb +13 -0
  14. data/examples/infrastructure/version.yml +2 -0
  15. data/examples/infrastructure.yml +11 -0
  16. data/lib/infrastructure/configurable.rb +51 -0
  17. data/lib/infrastructure/configuration.rb +93 -0
  18. data/lib/infrastructure/constants.rb +5 -0
  19. data/lib/infrastructure/databases.rb +117 -0
  20. data/lib/infrastructure/environment.rb +16 -0
  21. data/lib/infrastructure/path.rb +7 -0
  22. data/lib/infrastructure/railtie.rb +68 -0
  23. data/lib/infrastructure/server.rb +7 -0
  24. data/lib/infrastructure/version.rb +23 -0
  25. data/lib/infrastructure.rb +25 -0
  26. data/lib/rails-infrastructure.rb +2 -0
  27. data/lib/tasks/databases.rake +148 -0
  28. data/lib/tasks/environment.rake +19 -0
  29. data/lib/tasks/server.rake +73 -0
  30. data/lib/tasks/version.rake +23 -0
  31. data/rails-infrastructure.gemspec +28 -0
  32. data/test/infrastructure/configurable_test.rb +94 -0
  33. data/test/infrastructure/configuration_test.yml.erb +5 -0
  34. data/test/infrastructure/database_test.rb +108 -0
  35. data/test/infrastructure/environment_test.rb +23 -0
  36. data/test/infrastructure/paths_test.rb +9 -0
  37. data/test/infrastructure/server_test.rb +9 -0
  38. data/test/infrastructure/version_test.rb +23 -0
  39. data/test/infrastructure_test.rb +26 -0
  40. data/test/test_helper.rb +2 -0
  41. 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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rails-infrastructure.gemspec
4
+ gemspec
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,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.pattern = 'test/**/*_test.rb'
7
+ end
@@ -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,2 @@
1
+ ---
2
+ environment: development
@@ -0,0 +1,9 @@
1
+ ---
2
+ defaults:
3
+ daemonize: true
4
+ port: 8080
5
+ interface: 0.0.0.0
6
+ kill_signal: TERM
7
+
8
+ servers:
9
+ - unicorn
@@ -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,2 @@
1
+ ---
2
+ version: 2.1.3
@@ -0,0 +1,11 @@
1
+ ---
2
+ domain: my-domain.com
3
+ fruits:
4
+ - Apple
5
+ - Blueberry
6
+ - Grape
7
+ regex:
8
+ key: /\A[a-z0-9][a-z0-9_]+[a-z0-9]\z/
9
+ validation:
10
+ format:
11
+ message: is not in the correct format
@@ -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