omnibus-ctl 0.3.6 → 0.5.0
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 +4 -4
- data/README.md +24 -11
- data/lib/omnibus-ctl/version.rb +1 -1
- data/lib/omnibus-ctl.rb +387 -75
- metadata +19 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba3442fde147f0b637bb2ce3dfe8f61952c00c5d
|
4
|
+
data.tar.gz: 69b92b796d3f0afbbfe13bc429fcc09cb8ad8043
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d184d6b71831ed278e907ee83d3b73d26876dbcd4d1aae0a0ed5ac6b7e8990629e6a362b31132776878f6cf3ac0964e093c72bc098c385b9a746f100c1c2f34
|
7
|
+
data.tar.gz: e2b700aa51a77c273846a1669ebbbda5c9a5c7bb520e277c1199dbabe66edbe248094b6614bac68a5679d5738e293feb26ea4f1265541b860d1bc782c84d8e46
|
data/README.md
CHANGED
@@ -1,32 +1,32 @@
|
|
1
|
-
|
1
|
+
# omnibus-ctl
|
2
2
|
|
3
3
|
[](https://travis-ci.org/chef/omnibus-ctl)
|
4
4
|
|
5
5
|
omnibus-ctl provides service control and configuration for omnibus packages.
|
6
6
|
|
7
|
-
|
7
|
+
For an introduction, please see this blog post [Omnibus-ctl: What is it and what can it do for you?](https://www.chef.io/blog/2015/05/26/omnibus-ctl-what-is-it-and-what-can-it-do-for-you/).
|
8
8
|
|
9
|
-
|
9
|
+
## Run the Tests!
|
10
10
|
|
11
11
|
There are tests in this repo that should be run before merging to master in the `spec` directory.
|
12
12
|
|
13
13
|
To run them, first install rspec via bundler:
|
14
14
|
|
15
15
|
```
|
16
|
-
bundle install
|
16
|
+
bundle install
|
17
17
|
```
|
18
18
|
|
19
19
|
Then run the tests:
|
20
20
|
|
21
21
|
```
|
22
|
-
|
22
|
+
bin/rspec
|
23
23
|
```
|
24
24
|
|
25
|
-
|
25
|
+
## Framework API
|
26
26
|
|
27
27
|
There are two main functions you will use in your `*-ctl` project to add commands.
|
28
28
|
|
29
|
-
|
29
|
+
### add_command_under_category(string, string, string, int, ruby_block)
|
30
30
|
|
31
31
|
This method will add a new command to your ctl under a category, useful for grouping similar commands together logically in help output.
|
32
32
|
|
@@ -38,13 +38,13 @@ Input arguments:
|
|
38
38
|
4. Arity. TODO: Due to current bug, this must be 2, I believe. We should fix this.
|
39
39
|
5. Ruby block. Ruby code to be executed when your command is run (arguments to that command will be passed into the block).
|
40
40
|
|
41
|
-
|
41
|
+
### add_command(string, string, int, ruby_block)
|
42
42
|
|
43
43
|
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.
|
44
44
|
|
45
45
|
Input arguments are the same as `add_command_under_category` except 2 doesn't exist.
|
46
46
|
|
47
|
-
|
47
|
+
### Sample Output
|
48
48
|
|
49
49
|
```
|
50
50
|
# sample-ctl help
|
@@ -67,11 +67,24 @@ Another Category:
|
|
67
67
|
|
68
68
|
If you only use `add_command_under_category` to add your custom commands, everything will be outputted under a category.
|
69
69
|
|
70
|
-
|
70
|
+
## Releasing
|
71
|
+
|
72
|
+
*NOTE: Versions prior to 0.3.6 do not use a "v" prefix for their tags. Current
|
73
|
+
versions do.*
|
74
|
+
|
75
|
+
* Update the version in lib/omnibus-ctl/version.rb.
|
76
|
+
* Update the [Change log](CHANGELOG.md).
|
77
|
+
* Commit those changes.
|
78
|
+
* Make sure you are an owner of the
|
79
|
+
[omnibus-ctl gem on RubyGems.org](https://rubygems.org/gems/omnibus-ctl). If
|
80
|
+
you aren't, contact one of the owners to be added.
|
81
|
+
* `rake release`. This will tag the version, push it to GitHub and RubyGems.
|
82
|
+
|
83
|
+
## License
|
71
84
|
|
72
85
|
See the LICENSE file for details.
|
73
86
|
|
74
|
-
Copyright: Copyright (c) 2012
|
87
|
+
Copyright: Copyright (c) 2012-2015 Chef Software, Inc.
|
75
88
|
License: Apache License, Version 2.0
|
76
89
|
|
77
90
|
Licensed under the Apache License, Version 2.0 (the "License");
|
data/lib/omnibus-ctl/version.rb
CHANGED
data/lib/omnibus-ctl.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2012 Opscode, Inc.
|
1
|
+
# Copyright (c) 2012-2015 Chef Software, Inc.
|
3
2
|
# License:: Apache License, Version 2.0
|
4
3
|
#
|
5
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -19,6 +18,10 @@ require "omnibus-ctl/version"
|
|
19
18
|
require 'json'
|
20
19
|
require 'fileutils'
|
21
20
|
|
21
|
+
# For license checks
|
22
|
+
require 'io/console'
|
23
|
+
require 'io/wait'
|
24
|
+
|
22
25
|
module Omnibus
|
23
26
|
class Ctl
|
24
27
|
|
@@ -26,16 +29,19 @@ module Omnibus
|
|
26
29
|
|
27
30
|
SV_COMMAND_NAMES = %w[status up down once pause cont hup alarm interrupt quit
|
28
31
|
term kill start stop restart shutdown force-stop
|
29
|
-
force-reload force-restart force-shutdown check]
|
32
|
+
force-reload force-restart force-shutdown check usr1 usr2]
|
30
33
|
|
31
34
|
attr_accessor :name, :display_name, :log_exclude, :base_path, :sv_path,
|
32
35
|
:service_path, :etc_path, :data_path, :log_path, :command_map, :category_command_map,
|
33
36
|
:fh_output, :kill_users, :verbose, :log_path_exclude
|
34
37
|
|
35
|
-
|
38
|
+
attr_reader :backup_dir, :exe_name
|
39
|
+
|
40
|
+
|
41
|
+
def initialize(name, merge_service_commands=true, disp_name = nil)
|
36
42
|
@name = name
|
37
|
-
@service_commands =
|
38
|
-
@display_name = name
|
43
|
+
@service_commands = merge_service_commands
|
44
|
+
@display_name = disp_name || name
|
39
45
|
@base_path = "/opt/#{name}"
|
40
46
|
@sv_path = File.join(@base_path, "sv")
|
41
47
|
@service_path = File.join(@base_path, "service")
|
@@ -47,6 +53,10 @@ module Omnibus
|
|
47
53
|
@fh_output = STDOUT
|
48
54
|
@kill_users = []
|
49
55
|
@verbose = false
|
56
|
+
@quiet = false
|
57
|
+
@exe_name = File.basename($0)
|
58
|
+
@force_exit = false
|
59
|
+
|
50
60
|
# backwards compat command map that does not have categories
|
51
61
|
@command_map = { }
|
52
62
|
|
@@ -59,7 +69,7 @@ module Omnibus
|
|
59
69
|
},
|
60
70
|
"reconfigure" => {
|
61
71
|
:desc => "Reconfigure the application.",
|
62
|
-
:arity =>
|
72
|
+
:arity => 2
|
63
73
|
},
|
64
74
|
"cleanse" => {
|
65
75
|
:desc => "Delete *all* #{display_name} data, and start from scratch.",
|
@@ -124,19 +134,31 @@ module Omnibus
|
|
124
134
|
"graceful-kill" => {
|
125
135
|
:desc => "Attempt a graceful stop, then SIGKILL the entire process group.",
|
126
136
|
:arity => 2
|
137
|
+
},
|
138
|
+
"usr1" => {
|
139
|
+
:desc => "Send the services a USR1.",
|
140
|
+
:arity => 2
|
141
|
+
},
|
142
|
+
"usr2" => {
|
143
|
+
:desc => "Send the services a USR2.",
|
144
|
+
:arity => 2
|
127
145
|
}
|
128
146
|
}
|
129
147
|
}
|
130
148
|
@category_command_map.merge!(service_command_map) if service_commands?
|
131
149
|
end
|
132
150
|
|
151
|
+
def self.to_method_name(name)
|
152
|
+
name.gsub(/-/, '_').to_sym
|
153
|
+
end
|
154
|
+
def to_method_name(name)
|
155
|
+
Ctl.to_method_name(name)
|
156
|
+
end
|
157
|
+
|
133
158
|
SV_COMMAND_NAMES.each do |sv_cmd|
|
134
|
-
|
135
|
-
Omnibus::Ctl.class_eval <<-EOH
|
136
|
-
def #{method_name}(*args)
|
159
|
+
define_method to_method_name(sv_cmd) do |*args|
|
137
160
|
run_sv_command(*args)
|
138
161
|
end
|
139
|
-
EOH
|
140
162
|
end
|
141
163
|
|
142
164
|
# merges category_command_map and command_map,
|
@@ -160,15 +182,15 @@ module Omnibus
|
|
160
182
|
end
|
161
183
|
|
162
184
|
def load_file(filepath)
|
163
|
-
eval(IO.read(filepath))
|
185
|
+
eval(IO.read(filepath), nil, filepath, 1)
|
164
186
|
end
|
165
187
|
|
166
188
|
def add_command(name, description, arity=1, &block)
|
167
189
|
@command_map[name] = { :desc => description, :arity => arity }
|
168
190
|
metaclass = class << self; self; end
|
169
191
|
# Ruby does not like dashes in method names
|
170
|
-
method_name = name.
|
171
|
-
metaclass.send(:define_method, method_name
|
192
|
+
method_name = to_method_name(name).to_sym
|
193
|
+
metaclass.send(:define_method, method_name) { |*args| block.call(*args) }
|
172
194
|
end
|
173
195
|
|
174
196
|
def add_command_under_category(name, category, description, arity=1, &block)
|
@@ -176,13 +198,13 @@ module Omnibus
|
|
176
198
|
@category_command_map[category] = {} unless @category_command_map.has_key?(category)
|
177
199
|
@category_command_map[category][name] = { :desc => description, :arity => arity }
|
178
200
|
metaclass = class << self; self; end
|
179
|
-
|
180
|
-
method_name
|
181
|
-
metaclass.send(:define_method, method_name.to_sym) { |*args| block.call(*args) }
|
201
|
+
method_name = to_method_name(name).to_sym
|
202
|
+
metaclass.send(:define_method, method_name) { |*args| block.call(*args) }
|
182
203
|
end
|
183
204
|
|
184
|
-
def exit!(
|
185
|
-
|
205
|
+
def exit!(code)
|
206
|
+
@force_exit = true
|
207
|
+
code
|
186
208
|
end
|
187
209
|
|
188
210
|
def log(msg)
|
@@ -218,27 +240,22 @@ module Omnibus
|
|
218
240
|
exit! 0
|
219
241
|
end
|
220
242
|
|
221
|
-
def cleanup_procs_and_nuke(filestr)
|
222
|
-
|
223
|
-
run_sv_command("stop")
|
224
|
-
rescue SystemExit
|
225
|
-
end
|
243
|
+
def cleanup_procs_and_nuke(filestr, calling_method = nil)
|
244
|
+
run_sv_command("stop")
|
226
245
|
|
227
246
|
FileUtils.rm_f("/etc/init/#{name}-runsvdir.conf") if File.exists?("/etc/init/#{name}-runsvdir.conf")
|
228
247
|
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")
|
229
248
|
run_command("kill -1 1")
|
230
249
|
|
231
|
-
backup_dir = Time.now.strftime("/root/#{name}-cleanse-%FT%R")
|
250
|
+
@backup_dir = Time.now.strftime("/root/#{name}-cleanse-%FT%R")
|
251
|
+
|
232
252
|
FileUtils.mkdir_p("/root") unless File.exists?("/root")
|
233
253
|
FileUtils.rm_rf(backup_dir)
|
234
254
|
FileUtils.cp_r(etc_path, backup_dir) if File.exists?(etc_path)
|
235
255
|
run_command("rm -rf #{filestr}")
|
256
|
+
graceful_kill
|
236
257
|
|
237
|
-
|
238
|
-
graceful_kill
|
239
|
-
rescue SystemExit
|
240
|
-
end
|
241
|
-
|
258
|
+
log "Terminating processes running under application users. This will take a few seconds."
|
242
259
|
run_command("pkill -HUP -u #{kill_users.join(',')}") if kill_users.length > 0
|
243
260
|
run_command("pkill -HUP -f 'runsvdir -P #{service_path}'")
|
244
261
|
sleep 3
|
@@ -251,7 +268,6 @@ module Omnibus
|
|
251
268
|
get_all_services.each do |die_daemon_die|
|
252
269
|
run_command("pkill -KILL -f 'runsv #{die_daemon_die}'")
|
253
270
|
end
|
254
|
-
|
255
271
|
log "Your config files have been backed up to #{backup_dir}."
|
256
272
|
exit! 0
|
257
273
|
end
|
@@ -260,14 +276,55 @@ module Omnibus
|
|
260
276
|
cleanup_procs_and_nuke("/tmp/opt")
|
261
277
|
end
|
262
278
|
|
263
|
-
def
|
264
|
-
|
265
|
-
|
266
|
-
|
279
|
+
def scary_cleanse_warning(*args)
|
280
|
+
just_do_it = args.include?("yes")
|
281
|
+
with_external = ARGV.include?("--with-external")
|
282
|
+
log <<EOM
|
283
|
+
*******************************************************************
|
284
|
+
* * * * * * * * * * * STOP AND READ * * * * * * * * * *
|
285
|
+
*******************************************************************
|
286
|
+
This command will delete *all* local configuration, log, and
|
287
|
+
variable data associated with #{display_name}.
|
288
|
+
EOM
|
289
|
+
if (with_external)
|
290
|
+
log <<EOM
|
291
|
+
This will also delete externally hosted #{display_name} data.
|
292
|
+
This means that any service you have configured as 'external'
|
293
|
+
will have any #{display_name} permanently deleted.
|
294
|
+
EOM
|
295
|
+
elsif (not external_services.empty?)
|
296
|
+
log <<EOM
|
297
|
+
|
298
|
+
Important note: If you also wish to delete externally hosted #{display_name}
|
299
|
+
data, please hit CTRL+C now and run '#{exe_name} cleanse --with-external'
|
300
|
+
EOM
|
301
|
+
end
|
302
|
+
|
303
|
+
unless just_do_it
|
304
|
+
data = with_external ? "local, and remote data" : "and local data"
|
305
|
+
log <<EOM
|
306
|
+
|
307
|
+
You have 60 seconds to hit CTRL-C before configuration,
|
308
|
+
logs, #{data} for this application are permanently
|
309
|
+
deleted.
|
310
|
+
*******************************************************************
|
311
|
+
|
312
|
+
EOM
|
313
|
+
begin
|
314
|
+
sleep 60
|
315
|
+
rescue Interrupt
|
316
|
+
log ""
|
317
|
+
exit 0
|
318
|
+
end
|
267
319
|
end
|
268
|
-
cleanup_procs_and_nuke("#{service_path}/* /tmp/opt #{data_path} #{etc_path} #{log_path}")
|
269
320
|
end
|
270
321
|
|
322
|
+
def cleanse(*args)
|
323
|
+
scary_cleanse_warning(*args)
|
324
|
+
cleanup_procs_and_nuke("#{service_path}/* /tmp/opt #{data_path} #{etc_path} #{log_path}", "cleanse")
|
325
|
+
end
|
326
|
+
|
327
|
+
|
271
328
|
def get_all_services_files
|
272
329
|
Dir[File.join(sv_path, '*')]
|
273
330
|
end
|
@@ -282,6 +339,8 @@ module Omnibus
|
|
282
339
|
|
283
340
|
def run_sv_command(sv_cmd, service=nil)
|
284
341
|
exit_status = 0
|
342
|
+
sv_cmd = "1" if sv_cmd == "usr1"
|
343
|
+
sv_cmd = "2" if sv_cmd == "usr2"
|
285
344
|
if service
|
286
345
|
exit_status += run_sv_command_for_service(sv_cmd, service)
|
287
346
|
else
|
@@ -296,10 +355,10 @@ module Omnibus
|
|
296
355
|
def run_sv_command_for_service(sv_cmd, service_name)
|
297
356
|
if service_enabled?(service_name)
|
298
357
|
status = run_command("#{base_path}/init/#{service_name} #{sv_cmd}")
|
299
|
-
|
358
|
+
status.exitstatus
|
300
359
|
else
|
301
360
|
log "#{service_name} disabled" if sv_cmd == "status" && verbose
|
302
|
-
|
361
|
+
0
|
303
362
|
end
|
304
363
|
end
|
305
364
|
|
@@ -341,12 +400,7 @@ module Omnibus
|
|
341
400
|
# not exist), we know that this will be a new server, and we don't
|
342
401
|
# have to worry about pre-upgrade services hanging around. We can safely
|
343
402
|
# return an empty array when running_config is nil
|
344
|
-
|
345
|
-
key = package_name.gsub(/-/, '_')
|
346
|
-
cfg[key]["removed_services"] || []
|
347
|
-
else
|
348
|
-
[]
|
349
|
-
end
|
403
|
+
running_package_config["removed_services"] || []
|
350
404
|
end
|
351
405
|
|
352
406
|
# hidden services are configured via the attributes file in
|
@@ -359,12 +413,7 @@ module Omnibus
|
|
359
413
|
# not exist), we don't want to return nil, just return an empty array.
|
360
414
|
# worse result with doing that is services that we don't want to show up in
|
361
415
|
# c-s-c status will show up.
|
362
|
-
|
363
|
-
key = package_name.gsub(/-/, '_')
|
364
|
-
cfg[key]["hidden_services"] || []
|
365
|
-
else
|
366
|
-
[]
|
367
|
-
end
|
416
|
+
running_package_config["hidden_services"] || []
|
368
417
|
end
|
369
418
|
|
370
419
|
# translate the name from the config to the package name.
|
@@ -389,41 +438,134 @@ module Omnibus
|
|
389
438
|
end
|
390
439
|
end
|
391
440
|
|
441
|
+
# Helper function that returns the hash of config hashes that have the key 'external' : true
|
442
|
+
# in the running config. If none exist it will return an empty hash.
|
443
|
+
def external_services
|
444
|
+
@external_services ||= running_package_config.select { |k, v| v.class == Hash and v["external"] == true }
|
445
|
+
end
|
446
|
+
|
447
|
+
# Helper function that returns true if an external service entry exists for
|
448
|
+
# the named service
|
449
|
+
def service_external?(service)
|
450
|
+
return false if service.nil?
|
451
|
+
return external_services.has_key? service
|
452
|
+
end
|
453
|
+
|
454
|
+
# Gives package config from the running_config.
|
455
|
+
# If there is no running config or if package_name doens't
|
456
|
+
# reference a valid key, this will return an empty hash
|
457
|
+
def running_package_config
|
458
|
+
if (cfg = running_config)
|
459
|
+
cfg[package_name.gsub(/-/, '_')] || {}
|
460
|
+
else
|
461
|
+
{}
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
# This returns running_config[package][service].
|
466
|
+
#
|
467
|
+
# If there is no running_config or is no matching key
|
468
|
+
# it will return nil.
|
469
|
+
def running_service_config(service)
|
470
|
+
running_package_config[service]
|
471
|
+
end
|
472
|
+
|
392
473
|
def remove_old_node_state
|
393
474
|
node_cache_path = "#{base_path}/embedded/nodes/"
|
394
475
|
status = run_command("rm -rf #{node_cache_path}")
|
395
|
-
if !
|
476
|
+
if !status.success?
|
396
477
|
log "Could not remove cached node state!"
|
397
|
-
exit
|
478
|
+
exit 1
|
398
479
|
end
|
399
480
|
end
|
400
481
|
|
401
482
|
def run_chef(attr_location, args='')
|
483
|
+
if @verbose
|
484
|
+
log_level = "-L debug"
|
485
|
+
elsif @quiet
|
486
|
+
# null formatter is awfully quiet, so let them know we're doing something.
|
487
|
+
log "Reconfiguring #{display_name}."
|
488
|
+
log_level = "-L fatal -F null"
|
489
|
+
else
|
490
|
+
log_level = ""
|
491
|
+
end
|
402
492
|
remove_old_node_state
|
403
|
-
cmd = "#{base_path}/embedded/bin/chef-client -z -c #{base_path}/embedded/cookbooks/solo.rb -j #{attr_location}"
|
493
|
+
cmd = "#{base_path}/embedded/bin/chef-client #{log_level} -z -c #{base_path}/embedded/cookbooks/solo.rb -j #{attr_location}"
|
404
494
|
cmd += " #{args}" unless args.empty?
|
405
495
|
run_command(cmd)
|
406
496
|
end
|
407
497
|
|
408
498
|
def show_config(*args)
|
409
|
-
status = run_chef("#{base_path}/embedded/cookbooks/show-config.json", "-l fatal")
|
410
|
-
|
411
|
-
exit! 0
|
412
|
-
else
|
413
|
-
exit! 1
|
414
|
-
end
|
499
|
+
status = run_chef("#{base_path}/embedded/cookbooks/show-config.json", "-l fatal -F null")
|
500
|
+
exit! status.success? ? 0 : 1
|
415
501
|
end
|
416
502
|
|
417
|
-
def reconfigure(
|
503
|
+
def reconfigure(*args)
|
504
|
+
# args being passed to this command does not include the ones that are
|
505
|
+
# starting with "-". See #is_option? method. If it is starting with "-"
|
506
|
+
# then it is treated as a option and we need to look for them in ARGV.
|
507
|
+
check_license_acceptance(ARGV.include?("--accept-license"))
|
508
|
+
|
418
509
|
status = run_chef("#{base_path}/embedded/cookbooks/dna.json")
|
419
510
|
if status.success?
|
420
511
|
log "#{display_name} Reconfigured!"
|
421
|
-
exit! 0
|
512
|
+
exit! 0
|
422
513
|
else
|
423
514
|
exit! 1
|
424
515
|
end
|
425
516
|
end
|
426
517
|
|
518
|
+
def check_license_acceptance(override_accept = false)
|
519
|
+
license_guard_file_path = File.join(data_path, ".license.accepted")
|
520
|
+
|
521
|
+
# If the project does not have a license we do not have
|
522
|
+
# any license to accept.
|
523
|
+
return unless File.exist?(project_license_path)
|
524
|
+
|
525
|
+
if !File.exist?(license_guard_file_path)
|
526
|
+
if override_accept || ask_license_acceptance
|
527
|
+
FileUtils.mkdir_p(data_path)
|
528
|
+
FileUtils.touch(license_guard_file_path)
|
529
|
+
else
|
530
|
+
log "Please accept the software license agreement to continue."
|
531
|
+
exit(1)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
def ask_license_acceptance
|
537
|
+
log "To use this software, you must agree to the terms of the software license agreement."
|
538
|
+
|
539
|
+
if !STDIN.tty?
|
540
|
+
log "Please view and accept the software license agreement, or pass --accept-license."
|
541
|
+
exit(1)
|
542
|
+
end
|
543
|
+
|
544
|
+
log "Press any key to continue."
|
545
|
+
user_input = STDIN.getch
|
546
|
+
user_input << STDIN.getch while STDIN.ready?
|
547
|
+
# No need to check for user input
|
548
|
+
|
549
|
+
system("less #{project_license_path}")
|
550
|
+
|
551
|
+
loop do
|
552
|
+
log "Type 'yes' to accept the software license agreement, or anything else to cancel."
|
553
|
+
|
554
|
+
user_input = STDIN.gets.chomp.downcase
|
555
|
+
case user_input
|
556
|
+
when "yes"
|
557
|
+
return true
|
558
|
+
else
|
559
|
+
log "You have not accepted the software license agreement."
|
560
|
+
return false
|
561
|
+
end
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
def project_license_path
|
566
|
+
File.join(base_path, "LICENSE")
|
567
|
+
end
|
568
|
+
|
427
569
|
def tail(*args)
|
428
570
|
# find /var/log -type f -not -path '*/sasl/*' | grep -E -v '(lock|@|tgz|gzip)' | xargs tail --follow=name --retry
|
429
571
|
command = "find #{log_path}"
|
@@ -468,14 +610,14 @@ module Omnibus
|
|
468
610
|
end
|
469
611
|
else
|
470
612
|
log "#{service_name} disabled, not stopping"
|
471
|
-
exit_status =
|
613
|
+
exit_status =1
|
472
614
|
end
|
473
615
|
end
|
474
616
|
exit! exit_status
|
475
617
|
end
|
476
618
|
|
477
619
|
def help(*args)
|
478
|
-
log "#{
|
620
|
+
log "#{exe_name}: command (subcommand)\n"
|
479
621
|
command_map.keys.sort.each do |command|
|
480
622
|
log command
|
481
623
|
log " #{command_map[command][:desc]}"
|
@@ -491,16 +633,22 @@ module Omnibus
|
|
491
633
|
log " #{commands[command][:desc]}"
|
492
634
|
end
|
493
635
|
end
|
494
|
-
exit
|
636
|
+
# Help is not an error so exit with 0. In cases where we display help as a result of an error
|
637
|
+
# the framework will handle setting proper exit code.
|
638
|
+
exit! 0
|
495
639
|
end
|
496
640
|
|
497
|
-
# Set options
|
498
|
-
#
|
499
|
-
def parse_options
|
500
|
-
args.
|
641
|
+
# Set global options and remove them from the args list we pass
|
642
|
+
# into commands.
|
643
|
+
def parse_options(args)
|
644
|
+
args.select do |option|
|
501
645
|
case option
|
646
|
+
when "--quiet", "-q"
|
647
|
+
@quiet = true
|
648
|
+
false
|
502
649
|
when "--verbose", "-v"
|
503
650
|
@verbose = true
|
651
|
+
false
|
504
652
|
end
|
505
653
|
end
|
506
654
|
end
|
@@ -526,6 +674,10 @@ module Omnibus
|
|
526
674
|
end
|
527
675
|
end
|
528
676
|
|
677
|
+
# Previously this would exit immediately with the provided
|
678
|
+
# exit code; however this would prevent post-run hooks from continuing
|
679
|
+
# Instead, we'll just track whether a an exit was requested and use that
|
680
|
+
# to determine how we exit from 'run'
|
529
681
|
def run(args)
|
530
682
|
# Ensure Omnibus related binaries are in the PATH
|
531
683
|
ENV["PATH"] = [File.join(base_path, "bin"),
|
@@ -549,31 +701,191 @@ module Omnibus
|
|
549
701
|
service = args[1]
|
550
702
|
end
|
551
703
|
|
552
|
-
# returns either hash content of
|
704
|
+
# returns either hash content of command or nil
|
553
705
|
command = retrieve_command(command_to_run)
|
554
|
-
|
555
706
|
if command.nil?
|
556
707
|
log "I don't know that command."
|
557
708
|
if args.length == 2
|
558
|
-
log "Did you mean: #{
|
709
|
+
log "Did you mean: #{exe_name} #{service} #{command_to_run}?"
|
559
710
|
end
|
560
711
|
help
|
712
|
+
Kernel.exit 1
|
561
713
|
end
|
562
714
|
|
563
715
|
if args.length > 1 && command[:arity] != 2
|
564
716
|
log "The command #{command_to_run} does not accept any arguments"
|
565
|
-
exit
|
717
|
+
Kernel.exit 2
|
566
718
|
end
|
567
719
|
|
568
|
-
parse_options
|
720
|
+
parse_options options
|
721
|
+
@force_exit = false
|
722
|
+
exit_code = 0
|
569
723
|
|
570
|
-
method_to_call = command_to_run.gsub(/-/, '_')
|
571
724
|
# Filter args to just command and service. If you are loading
|
572
725
|
# custom commands and need access to the command line argument,
|
573
726
|
# use ARGV directly.
|
574
727
|
actual_args = [command_to_run, service].reject(&:nil?)
|
575
|
-
|
728
|
+
if command_pre_hook(*actual_args)
|
729
|
+
method_to_call = to_method_name(command_to_run)
|
730
|
+
begin
|
731
|
+
ret = send(method_to_call, *actual_args)
|
732
|
+
rescue SystemExit => e
|
733
|
+
@force_exit = true
|
734
|
+
ret = e.status
|
735
|
+
end
|
736
|
+
command_post_hook(*actual_args)
|
737
|
+
exit_code = ret unless ret.nil?
|
738
|
+
else
|
739
|
+
exit_code = 8
|
740
|
+
@force_exit = true
|
741
|
+
end
|
742
|
+
|
743
|
+
if @force_exit
|
744
|
+
Kernel.exit exit_code
|
745
|
+
else
|
746
|
+
exit_code
|
747
|
+
end
|
748
|
+
end
|
749
|
+
|
750
|
+
# Below are some basic command hooks that do the right thing
|
751
|
+
# when a service is configured as external via [package][service
|
752
|
+
|
753
|
+
# If a command has a pre-hook defined we will run it.
|
754
|
+
# Otherwise, if it is a run-sv command and the service it refers to
|
755
|
+
# is an external service, we will show an error since we
|
756
|
+
# can't control external services from here.
|
757
|
+
#
|
758
|
+
# If any pre-hook returns false, it will prevent execution of the command
|
759
|
+
# and exit the command with exit code 8.
|
760
|
+
def command_pre_hook(*args)
|
761
|
+
command = args.shift
|
762
|
+
method = to_method_name("#{command}_pre_hook")
|
763
|
+
if respond_to?(method)
|
764
|
+
send(method, *args)
|
765
|
+
else
|
766
|
+
return true if args.empty?
|
767
|
+
if SV_COMMAND_NAMES.include? command
|
768
|
+
if service_external? args[0]
|
769
|
+
log error_external_service(command, args[0])
|
770
|
+
return false;
|
771
|
+
end
|
772
|
+
end
|
773
|
+
true
|
774
|
+
end
|
576
775
|
end
|
577
776
|
|
777
|
+
# Executes after successful completion of a command
|
778
|
+
# If a post-hook provides a numeric return code, it will
|
779
|
+
# replace the return/exit of the original command
|
780
|
+
def command_post_hook(*args)
|
781
|
+
command = args.shift
|
782
|
+
method = to_method_name("#{command}_post_hook")
|
783
|
+
if respond_to?(method)
|
784
|
+
send(method, *args)
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
# If we're listing status for all services and have external
|
789
|
+
# services to show, we'll include an output header to show that
|
790
|
+
# we're reporting internal services
|
791
|
+
def status_pre_hook(service = nil)
|
792
|
+
log_internal_service_header if service.nil?
|
793
|
+
true
|
794
|
+
end
|
795
|
+
# Status gets its own hook because each externalized service will
|
796
|
+
# have its own things to do in order to report status.
|
797
|
+
# As above, we may also include an output header to show that we're
|
798
|
+
# reporting on external services.
|
799
|
+
#
|
800
|
+
# Your callback for this function should be in the form
|
801
|
+
# 'external_status_#{service_name}(detail_level)
|
802
|
+
# where detail_level is :sparse|:verbose
|
803
|
+
# :sparse is used when it's a summary service status list, eg
|
804
|
+
# "$appname-ctl status"
|
805
|
+
# :verbose is used when the specific service has been named, eg
|
806
|
+
# "$appname-ctl status postgresql"
|
807
|
+
def status_post_hook(service = nil)
|
808
|
+
if service.nil?
|
809
|
+
log_external_service_header
|
810
|
+
external_services.each_key do |service_name|
|
811
|
+
status = send(to_method_name("external_status_#{service_name}"), :sparse)
|
812
|
+
log status
|
813
|
+
end
|
814
|
+
else
|
815
|
+
# Request verbose status if the service is asked for by name.
|
816
|
+
if service_external?(service)
|
817
|
+
status = send(to_method_name("external_status_#{service}"), :verbose)
|
818
|
+
log status
|
819
|
+
end
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
# Data cleanup requirements for external services aren't met by the standard
|
824
|
+
# 'nuke /var/opt' behavior - this hook allows each service to perform its own
|
825
|
+
# 'cleanse' operations.
|
826
|
+
#
|
827
|
+
# Your callback for this function should be in the
|
828
|
+
# form 'external_cleanup_#{service_name}(do_clean)
|
829
|
+
# where do_cliean is true if the delete should actually be
|
830
|
+
# performed, and false if it's expected to inform the user how to
|
831
|
+
# perform the data cleanup without doing any cleanup itself.
|
832
|
+
def cleanse_post_hook(*args)
|
833
|
+
external_services.each_key do |service_name|
|
834
|
+
perform_delete = ARGV.include?("--with-external")
|
835
|
+
if perform_delete
|
836
|
+
log "Deleting data from external service: #{service_name}"
|
837
|
+
end
|
838
|
+
send(to_method_name("external_cleanse_#{service_name}"), perform_delete)
|
839
|
+
end
|
840
|
+
end
|
841
|
+
|
842
|
+
# Add some output headers if we have external services enabled
|
843
|
+
def service_list_pre_hook
|
844
|
+
log_internal_service_header
|
845
|
+
return true
|
846
|
+
end
|
847
|
+
|
848
|
+
# Capture external services in the output list as well.
|
849
|
+
def service_list_post_hook
|
850
|
+
log_external_service_header
|
851
|
+
external_services.each do |name, settings|
|
852
|
+
log " > #{name} on #{settings['vip']}"
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
def error_external_service(command, service)
|
857
|
+
<<EOM
|
858
|
+
-------------------------------------------------------------------
|
859
|
+
The service #{service} is running externally and cannot be managed
|
860
|
+
vi chef-server-ctl. Please log into #{external_services[service]['vip'] }
|
861
|
+
to manage it directly.
|
862
|
+
-------------------------------------------------------------------
|
863
|
+
EOM
|
864
|
+
end
|
865
|
+
|
866
|
+
def format_multiline_message(indent, message)
|
867
|
+
if message.class == String
|
868
|
+
message = message.split("\n")
|
869
|
+
end
|
870
|
+
spaces = " "*indent
|
871
|
+
message.map!{|line| "#{spaces}#{line.strip}"}
|
872
|
+
message.join("\n")
|
873
|
+
end
|
874
|
+
|
875
|
+
def log_internal_service_header
|
876
|
+
# Don't decorate output unless we have
|
877
|
+
# external services to report on.
|
878
|
+
return if external_services.empty?
|
879
|
+
log "-------------------"
|
880
|
+
log " Internal Services "
|
881
|
+
log "-------------------"
|
882
|
+
end
|
883
|
+
|
884
|
+
def log_external_service_header
|
885
|
+
return if external_services.empty?
|
886
|
+
log "-------------------"
|
887
|
+
log " External Services "
|
888
|
+
log "-------------------"
|
889
|
+
end
|
578
890
|
end
|
579
891
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omnibus-ctl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Opscode, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
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'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rspec
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -41,7 +55,7 @@ dependencies:
|
|
41
55
|
description: Provides command line control for omnibus pakcages, rarely used as a
|
42
56
|
gem
|
43
57
|
email:
|
44
|
-
- legal@
|
58
|
+
- legal@chef.io
|
45
59
|
executables:
|
46
60
|
- omnibus-ctl
|
47
61
|
extensions: []
|
@@ -51,7 +65,7 @@ files:
|
|
51
65
|
- bin/omnibus-ctl
|
52
66
|
- lib/omnibus-ctl.rb
|
53
67
|
- lib/omnibus-ctl/version.rb
|
54
|
-
homepage: http://github.com/
|
68
|
+
homepage: http://github.com/chef/omnibus-ctl
|
55
69
|
licenses: []
|
56
70
|
metadata: {}
|
57
71
|
post_install_message:
|
@@ -70,9 +84,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
84
|
version: '0'
|
71
85
|
requirements: []
|
72
86
|
rubyforge_project:
|
73
|
-
rubygems_version: 2.
|
87
|
+
rubygems_version: 2.5.2
|
74
88
|
signing_key:
|
75
89
|
specification_version: 4
|
76
90
|
summary: Provides command line control for omnibus packages
|
77
91
|
test_files: []
|
78
|
-
has_rdoc:
|