omnibus-ctl 0.3.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.
- checksums.yaml +7 -0
- data/README.md +85 -0
- data/bin/omnibus-ctl +33 -0
- data/lib/omnibus-ctl.rb +559 -0
- data/lib/omnibus-ctl/version.rb +5 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3f727fad81d619b5de76e830757918590df8b636
|
4
|
+
data.tar.gz: 2a606b930145058c04f31a36f14ff4f32f1d1449
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ed89feaa9a4cfedb22f06640efd44644f1908cc6c254ba19185e41e144d722006855cb57c451c86e293448a3269ecae36acf725948cab7f83539df0e01aec4f7
|
7
|
+
data.tar.gz: 4627bd21c3569788abdca489e4d94096d847861fbfee83f35eb9cbbaeb67e29c4859dd5e67507ad8e94fe9d4f849d4ccee3a805aac8ab9ff6830263b37c57a21
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
## omnibus-ctl
|
2
|
+
|
3
|
+
omnibus-ctl provides service control and configuration for omnibus packages.
|
4
|
+
|
5
|
+
Not much to see here yet.
|
6
|
+
|
7
|
+
### Run the Tests!
|
8
|
+
|
9
|
+
There are tests in this repo that should be run before merging to master in the `spec` directory.
|
10
|
+
|
11
|
+
To run them, first install rspec via bundler:
|
12
|
+
|
13
|
+
```
|
14
|
+
bundle install --binstubs
|
15
|
+
```
|
16
|
+
|
17
|
+
Then run the tests:
|
18
|
+
|
19
|
+
```
|
20
|
+
./bin/rspec spec/
|
21
|
+
```
|
22
|
+
|
23
|
+
### Framework API
|
24
|
+
|
25
|
+
There are two main functions you will use in your `*-ctl` project to add commands.
|
26
|
+
|
27
|
+
#### add_command_under_category(string, string, string, int, ruby_block)
|
28
|
+
|
29
|
+
This method will add a new command to your ctl under a category, useful for grouping similar commands together logically in help output.
|
30
|
+
|
31
|
+
Input arguments:
|
32
|
+
|
33
|
+
1. Name of the command.
|
34
|
+
2. Category of the command. It should be string consisting of only characters and "-". If the category does not exist, it will be added. Default categories are "general" and "service-management" (if the latter is enabled).
|
35
|
+
3. Description. This will be outputted below the command name when the help command is run.
|
36
|
+
4. Arity. TODO: Due to current bug, this must be 2, I believe. We should fix this.
|
37
|
+
5. Ruby block. Ruby code to be executed when your command is run (arguments to that command will be passed into the block).
|
38
|
+
|
39
|
+
#### add_command(string, string, int, ruby_block)
|
40
|
+
|
41
|
+
This method will add a new command to your ctl without a category. It will be displayed above all categories when the help command is called.
|
42
|
+
|
43
|
+
Input arguments are the same as `add_command_under_category` except 2 doesn't exist.
|
44
|
+
|
45
|
+
#### Sample Output
|
46
|
+
|
47
|
+
```
|
48
|
+
# sample-ctl help
|
49
|
+
/opt/opscode/embedded/bin/sample-ctl: command (subcommand)
|
50
|
+
command-without-category
|
51
|
+
Here is an insightful description for the above command, added via add_command.
|
52
|
+
another-command-without-category
|
53
|
+
Yet another description.
|
54
|
+
Some Category Of Commands:
|
55
|
+
command-with-category
|
56
|
+
Exciting description of command added via add_command_under_category.
|
57
|
+
better-command-with-category
|
58
|
+
You get the idea.
|
59
|
+
Another Category:
|
60
|
+
command-with-better-category
|
61
|
+
I'm not just going to copy-pasta above example descriptions.
|
62
|
+
better-command-with-better-category
|
63
|
+
I'm running out of ideas.
|
64
|
+
```
|
65
|
+
|
66
|
+
If you only use `add_command_under_category` to add your custom commands, everything will be outputted under a category.
|
67
|
+
|
68
|
+
### Licensing
|
69
|
+
|
70
|
+
See the LICENSE file for details.
|
71
|
+
|
72
|
+
Copyright: Copyright (c) 2012 Opscode, Inc.
|
73
|
+
License: Apache License, Version 2.0
|
74
|
+
|
75
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
76
|
+
you may not use this file except in compliance with the License.
|
77
|
+
You may obtain a copy of the License at
|
78
|
+
|
79
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
80
|
+
|
81
|
+
Unless required by applicable law or agreed to in writing, software
|
82
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
83
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
84
|
+
See the License for the specific language governing permissions and
|
85
|
+
limitations under the License.
|
data/bin/omnibus-ctl
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'omnibus-ctl'
|
21
|
+
|
22
|
+
# service name: ARGV[0]
|
23
|
+
# additional modules: ARGV[1]
|
24
|
+
# command: ARGV[2]
|
25
|
+
# service: ARGV[3]
|
26
|
+
# options: ARGV[4..]
|
27
|
+
|
28
|
+
ctl = Omnibus::Ctl.new(ARGV[0])
|
29
|
+
ctl.load_files(ARGV[1])
|
30
|
+
arguments = ARGV[2..-1] # Get the rest of the command line arguments
|
31
|
+
ctl.run(arguments)
|
32
|
+
exit 0
|
33
|
+
|
data/lib/omnibus-ctl.rb
ADDED
@@ -0,0 +1,559 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2012 Opscode, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require "omnibus-ctl/version"
|
19
|
+
require 'json'
|
20
|
+
require 'fileutils'
|
21
|
+
|
22
|
+
module Omnibus
|
23
|
+
class Ctl
|
24
|
+
|
25
|
+
File::umask(022)
|
26
|
+
|
27
|
+
SV_COMMAND_NAMES = %w[status up down once pause cont hup alarm interrupt quit
|
28
|
+
term kill start stop restart shutdown force-stop
|
29
|
+
force-reload force-restart force-shutdown check]
|
30
|
+
|
31
|
+
attr_accessor :name, :display_name, :log_exclude, :base_path, :sv_path,
|
32
|
+
:service_path, :etc_path, :data_path, :log_path, :command_map, :category_command_map,
|
33
|
+
:fh_output, :kill_users, :verbose, :log_path_exclude
|
34
|
+
|
35
|
+
def initialize(name, service_commands=true)
|
36
|
+
@name = name
|
37
|
+
@service_commands = service_commands
|
38
|
+
@display_name = name
|
39
|
+
@base_path = "/opt/#{name}"
|
40
|
+
@sv_path = File.join(@base_path, "sv")
|
41
|
+
@service_path = File.join(@base_path, "service")
|
42
|
+
@log_path = "/var/log/#{name}"
|
43
|
+
@data_path = "/var/opt/#{name}"
|
44
|
+
@etc_path = "/etc/#{name}"
|
45
|
+
@log_exclude = '(config|lock|@|gzip|tgz|gz)'
|
46
|
+
@log_path_exclude = ['*/sasl/*']
|
47
|
+
@fh_output = STDOUT
|
48
|
+
@kill_users = []
|
49
|
+
@verbose = false
|
50
|
+
# backwards compat command map that does not have categories
|
51
|
+
@command_map = { }
|
52
|
+
|
53
|
+
# categoired commands that we want by default
|
54
|
+
@category_command_map = {
|
55
|
+
"general" => {
|
56
|
+
"show-config" => {
|
57
|
+
:desc => "Show the configuration that would be generated by reconfigure.",
|
58
|
+
:arity => 1
|
59
|
+
},
|
60
|
+
"reconfigure" => {
|
61
|
+
:desc => "Reconfigure the application.",
|
62
|
+
:arity => 1
|
63
|
+
},
|
64
|
+
"cleanse" => {
|
65
|
+
:desc => "Delete *all* #{display_name} data, and start from scratch.",
|
66
|
+
:arity => 2
|
67
|
+
},
|
68
|
+
"uninstall" => {
|
69
|
+
:arity => 1,
|
70
|
+
:desc => "Kill all processes and uninstall the process supervisor (data will be preserved)."
|
71
|
+
},
|
72
|
+
"help" => {
|
73
|
+
:arity => 1,
|
74
|
+
:desc => "Print this help message."
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
service_command_map = {
|
79
|
+
"service-management" => {
|
80
|
+
"service-list" => {
|
81
|
+
:arity => 1,
|
82
|
+
:desc => "List all the services (enabled services appear with a *.)"
|
83
|
+
},
|
84
|
+
"status" => {
|
85
|
+
:desc => "Show the status of all the services.",
|
86
|
+
:arity => 2
|
87
|
+
},
|
88
|
+
"tail" => {
|
89
|
+
:desc => "Watch the service logs of all enabled services.",
|
90
|
+
:arity => 2
|
91
|
+
},
|
92
|
+
"start" => {
|
93
|
+
:desc => "Start services if they are down, and restart them if they stop.",
|
94
|
+
:arity => 2
|
95
|
+
},
|
96
|
+
"stop" => {
|
97
|
+
:desc => "Stop the services, and do not restart them.",
|
98
|
+
:arity => 2
|
99
|
+
},
|
100
|
+
"restart" => {
|
101
|
+
:desc => "Stop the services if they are running, then start them again.",
|
102
|
+
:arity => 2
|
103
|
+
},
|
104
|
+
"once" => {
|
105
|
+
:desc => "Start the services if they are down. Do not restart them if they stop.",
|
106
|
+
:arity => 2
|
107
|
+
},
|
108
|
+
"hup" => {
|
109
|
+
:desc => "Send the services a HUP.",
|
110
|
+
:arity => 2
|
111
|
+
},
|
112
|
+
"term" => {
|
113
|
+
:desc => "Send the services a TERM.",
|
114
|
+
:arity => 2
|
115
|
+
},
|
116
|
+
"int" => {
|
117
|
+
:desc => "Send the services an INT.",
|
118
|
+
:arity => 2
|
119
|
+
},
|
120
|
+
"kill" => {
|
121
|
+
:desc => "Send the services a KILL.",
|
122
|
+
:arity => 2
|
123
|
+
},
|
124
|
+
"graceful-kill" => {
|
125
|
+
:desc => "Attempt a graceful stop, then SIGKILL the entire process group.",
|
126
|
+
:arity => 2
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
@category_command_map.merge!(service_command_map) if service_commands?
|
131
|
+
end
|
132
|
+
|
133
|
+
SV_COMMAND_NAMES.each do |sv_cmd|
|
134
|
+
method_name = sv_cmd.gsub(/-/, "_")
|
135
|
+
Omnibus::Ctl.class_eval <<-EOH
|
136
|
+
def #{method_name}(*args)
|
137
|
+
run_sv_command(*args)
|
138
|
+
end
|
139
|
+
EOH
|
140
|
+
end
|
141
|
+
|
142
|
+
# merges category_command_map and command_map,
|
143
|
+
# removing categories
|
144
|
+
def get_all_commands_hash
|
145
|
+
without_categories = {}
|
146
|
+
category_command_map.each do |category, commands|
|
147
|
+
without_categories.merge!(commands)
|
148
|
+
end
|
149
|
+
command_map.merge(without_categories)
|
150
|
+
end
|
151
|
+
|
152
|
+
def service_commands?
|
153
|
+
@service_commands
|
154
|
+
end
|
155
|
+
|
156
|
+
def load_files(path)
|
157
|
+
Dir["#{path}/*.rb"].each do |file|
|
158
|
+
eval(IO.read(file))
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def add_command(name, description, arity=1, &block)
|
163
|
+
@command_map[name] = { :desc => description, :arity => arity }
|
164
|
+
metaclass = class << self; self; end
|
165
|
+
# Ruby does not like dashes in method names
|
166
|
+
method_name = name.gsub(/-/, "_")
|
167
|
+
metaclass.send(:define_method, method_name.to_sym) { |*args| block.call(*args) }
|
168
|
+
end
|
169
|
+
|
170
|
+
def add_command_under_category(name, category, description, arity=1, &block)
|
171
|
+
# add new category if it doesn't exist
|
172
|
+
@category_command_map[category] = {} unless @category_command_map.has_key?(category)
|
173
|
+
@category_command_map[category][name] = { :desc => description, :arity => arity }
|
174
|
+
metaclass = class << self; self; end
|
175
|
+
# Ruby does not like dashes in method names
|
176
|
+
method_name = name.gsub(/-/, "_")
|
177
|
+
metaclass.send(:define_method, method_name.to_sym) { |*args| block.call(*args) }
|
178
|
+
end
|
179
|
+
|
180
|
+
def exit!(error_code)
|
181
|
+
exit error_code
|
182
|
+
end
|
183
|
+
|
184
|
+
def log(msg)
|
185
|
+
fh_output.puts msg
|
186
|
+
end
|
187
|
+
|
188
|
+
def get_pgrp_from_pid(pid)
|
189
|
+
ps=`which ps`.chomp
|
190
|
+
`#{ps} -p #{pid} -o pgrp=`.chomp
|
191
|
+
end
|
192
|
+
|
193
|
+
def get_pids_from_pgrp(pgrp)
|
194
|
+
pgrep=`which pgrep`.chomp
|
195
|
+
`#{pgrep} -g #{pgrp}`.split(/\n/).join(" ")
|
196
|
+
end
|
197
|
+
|
198
|
+
def sigkill_pgrp(pgrp)
|
199
|
+
pkill=`which pkill`.chomp
|
200
|
+
run_command("#{pkill} -9 -g #{pgrp}")
|
201
|
+
end
|
202
|
+
|
203
|
+
def run_command(command)
|
204
|
+
system(command)
|
205
|
+
$?
|
206
|
+
end
|
207
|
+
|
208
|
+
def service_list(*args)
|
209
|
+
get_all_services.each do |service_name|
|
210
|
+
print "#{service_name}"
|
211
|
+
print "*" if service_enabled?(service_name)
|
212
|
+
print "\n"
|
213
|
+
end
|
214
|
+
exit! 0
|
215
|
+
end
|
216
|
+
|
217
|
+
def cleanup_procs_and_nuke(filestr)
|
218
|
+
begin
|
219
|
+
run_sv_command("stop")
|
220
|
+
rescue SystemExit
|
221
|
+
end
|
222
|
+
|
223
|
+
FileUtils.rm_f("/etc/init/#{name}-runsvdir.conf") if File.exists?("/etc/init/#{name}-runsvdir.conf")
|
224
|
+
run_command("egrep -v '#{base_path}/embedded/bin/runsvdir-start' /etc/inittab > /etc/inittab.new && mv /etc/inittab.new /etc/inittab") if File.exists?("/etc/inittab")
|
225
|
+
run_command("kill -1 1")
|
226
|
+
|
227
|
+
backup_dir = Time.now.strftime("/root/#{name}-cleanse-%FT%R")
|
228
|
+
FileUtils.mkdir_p("/root") unless File.exists?("/root")
|
229
|
+
FileUtils.rm_rf(backup_dir)
|
230
|
+
FileUtils.cp_r(etc_path, backup_dir) if File.exists?(etc_path)
|
231
|
+
run_command("rm -rf #{filestr}")
|
232
|
+
|
233
|
+
begin
|
234
|
+
graceful_kill
|
235
|
+
rescue SystemExit
|
236
|
+
end
|
237
|
+
|
238
|
+
run_command("pkill -HUP -u #{kill_users.join(',')}") if kill_users.length > 0
|
239
|
+
run_command("pkill -HUP -f 'runsvdir -P #{service_path}'")
|
240
|
+
sleep 3
|
241
|
+
run_command("pkill -TERM -u #{kill_users.join(',')}") if kill_users.length > 0
|
242
|
+
run_command("pkill -TERM -f 'runsvdir -P #{service_path}'")
|
243
|
+
sleep 3
|
244
|
+
run_command("pkill -KILL -u #{kill_users.join(',')}") if kill_users.length > 0
|
245
|
+
run_command("pkill -KILL -f 'runsvdir -P #{service_path}'")
|
246
|
+
|
247
|
+
get_all_services.each do |die_daemon_die|
|
248
|
+
run_command("pkill -KILL -f 'runsv #{die_daemon_die}'")
|
249
|
+
end
|
250
|
+
|
251
|
+
log "Your config files have been backed up to #{backup_dir}."
|
252
|
+
exit! 0
|
253
|
+
end
|
254
|
+
|
255
|
+
def uninstall(*args)
|
256
|
+
cleanup_procs_and_nuke("/tmp/opt")
|
257
|
+
end
|
258
|
+
|
259
|
+
def cleanse(*args)
|
260
|
+
log "This will delete *all* configuration, log, and variable data associated with this application.\n\n*** You have 60 seconds to hit CTRL-C ***\n\n"
|
261
|
+
unless args[1] == "yes"
|
262
|
+
sleep 60
|
263
|
+
end
|
264
|
+
cleanup_procs_and_nuke("#{service_path}/* /tmp/opt #{data_path} #{etc_path} #{log_path}")
|
265
|
+
end
|
266
|
+
|
267
|
+
def get_all_services_files
|
268
|
+
Dir[File.join(sv_path, '*')]
|
269
|
+
end
|
270
|
+
|
271
|
+
def get_all_services
|
272
|
+
get_all_services_files.map { |f| File.basename(f) }.sort
|
273
|
+
end
|
274
|
+
|
275
|
+
def service_enabled?(service_name)
|
276
|
+
File.symlink?("#{service_path}/#{service_name}")
|
277
|
+
end
|
278
|
+
|
279
|
+
def run_sv_command(sv_cmd, service=nil)
|
280
|
+
exit_status = 0
|
281
|
+
if service
|
282
|
+
exit_status += run_sv_command_for_service(sv_cmd, service)
|
283
|
+
else
|
284
|
+
get_all_services.each do |service_name|
|
285
|
+
exit_status += run_sv_command_for_service(sv_cmd, service_name) if global_service_command_permitted(sv_cmd, service_name)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
exit! exit_status
|
289
|
+
end
|
290
|
+
|
291
|
+
# run an sv command for a specific service name
|
292
|
+
def run_sv_command_for_service(sv_cmd, service_name)
|
293
|
+
if service_enabled?(service_name)
|
294
|
+
status = run_command("#{base_path}/init/#{service_name} #{sv_cmd}")
|
295
|
+
return status.exitstatus
|
296
|
+
else
|
297
|
+
log "#{service_name} disabled" if sv_cmd == "status" && verbose
|
298
|
+
return 0
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# if we're running a global service command (like p-c-c status)
|
303
|
+
# across all of the services, there are certain cases where we
|
304
|
+
# want to prevent services files that exist in the service
|
305
|
+
# directory from being activated. This method is the logic that
|
306
|
+
# blocks those services
|
307
|
+
def global_service_command_permitted(sv_cmd, service_name)
|
308
|
+
# For services that have been removed, we only want to
|
309
|
+
# them to respond to the stop command. They should not show
|
310
|
+
# up in status, and they should not be started.
|
311
|
+
if removed_services.include?(service_name)
|
312
|
+
return sv_cmd == "stop"
|
313
|
+
end
|
314
|
+
|
315
|
+
# For keepalived, we only want it to respond to the status
|
316
|
+
# command when running global service commands like p-c-c start
|
317
|
+
# and p-c-c stop
|
318
|
+
if service_name == "keepalived"
|
319
|
+
return sv_cmd == "status"
|
320
|
+
end
|
321
|
+
|
322
|
+
# If c-s-c status is called, check to see if the service
|
323
|
+
# is hidden supposed to be hidden from the status results
|
324
|
+
# (mover for example should be hidden).
|
325
|
+
if sv_cmd == "status"
|
326
|
+
return !(hidden_services.include?(service_name))
|
327
|
+
end
|
328
|
+
|
329
|
+
# All other services respond normally to p-c-c * commands
|
330
|
+
return true
|
331
|
+
end
|
332
|
+
|
333
|
+
# removed services are configured via the attributes file in
|
334
|
+
# the main omnibus cookbook
|
335
|
+
def removed_services
|
336
|
+
# in the case that there is no running_config (the config file does
|
337
|
+
# not exist), we know that this will be a new server, and we don't
|
338
|
+
# have to worry about pre-upgrade services hanging around. We can safely
|
339
|
+
# return an empty array when running_config is nil
|
340
|
+
if (cfg = running_config)
|
341
|
+
key = package_name.gsub(/-/, '_')
|
342
|
+
cfg[key]["removed_services"] || []
|
343
|
+
else
|
344
|
+
[]
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# hidden services are configured via the attributes file in
|
349
|
+
# the main omnibus cookbook
|
350
|
+
#
|
351
|
+
# hidden services are services that we do not want to show up in
|
352
|
+
# c-s-c status.
|
353
|
+
def hidden_services
|
354
|
+
# in the case that there is no running_config (the config file does
|
355
|
+
# not exist), we don't want to return nil, just return an empty array.
|
356
|
+
# worse result with doing that is services that we don't want to show up in
|
357
|
+
# c-s-c status will show up.
|
358
|
+
if (cfg = running_config)
|
359
|
+
key = package_name.gsub(/-/, '_')
|
360
|
+
cfg[key]["hidden_services"] || []
|
361
|
+
else
|
362
|
+
[]
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
# translate the name from the config to the package name.
|
367
|
+
# this is a special case for the private-chef package because
|
368
|
+
# it is configured to use the name and directory structure of
|
369
|
+
# 'opscode', not 'private-chef'
|
370
|
+
def package_name
|
371
|
+
case @name
|
372
|
+
when "opscode"
|
373
|
+
"private-chef"
|
374
|
+
else
|
375
|
+
@name
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
# returns nil when chef-server-running.json does not exist
|
380
|
+
def running_config
|
381
|
+
@running_config ||= begin
|
382
|
+
if File.exists?("#{etc_path}/chef-server-running.json")
|
383
|
+
JSON.parse(File.read("#{etc_path}/chef-server-running.json"))
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def show_config(*args)
|
389
|
+
status = run_command("#{base_path}/embedded/bin/chef-client -z -c #{base_path}/embedded/cookbooks/solo.rb -j #{base_path}/embedded/cookbooks/show-config.json -l fatal")
|
390
|
+
if status.success?
|
391
|
+
exit! 0
|
392
|
+
else
|
393
|
+
exit! 1
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
def reconfigure(exit_on_success=true)
|
398
|
+
status = run_command("#{base_path}/embedded/bin/chef-client -z -c #{base_path}/embedded/cookbooks/solo.rb -j #{base_path}/embedded/cookbooks/dna.json")
|
399
|
+
if status.success?
|
400
|
+
log "#{display_name} Reconfigured!"
|
401
|
+
exit! 0 if exit_on_success
|
402
|
+
else
|
403
|
+
exit! 1
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def tail(*args)
|
408
|
+
# find /var/log -type f -not -path '*/sasl/*' | grep -E -v '(lock|@|tgz|gzip)' | xargs tail --follow=name --retry
|
409
|
+
command = "find #{log_path}"
|
410
|
+
command << "/#{args[1]}" if args[1]
|
411
|
+
command << ' -type f'
|
412
|
+
command << log_path_exclude.map { |path| " -not -path #{path}" }.join(' ')
|
413
|
+
command << " | grep -E -v '#{log_exclude}' | xargs tail --follow=name --retry"
|
414
|
+
|
415
|
+
system(command)
|
416
|
+
end
|
417
|
+
|
418
|
+
def is_integer?(string)
|
419
|
+
return true if Integer(string) rescue false
|
420
|
+
end
|
421
|
+
|
422
|
+
def graceful_kill(*args)
|
423
|
+
service = args[1]
|
424
|
+
exit_status = 0
|
425
|
+
get_all_services.each do |service_name|
|
426
|
+
next if !service.nil? && service_name != service
|
427
|
+
if service_enabled?(service_name)
|
428
|
+
pidfile="#{sv_path}/#{service_name}/supervise/pid"
|
429
|
+
pid=File.read(pidfile).chomp if File.exists?(pidfile)
|
430
|
+
if pid.nil? || !is_integer?(pid)
|
431
|
+
log "could not find #{service_name} runit pidfile (service already stopped?), cannot attempt SIGKILL..."
|
432
|
+
status = run_command("#{base_path}/init/#{service_name} stop")
|
433
|
+
exit_status = status.exitstatus if exit_status == 0 && !status.success?
|
434
|
+
next
|
435
|
+
end
|
436
|
+
pgrp=get_pgrp_from_pid(pid)
|
437
|
+
if pgrp.nil? || !is_integer?(pgrp)
|
438
|
+
log "could not find pgrp of pid #{pid} (not running?), cannot attempt SIGKILL..."
|
439
|
+
status = run_command("#{base_path}/init/#{service_name} stop")
|
440
|
+
exit_status = status.exitstatus if exit_status == 0 && !status.success?
|
441
|
+
next
|
442
|
+
end
|
443
|
+
run_command("#{base_path}/init/#{service_name} stop")
|
444
|
+
pids=get_pids_from_pgrp(pgrp)
|
445
|
+
if !pids.empty?
|
446
|
+
log "found stuck pids still running in process group: #{pids}, sending SIGKILL" unless pids.empty?
|
447
|
+
sigkill_pgrp(pgrp)
|
448
|
+
end
|
449
|
+
else
|
450
|
+
log "#{service_name} disabled, not stopping"
|
451
|
+
exit_status = 1
|
452
|
+
end
|
453
|
+
end
|
454
|
+
exit! exit_status
|
455
|
+
end
|
456
|
+
|
457
|
+
def help(*args)
|
458
|
+
log "#{$0}: command (subcommand)\n"
|
459
|
+
command_map.keys.sort.each do |command|
|
460
|
+
log command
|
461
|
+
log " #{command_map[command][:desc]}"
|
462
|
+
end
|
463
|
+
category_command_map.each do |category, commands|
|
464
|
+
# Remove "-" and replace with spaces in category and capalize for output
|
465
|
+
category_string = category.gsub("-", " ").split.map(&:capitalize).join(' ')
|
466
|
+
log "#{category_string} Commands:\n"
|
467
|
+
|
468
|
+
# Print each command in this category
|
469
|
+
commands.keys.sort.each do |command|
|
470
|
+
log " #{command}"
|
471
|
+
log " #{commands[command][:desc]}"
|
472
|
+
end
|
473
|
+
end
|
474
|
+
exit! 1
|
475
|
+
end
|
476
|
+
|
477
|
+
# Set options. Silently ignore bad options.
|
478
|
+
# This allows the test subcommand to pass on pedant options
|
479
|
+
def parse_options!(args)
|
480
|
+
args.each do |option|
|
481
|
+
case option
|
482
|
+
when "--verbose", "-v"
|
483
|
+
@verbose = true
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
# If it begins with a '-', it is an option.
|
489
|
+
def is_option?(arg)
|
490
|
+
arg && arg[0] == '-'
|
491
|
+
end
|
492
|
+
|
493
|
+
# retrieves the commmand from either the command_map
|
494
|
+
# or the category_command_map, if the command is not found
|
495
|
+
# return nil
|
496
|
+
def retrieve_command(command_to_run)
|
497
|
+
if command_map.has_key?(command_to_run)
|
498
|
+
command_map[command_to_run]
|
499
|
+
else
|
500
|
+
command = nil
|
501
|
+
category_command_map.each do |category, commands|
|
502
|
+
command = commands[command_to_run] if commands.has_key?(command_to_run)
|
503
|
+
end
|
504
|
+
# return the command, or nil if it wasn't found
|
505
|
+
command
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
def run(args)
|
510
|
+
# Ensure Omnibus related binaries are in the PATH
|
511
|
+
ENV["PATH"] = [File.join(base_path, "bin"),
|
512
|
+
File.join(base_path, "embedded","bin"),
|
513
|
+
ENV['PATH']].join(":")
|
514
|
+
|
515
|
+
command_to_run = args[0]
|
516
|
+
|
517
|
+
# This piece of code checks if the argument is an option. If it is,
|
518
|
+
# then it sets service to nil and adds the argument into the options
|
519
|
+
# argument. This is ugly. A better solution is having a proper parser.
|
520
|
+
# But if we are going to implement a proper parser, we might as well
|
521
|
+
# port this to Thor rather than reinventing Thor. For now, this preserves
|
522
|
+
# the behavior to complain and exit with an error if one attempts to invoke
|
523
|
+
# a pcc command that does not accept an argument. Like "help".
|
524
|
+
options = args[2..-1] || []
|
525
|
+
if is_option?(args[1])
|
526
|
+
options.unshift(args[1])
|
527
|
+
service = nil
|
528
|
+
else
|
529
|
+
service = args[1]
|
530
|
+
end
|
531
|
+
|
532
|
+
# returns either hash content of comamnd or nil
|
533
|
+
command = retrieve_command(command_to_run)
|
534
|
+
|
535
|
+
if command.nil?
|
536
|
+
log "I don't know that command."
|
537
|
+
if args.length == 2
|
538
|
+
log "Did you mean: #{$0} #{service} #{command_to_run}?"
|
539
|
+
end
|
540
|
+
help
|
541
|
+
end
|
542
|
+
|
543
|
+
if args.length > 1 && command[:arity] != 2
|
544
|
+
log "The command #{command_to_run} does not accept any arguments"
|
545
|
+
exit! 2
|
546
|
+
end
|
547
|
+
|
548
|
+
parse_options! options
|
549
|
+
|
550
|
+
method_to_call = command_to_run.gsub(/-/, '_')
|
551
|
+
# Filter args to just command and service. If you are loading
|
552
|
+
# custom commands and need access to the command line argument,
|
553
|
+
# use ARGV directly.
|
554
|
+
actual_args = [command_to_run, service].reject(&:nil?)
|
555
|
+
self.send(method_to_call.to_sym, *actual_args)
|
556
|
+
end
|
557
|
+
|
558
|
+
end
|
559
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omnibus-ctl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Opscode, Inc.
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec_junit_formatter
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Provides command line control for omnibus pakcages, rarely used as a
|
42
|
+
gem
|
43
|
+
email:
|
44
|
+
- legal@opscode.com
|
45
|
+
executables:
|
46
|
+
- omnibus-ctl
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- README.md
|
51
|
+
- bin/omnibus-ctl
|
52
|
+
- lib/omnibus-ctl.rb
|
53
|
+
- lib/omnibus-ctl/version.rb
|
54
|
+
homepage: http://github.com/opscode/omnibus-ctl
|
55
|
+
licenses: []
|
56
|
+
metadata: {}
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 2.2.2
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
76
|
+
summary: Provides command line control for omnibus packages
|
77
|
+
test_files: []
|
78
|
+
has_rdoc:
|