golden_brindle 0.2 → 0.3
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.
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +38 -0
- data/Rakefile +33 -46
- data/bin/golden_brindle +1 -4
- data/golden_brindle.gemspec +33 -15
- data/lib/golden_brindle/actions/cluster.rb +50 -0
- data/lib/golden_brindle/actions/configure.rb +63 -0
- data/lib/golden_brindle/actions/restart.rb +40 -0
- data/lib/golden_brindle/actions/start.rb +131 -0
- data/lib/golden_brindle/actions/stop.rb +45 -0
- data/lib/golden_brindle/base.rb +89 -0
- data/lib/golden_brindle/command.rb +39 -174
- data/lib/golden_brindle/const.rb +5 -5
- data/lib/golden_brindle/hooks.rb +2 -1
- data/lib/golden_brindle/rails_support.rb +2 -2
- data/lib/golden_brindle/validations.rb +56 -0
- data/lib/golden_brindle.rb +6 -7
- data/spec/golden_brindle_spec.rb +23 -0
- data/spec/spec_helper.rb +12 -0
- metadata +70 -18
- data/lib/golden_brindle/cluster.rb +0 -53
- data/lib/golden_brindle/configure.rb +0 -63
- data/lib/golden_brindle/restart.rb +0 -40
- data/lib/golden_brindle/start.rb +0 -130
- data/lib/golden_brindle/stop.rb +0 -45
- data/test/helper.rb +0 -10
- data/test/test_golden_brindle.rb +0 -7
@@ -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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
29
|
+
constant
|
59
30
|
end
|
60
31
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|
86
|
-
|
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
|
-
|
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
|
-
|
208
|
-
|
209
|
-
|
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
|
data/lib/golden_brindle/const.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
module GoldenBrindle
|
2
|
-
|
3
2
|
module Const
|
4
|
-
|
5
3
|
# current version
|
6
|
-
VERSION="0.
|
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
|
data/lib/golden_brindle/hooks.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
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
|
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
|