golden_brindle 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ module GoldenBrindle
2
+ module Actions
3
+
4
+ class Stop < ::GoldenBrindle::Base
5
+
6
+ def configure
7
+ options [
8
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded).", :@cwd, "."],
9
+ ['-C', '--config PATH', "Use a mongrel based config file", :@config_file, nil],
10
+ ['-f', '--force', "Force the shutdown (kill -9).", :@force, false],
11
+ ['-w', '--wait SECONDS', "Wait SECONDS before forcing shutdown", :@wait, "0"],
12
+ ['-P', '--pid FILE', "Where the PID file is located.", :@pid_file, "tmp/pids/unicorn.pid"]
13
+ ]
14
+ end
15
+
16
+ def validate
17
+ if @config_file
18
+ valid_exists?(@config_file, "Config file not there: #@config_file")
19
+ @config_file = File.expand_path(@config_file)
20
+ load_config
21
+ return @valid
22
+ end
23
+
24
+ @cwd = File.expand_path(@cwd)
25
+ valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
26
+ valid_exists? File.join(@cwd,@pid_file), "PID file #@pid_file does not exist. Not running?"
27
+ return @valid
28
+ end
29
+
30
+ def run
31
+ @pid_file = File.join(@cwd,@pid_file)
32
+ if @force
33
+ @wait.to_i.times do |waiting|
34
+ exit(0) if not File.exist? @pid_file
35
+ sleep 1
36
+ end
37
+ GoldenBrindle::send_signal("KILL", @pid_file) if File.exist? @pid_file
38
+ else
39
+ GoldenBrindle::send_signal("TERM", @pid_file)
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,89 @@
1
+ module GoldenBrindle
2
+ class Base
3
+ include Validations
4
+ attr_reader :valid, :done_validating, :original_args
5
+
6
+ # Called by the subclass to setup the command and parse the argv arguments.
7
+ # The call is destructive on argv since it uses the OptionParser#parse! function.
8
+ def initialize(argv)
9
+ @opt = ::OptionParser.new
10
+ @opt.banner = GoldenBrindle::Const::BANNER
11
+ @valid = true
12
+ # this is retarded, but it has to be done this way because -h and -v exit
13
+ @done_validating = false
14
+ @original_args = argv.dup
15
+ configure
16
+ # I need to add my own -h definition to prevent the -h by default from exiting.
17
+ @opt.on_tail("-h", "--help", "Show this message") do
18
+ @done_validating = true
19
+ puts @opt
20
+ end
21
+ # I need to add my own -v definition to prevent the -v from exiting by default as well.
22
+ @opt.on_tail("--version", "Show version") do
23
+ @done_validating = true
24
+ if VERSION
25
+ puts "Version #{GoldenBrindle::Const::VERSION}"
26
+ end
27
+ end
28
+ @opt.parse! argv
29
+ end
30
+
31
+ # Called by the implemented command to set the options for that command.
32
+ # Every option has a short and long version, a description, a variable to
33
+ # set, and a default value. No exceptions.
34
+ def options(opts)
35
+ # process the given options array
36
+ opts.each do |short, long, help, variable, default|
37
+ self.instance_variable_set(variable, default)
38
+ @opt.on(short, long, help) do |arg|
39
+ self.instance_variable_set(variable, arg)
40
+ end
41
+ end
42
+ end
43
+
44
+ def configure
45
+ options []
46
+ end
47
+
48
+ def config_keys
49
+ GoldenBrindle::Const::CONFIG_KEYS
50
+ end
51
+
52
+ def load_config
53
+ settings = {}
54
+ begin
55
+ settings = ::YAML.load_file(@config_file)
56
+ ensure
57
+ STDERR.puts "** Loading settings from #{@config_file} (they override command line)." unless @daemon || settings[:daemon]
58
+ end
59
+
60
+ # Config file settings will override command line settings
61
+ settings.each do |key, value|
62
+ key = key.to_s
63
+ if config_keys.include?(key)
64
+ key = 'address' if key == 'host'
65
+ self.instance_variable_set("@#{key}", value)
66
+ else
67
+ failure "Unknown configuration setting: #{key}"
68
+ @valid = false
69
+ end
70
+ end
71
+ end
72
+
73
+ # Returns true/false depending on whether the command is configured properly.
74
+ def validate
75
+ @valid
76
+ end
77
+
78
+ # Returns a help message. Defaults to OptionParser#help which should be good.
79
+ def help
80
+ @opt.help
81
+ end
82
+
83
+ # Runs the command doing it's job. You should implement this otherwise it will
84
+ # throw a NotImplementedError as a reminder.
85
+ def run
86
+ raise NotImplementedError
87
+ end
88
+ end
89
+ end
@@ -1,194 +1,60 @@
1
1
  module GoldenBrindle
2
-
3
-
4
- def GoldenBrindle::send_signal(signal, pid_file)
5
- pid = open(pid_file).read.to_i
6
- print "Sending #{signal} to Unicorn at PID #{pid}..."
7
- begin
8
- Process.kill(signal, pid)
9
- rescue Errno::ESRCH
10
- puts "Process does not exist. Not running."
2
+
3
+ class << self
4
+ def send_signal(signal, pid_file)
5
+ pid = open(pid_file).read.to_i
6
+ print "Sending #{signal} to Unicorn at PID #{pid}..."
7
+ begin
8
+ Process.kill(signal, pid)
9
+ rescue Errno::ESRCH
10
+ puts "Process does not exist. Not running."
11
+ end
12
+ puts "Done."
11
13
  end
12
- puts "Done."
13
14
  end
14
-
15
- module Command
16
-
17
- module Base
18
-
19
- attr_reader :valid, :done_validating, :original_args
20
15
 
21
- # Called by the implemented command to set the options for that command.
22
- # Every option has a short and long version, a description, a variable to
23
- # set, and a default value. No exceptions.
24
- def options(opts)
25
- # process the given options array
26
- opts.each do |short, long, help, variable, default|
27
- self.instance_variable_set(variable, default)
28
- @opt.on(short, long, help) do |arg|
29
- self.instance_variable_set(variable, arg)
30
- end
31
- end
32
- end
16
+ # A Singleton class that manages all of the available commands
17
+ # and handles running them.
18
+ class Registry
33
19
 
34
- # Called by the subclass to setup the command and parse the argv arguments.
35
- # The call is destructive on argv since it uses the OptionParser#parse! function.
36
- def initialize(options={})
37
- argv = options[:argv] || []
38
- @opt = OptionParser.new
39
- @opt.banner = GoldenBrindle::Const::BANNER
40
- @valid = true
41
- # this is retarded, but it has to be done this way because -h and -v exit
42
- @done_validating = false
43
- @original_args = argv.dup
44
- configure
45
- # I need to add my own -h definition to prevent the -h by default from exiting.
46
- @opt.on_tail("-h", "--help", "Show this message") do
47
- @done_validating = true
48
- puts @opt
49
- end
20
+ class << self
50
21
 
51
- # I need to add my own -v definition to prevent the -v from exiting by default as well.
52
- @opt.on_tail("--version", "Show version") do
53
- @done_validating = true
54
- if VERSION
55
- puts "Version #{GoldenBrindle::Const::VERSION}"
56
- end
22
+ def constantize(camel_cased_word)
23
+ names = camel_cased_word.split('::')
24
+ names.shift if names.empty? || names.first.empty?
25
+ constant = Object
26
+ names.each do |name|
27
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
57
28
  end
58
- @opt.parse! argv
29
+ constant
59
30
  end
60
31
 
61
- def configure
62
- options []
63
- end
64
-
65
- def config_keys
66
- @config_keys ||=
67
- %w(address host port cwd log_file pid_file environment servers daemon debug config_script workers timeout user group prefix preload listen bundler)
68
- end
69
-
70
- def load_config
71
- settings = {}
72
- begin
73
- settings = YAML.load_file(@config_file)
74
- ensure
75
- STDERR.puts "** Loading settings from #{@config_file} (they override command line)." unless @daemon || settings[:daemon]
76
- end
77
-
78
- # Config file settings will override command line settings
79
- settings.each do |key, value|
80
- key = key.to_s
81
- if config_keys.include?(key)
82
- key = 'address' if key == 'host'
83
- self.instance_variable_set("@#{key}", value)
32
+ # Builds a list of possible commands from the Command derivates list
33
+ def commands
34
+ GoldenBrindle::Actions.constants.inject([]) do |memo, action|
35
+ constants = constantize("GoldenBrindle::Actions::#{action.to_s}").constants
36
+ if constants.empty?
37
+ memo << action.to_s.downcase
84
38
  else
85
- failure "Unknown configuration setting: #{key}"
86
- @valid = false
39
+ constants.each do |subaction|
40
+ memo << "#{action.to_s}::#{subaction.to_s}".downcase
41
+ end
87
42
  end
43
+ memo
88
44
  end
89
45
  end
90
46
 
91
- # Returns true/false depending on whether the command is configured properly.
92
- def validate
93
- @valid
94
- end
95
-
96
- # Returns a help message. Defaults to OptionParser#help which should be good.
97
- def help
98
- @opt.help
99
- end
100
-
101
- # Runs the command doing it's job. You should implement this otherwise it will
102
- # throw a NotImplementedError as a reminder.
103
- def run
104
- raise NotImplementedError
105
- end
106
-
107
- # Validates the given expression is true and prints the message if not, exiting.
108
- def valid?(exp, message)
109
- if !@done_validating && !exp
110
- failure message
111
- @valid = false
112
- @done_validating = true
113
- end
114
- end
115
-
116
- # Validates that a file exists and if not displays the message
117
- def valid_exists?(file, message)
118
- valid?(File.exist?(file), message)
119
- end
120
-
121
- # Validates that the file is a file and not a directory or something else.
122
- def valid_file?(file, message)
123
- valid?(File.file?(file), message)
124
- end
125
-
126
- # Validates that the given directory exists
127
- def valid_dir?(file, message)
128
- valid?(File.directory?(file), message)
129
- end
130
-
131
- def can_change_user?
132
- valid?(Process.euid.to_i == 0, "if you want to change workers UID/GID you must run script from root")
133
- end
134
-
135
- def valid_user?(user)
136
- valid?(@group, "You must also specify a group.")
137
- can_change_user?
138
- begin
139
- Etc.getpwnam(user)
140
- rescue
141
- failure "User does not exist: #{user}"
142
- @valid = false
143
- end
144
- end
145
-
146
- def valid_group?(group)
147
- valid?(@user, "You must also specify a user.")
148
- begin
149
- Etc.getgrnam(group)
150
- rescue
151
- failure "Group does not exist: #{group}"
152
- @valid = false
153
- end
154
- end
155
-
156
- # Just a simple method to display failure until something better is developed.
157
- def failure(message)
158
- STDERR.puts "!!! #{message}"
159
- end
160
-
161
- end
162
-
163
- # A Singleton class that manages all of the available commands
164
- # and handles running them.
165
- class Registry
166
- include Singleton
167
-
168
- # Builds a list of possible commands from the Command derivates list
169
- def commands
170
- pmgr = GemPlugin::Manager.instance
171
- list = pmgr.plugins["/commands"].keys
172
- list.sort
173
- end
174
-
175
47
  # Prints a list of available commands.
176
48
  def print_command_list
177
49
  puts "#{GoldenBrindle::Const::BANNER}\nAvailable commands are:\n\n"
178
-
179
- self.commands.each do |name|
180
- if /brindle::/ =~ name
181
- name = name[9 .. -1]
182
- end
183
-
184
- puts " - #{name[1 .. -1]}\n"
50
+ commands.each do |name|
51
+ puts " - #{name}\n"
185
52
  end
186
53
 
187
54
  puts "\nEach command takes -h as an option to get help."
188
55
 
189
56
  end
190
57
 
191
-
192
58
  # Runs the args against the first argument as the command name.
193
59
  # If it has any errors it returns a false, otherwise it return true.
194
60
  def run(args)
@@ -204,10 +70,9 @@ module GoldenBrindle
204
70
  end
205
71
 
206
72
  begin
207
- if ["start", "stop", "restart", "configure", "reload"].include? cmd_name
208
- cmd_name = "brindle::" + cmd_name
209
- end
210
- command = GemPlugin::Manager.instance.create("/commands/#{cmd_name}", :argv => args)
73
+ cmd_name = cmd_name.split("::").map{|x| x.capitalize}.join("::")
74
+ constant = constantize("GoldenBrindle::Actions::#{cmd_name}")
75
+ command = constant.new(args)
211
76
  rescue OptionParser::InvalidOption
212
77
  STDERR.puts "#$! for command '#{cmd_name}'"
213
78
  STDERR.puts "Try #{cmd_name} -h to get help."
@@ -233,7 +98,7 @@ module GoldenBrindle
233
98
  true
234
99
  end
235
100
  end
236
-
101
+
237
102
  end
238
-
103
+
239
104
  end
@@ -1,12 +1,12 @@
1
1
  module GoldenBrindle
2
-
3
2
  module Const
4
-
5
3
  # current version
6
- VERSION="0.2"
4
+ VERSION="0.3"
7
5
  # main banner
8
6
  BANNER = "Usage: golden_brindle <command> [options]"
9
-
7
+ # config options names
8
+ CONFIG_KEYS = %w(address host port cwd log_file pid_file environment servers daemon debug config_script workers timeout user group prefix preload listen bundler)
9
+ ANSI_RED = "\033[0;31m"
10
+ ANSI_RESET = "\033[0m"
10
11
  end
11
-
12
12
  end
@@ -1,5 +1,6 @@
1
- module Brindle
1
+ module GoldenBrindle
2
2
  module Hooks
3
+
3
4
  def collect_hooks
4
5
  [:after_fork, :after_reload, :before_fork, :before_exec].inject({}) do |memo, sym|
5
6
  memo[sym] = send(sym)
@@ -1,4 +1,4 @@
1
- module Brindle
1
+ module GoldenBrindle
2
2
  class RailsSupport
3
3
  class << self
4
4
 
@@ -68,7 +68,7 @@ module Brindle
68
68
  unless defined?(ActionDispatch::Static)
69
69
  use Rails::Rack::Static
70
70
  end
71
- run Brindle::RailsSupport.rails_dispatcher
71
+ run ::GoldenBrindle::RailsSupport.rails_dispatcher
72
72
  end
73
73
  end
74
74
  end.to_app
@@ -0,0 +1,56 @@
1
+ module GoldenBrindle
2
+ module Validations
3
+
4
+ # Validates the given expression is true and prints the message if not, exiting.
5
+ def valid?(exp, message)
6
+ if !exp
7
+ failure message
8
+ @valid = false
9
+ end
10
+ end
11
+
12
+ # Validates that a file exists and if not displays the message
13
+ def valid_exists?(file, message)
14
+ valid?(File.exist?(file), message)
15
+ end
16
+
17
+ # Validates that the file is a file and not a directory or something else.
18
+ def valid_file?(file, message)
19
+ valid?(::File.file?(file), message)
20
+ end
21
+
22
+ # Validates that the given directory exists
23
+ def valid_dir?(file, message)
24
+ valid?(::File.directory?(file), message)
25
+ end
26
+
27
+ def can_change_user?
28
+ valid?(::Process.euid.zero?, "if you want to change workers UID/GID you must run programm from root")
29
+ end
30
+
31
+ def valid_user?(user)
32
+ return unless can_change_user?
33
+ begin
34
+ ::Etc.getpwnam(user)
35
+ rescue
36
+ failure "User does not exist: #{user}"
37
+ @valid = false
38
+ end
39
+ end
40
+
41
+ def valid_group?(group)
42
+ begin
43
+ ::Etc.getgrnam(group)
44
+ rescue
45
+ failure "Group does not exist: #{group}"
46
+ @valid = false
47
+ end
48
+ end
49
+
50
+ # Just a simple method to display failure until something better is developed.
51
+ def failure(message)
52
+ STDERR.puts "#{::GoldenBrindle::Const::ANSI_RED}!!! * #{message}#{::GoldenBrindle::Const::ANSI_RESET}"
53
+ end
54
+
55
+ end
56
+ end