omnibus-ctl 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
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
+
@@ -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
@@ -0,0 +1,5 @@
1
+ module Omnibus
2
+ class Ctl
3
+ VERSION = "0.3.3"
4
+ end
5
+ 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: