morpheus-cli 3.6.3 → 3.6.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/morpheus/cli/apps.rb +605 -216
- data/lib/morpheus/cli/blueprints_command.rb +139 -187
- data/lib/morpheus/cli/cli_command.rb +106 -6
- data/lib/morpheus/cli/cloud_datastores_command.rb +1 -1
- data/lib/morpheus/cli/commands/standard/cat_command.rb +45 -0
- data/lib/morpheus/cli/containers_command.rb +7 -9
- data/lib/morpheus/cli/echo_command.rb +3 -1
- data/lib/morpheus/cli/execution_request_command.rb +4 -4
- data/lib/morpheus/cli/expression_parser.rb +4 -0
- data/lib/morpheus/cli/file_copy_request_command.rb +4 -4
- data/lib/morpheus/cli/hosts.rb +11 -13
- data/lib/morpheus/cli/instances.rb +109 -41
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +115 -79
- data/lib/morpheus/cli/monitoring_checks_command.rb +2 -2
- data/lib/morpheus/cli/option_types.rb +30 -3
- data/lib/morpheus/cli/remote.rb +8 -4
- data/lib/morpheus/cli/shell.rb +4 -3
- data/lib/morpheus/cli/source_command.rb +1 -0
- data/lib/morpheus/cli/storage_providers_command.rb +10 -0
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.rb +3 -3
- metadata +3 -2
@@ -209,27 +209,53 @@ module Morpheus
|
|
209
209
|
nested_options[name_element] = nested_options[name_element] || {}
|
210
210
|
nested_options = nested_options[name_element]
|
211
211
|
else
|
212
|
-
|
212
|
+
val = custom_option_args[1]
|
213
|
+
if val.to_s[0] == '{' && val.to_s[-1] == '}'
|
214
|
+
begin
|
215
|
+
val = JSON.parse(val)
|
216
|
+
rescue
|
217
|
+
Morpheus::Logging::DarkPrinter.puts "Failed to parse option value '#{val}' as JSON" if Morpheus::Logging.debug?
|
218
|
+
end
|
219
|
+
end
|
220
|
+
nested_options[name_element] = val
|
213
221
|
end
|
214
222
|
end
|
215
223
|
else
|
216
|
-
|
224
|
+
val = custom_option_args[1]
|
225
|
+
if val.to_s[0] == '{' && val.to_s[-1] == '}'
|
226
|
+
begin
|
227
|
+
val = JSON.parse(val)
|
228
|
+
rescue
|
229
|
+
Morpheus::Logging::DarkPrinter.puts "Failed to parse option value '#{val}' as JSON" if Morpheus::Logging.debug?
|
230
|
+
end
|
231
|
+
end
|
232
|
+
custom_options[custom_option_args[0]] = val
|
217
233
|
end
|
218
234
|
# convert "true","on" and "false","off" to true and false
|
219
|
-
|
235
|
+
unless options[:skip_booleanize]
|
236
|
+
custom_options.booleanize!
|
237
|
+
end
|
220
238
|
options[:options] = custom_options
|
221
239
|
end
|
240
|
+
opts.on('-P','--prompt', "Always prompts. Use passed options as the default value.") do |val|
|
241
|
+
options[:always_prompt] = true
|
242
|
+
options[:options] ||= {}
|
243
|
+
options[:options][:always_prompt] = true
|
244
|
+
end
|
222
245
|
opts.on('-N','--no-prompt', "Skip prompts. Use default values for all optional fields.") do |val|
|
223
246
|
options[:no_prompt] = true
|
224
|
-
# ew, stored in here for now because options[:options] is what is passed into OptionTypes.prompt() everywhere!
|
225
247
|
options[:options] ||= {}
|
226
248
|
options[:options][:no_prompt] = true
|
227
249
|
end
|
228
250
|
|
229
|
-
when :
|
251
|
+
when :prompt
|
252
|
+
opts.on('-P','--prompt', "Always prompts. Use passed options as the default value.") do |val|
|
253
|
+
options[:always_prompt] = true
|
254
|
+
options[:options] ||= {}
|
255
|
+
options[:options][:always_prompt] = true
|
256
|
+
end
|
230
257
|
opts.on('-N','--no-prompt', "Skip prompts. Use default values for all optional fields.") do |val|
|
231
258
|
options[:no_prompt] = true
|
232
|
-
# ew, stored in here for now because options[:options] is what is passed into OptionTypes.prompt() everywhere!
|
233
259
|
options[:options] ||= {}
|
234
260
|
options[:options][:no_prompt] = true
|
235
261
|
end
|
@@ -252,6 +278,37 @@ module Morpheus
|
|
252
278
|
raise ::OptionParser::InvalidOption.new("Failed to parse payload file: #{payload_file} Error: #{ex.message}")
|
253
279
|
end
|
254
280
|
end
|
281
|
+
opts.on('--payload-dir DIRECTORY', String, "Payload from a local directory containing 1-N JSON or YAML files, skip all prompting") do |val|
|
282
|
+
options[:payload_dir] = val.to_s
|
283
|
+
payload_dir = File.expand_path(options[:payload_dir])
|
284
|
+
if !Dir.exists?(payload_dir) || !File.directory?(payload_dir)
|
285
|
+
raise ::OptionParser::InvalidOption.new("Directory not found: #{payload_dir}")
|
286
|
+
end
|
287
|
+
payload = {}
|
288
|
+
begin
|
289
|
+
merged_payload = {}
|
290
|
+
payload_files = []
|
291
|
+
payload_files += Dir["#{payload_dir}/*.json"]
|
292
|
+
payload_files += Dir["#{payload_dir}/*.yml"]
|
293
|
+
payload_files += Dir["#{payload_dir}/*.yaml"]
|
294
|
+
if payload_files.empty?
|
295
|
+
raise ::OptionParser::InvalidOption.new("No .json/yaml files found in config directory: #{payload_dir}")
|
296
|
+
end
|
297
|
+
payload_files.each do |payload_file|
|
298
|
+
Morpheus::Logging::DarkPrinter.puts "parsing payload file: #{payload_file}" if Morpheus::Logging.debug?
|
299
|
+
config_payload = {}
|
300
|
+
if payload_file =~ /\.ya?ml\Z/
|
301
|
+
config_payload = YAML.load_file(payload_file)
|
302
|
+
else
|
303
|
+
config_payload = JSON.parse(File.read(payload_file))
|
304
|
+
end
|
305
|
+
merged_payload.deep_merge!(config_payload)
|
306
|
+
end
|
307
|
+
options[:payload] = merged_payload
|
308
|
+
rescue => ex
|
309
|
+
raise ::OptionParser::InvalidOption.new("Failed to parse payload file: #{payload_file} Error: #{ex.message}")
|
310
|
+
end
|
311
|
+
end
|
255
312
|
opts.on('--payload-json JSON', String, "Payload JSON, skip all prompting") do |val|
|
256
313
|
begin
|
257
314
|
options[:payload] = JSON.parse(val.to_s)
|
@@ -455,6 +512,12 @@ module Morpheus
|
|
455
512
|
options[:include_fields] = val
|
456
513
|
end
|
457
514
|
|
515
|
+
when :outfile
|
516
|
+
opts.on('--out FILE', String, "Write standard output to a file instead of the terminal.") do |val|
|
517
|
+
# could validate directory is writable..
|
518
|
+
options[:outfile] = val
|
519
|
+
end
|
520
|
+
|
458
521
|
when :dry_run
|
459
522
|
opts.on('-d','--dry-run', "Dry Run, print the API request instead of executing it") do
|
460
523
|
options[:dry_run] = true
|
@@ -754,6 +817,43 @@ module Morpheus
|
|
754
817
|
return subtitles
|
755
818
|
end
|
756
819
|
|
820
|
+
def print_to_file(txt, filename)
|
821
|
+
Morpheus::Logging::DarkPrinter.puts "Writing #{txt.to_s.bytesize} bytes to file #{filename}" if Morpheus::Logging.debug?
|
822
|
+
outfile = nil
|
823
|
+
begin
|
824
|
+
outfile = File.open(File.expand_path(filename), 'w')
|
825
|
+
outfile.print(txt)
|
826
|
+
return 0
|
827
|
+
rescue => ex
|
828
|
+
puts_error "Error printing to outfile '#{filename}'. Error: #{ex}"
|
829
|
+
return 1
|
830
|
+
ensure
|
831
|
+
outfile.close if outfile
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
# basic rendering for options :json, :yaml, :csv, :fields, and :outfile
|
836
|
+
# returns the string rendered, or nil if nothing was rendered.
|
837
|
+
def render_with_format(json_response, options, object_key=nil)
|
838
|
+
output = nil
|
839
|
+
if options[:json]
|
840
|
+
output = as_json(json_response, options, object_key)
|
841
|
+
elsif options[:yaml]
|
842
|
+
output = as_yaml(json_response, options, object_key)
|
843
|
+
elsif options[:csv]
|
844
|
+
row = object_key ? json_response[object_key] : json_response
|
845
|
+
output = records_as_csv([row], options)
|
846
|
+
end
|
847
|
+
if output
|
848
|
+
if options[:outfile]
|
849
|
+
print_to_file(output, options[:outfile])
|
850
|
+
else
|
851
|
+
puts output
|
852
|
+
end
|
853
|
+
end
|
854
|
+
return output
|
855
|
+
end
|
856
|
+
|
757
857
|
module ClassMethods
|
758
858
|
|
759
859
|
def set_command_name(cmd_name)
|
@@ -379,7 +379,7 @@ class Morpheus::Cli::CloudDatastoresCommand
|
|
379
379
|
elsif datastores.size > 1
|
380
380
|
print_red_alert "#{datastores.size} datastores found by name #{name}"
|
381
381
|
# print_datastores_table(datastores, {color: red})
|
382
|
-
rows = datastores.collect do |
|
382
|
+
rows = datastores.collect do |it|
|
383
383
|
{id: it['id'], name: it['name']}
|
384
384
|
end
|
385
385
|
print red
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
# This is for printing the content of files(s)
|
4
|
+
class Morpheus::Cli::CatCommand
|
5
|
+
include Morpheus::Cli::CliCommand
|
6
|
+
set_command_name :cat
|
7
|
+
set_command_hidden
|
8
|
+
|
9
|
+
def handle(args)
|
10
|
+
append_newline = true
|
11
|
+
options = {}
|
12
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
13
|
+
opts.banner = "Usage: morpheus #{command_name} [file ...]"
|
14
|
+
build_common_options(opts, options, [])
|
15
|
+
opts.footer = "Concatenate and print files." + "\n" +
|
16
|
+
"[file] is required. This is the name of a file. Supports many [file] arguments."
|
17
|
+
end
|
18
|
+
optparse.parse!(args)
|
19
|
+
if args.count < 1
|
20
|
+
print_error Morpheus::Terminal.angry_prompt
|
21
|
+
puts_error "#{command_name} expects 1-N arguments and received #{args.count} #{args}\n#{optparse}"
|
22
|
+
return 1
|
23
|
+
end
|
24
|
+
|
25
|
+
arg_files = args
|
26
|
+
arg_files.each do |arg_file|
|
27
|
+
arg_file = File.expand_path(arg_file)
|
28
|
+
if !File.exists?(arg_file)
|
29
|
+
print_error Morpheus::Terminal.angry_prompt
|
30
|
+
puts_error "#{command_name}: file not found: '#{arg_file}'"
|
31
|
+
#print_red_alert "morpheus cat: file not found: '#{arg_file}'"
|
32
|
+
return 1
|
33
|
+
end
|
34
|
+
if File.directory?(arg_file)
|
35
|
+
print_red_alert "morpheus cat: file is a directory: '#{arg_file}'"
|
36
|
+
return 1
|
37
|
+
end
|
38
|
+
file_contents = File.read(arg_file)
|
39
|
+
print file_contents.to_s
|
40
|
+
return 0
|
41
|
+
end
|
42
|
+
return true
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -33,15 +33,14 @@ class Morpheus::Cli::ContainersCommand
|
|
33
33
|
opts.on( nil, '--actions', "Display Available Actions" ) do
|
34
34
|
options[:include_available_actions] = true
|
35
35
|
end
|
36
|
-
opts.on('--refresh [
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
options[:refresh_until_status] = val.to_s.downcase
|
36
|
+
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is 5 seconds.") do |val|
|
37
|
+
options[:refresh_until_status] ||= "running,failed"
|
38
|
+
if !val.to_s.empty?
|
39
|
+
options[:refresh_interval] = val.to_f
|
41
40
|
end
|
42
41
|
end
|
43
|
-
opts.on('--refresh-
|
44
|
-
options[:
|
42
|
+
opts.on('--refresh-until STATUS', String, "Refresh until a specified status is reached.") do |val|
|
43
|
+
options[:refresh_until_status] = val.to_s.downcase
|
45
44
|
end
|
46
45
|
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
47
46
|
end
|
@@ -140,8 +139,7 @@ class Morpheus::Cli::ContainersCommand
|
|
140
139
|
statuses = options[:refresh_until_status].to_s.downcase.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
|
141
140
|
if !statuses.include?(container['status'])
|
142
141
|
print cyan
|
143
|
-
print "
|
144
|
-
#sleep(options[:refresh_interval])
|
142
|
+
print cyan, "Refreshing in #{options[:refresh_interval]} seconds"
|
145
143
|
sleep_with_dots(options[:refresh_interval])
|
146
144
|
print "\n"
|
147
145
|
_get(arg, options)
|
@@ -23,7 +23,9 @@ class Morpheus::Cli::Echo
|
|
23
23
|
var_map.merge!(DEFAULT_VARIABLE_MAP)
|
24
24
|
appliance = ::Morpheus::Cli::Remote.load_active_remote()
|
25
25
|
if appliance
|
26
|
-
var_map.merge!({'%remote' => appliance[:name], '%remote_url' => appliance[:host], '%username' => appliance[:username]})
|
26
|
+
var_map.merge!({'%remote' => appliance[:name], '%remote_url' => appliance[:host].to_s, '%username' => appliance[:username].to_s})
|
27
|
+
else
|
28
|
+
var_map.merge!({'%remote' => '', '%remote_url' => '', '%username' => ''})
|
27
29
|
end
|
28
30
|
@output_variable_map = var_map
|
29
31
|
end
|
@@ -37,11 +37,11 @@ class Morpheus::Cli::ExecutionRequestCommand
|
|
37
37
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
38
38
|
opts.banner = subcommand_usage("[uid]")
|
39
39
|
build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
40
|
-
opts.on('--refresh', String, "Refresh until execution is finished.") do |val|
|
40
|
+
opts.on('--refresh [SECONDS]', String, "Refresh until execution is finished. Default interval is 5 seconds.") do |val|
|
41
41
|
options[:refresh_until_finished] = true
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
if !val.to_s.empty?
|
43
|
+
options[:refresh_interval] = val.to_f
|
44
|
+
end
|
45
45
|
end
|
46
46
|
opts.footer = "Get details about an execution request." + "\n" +
|
47
47
|
"[uid] is required. This is the unique id of an execution request."
|
@@ -40,6 +40,10 @@ module Morpheus::Cli::ExpressionParser
|
|
40
40
|
|
41
41
|
# parse an expression of morpheus commands into a list of expressions
|
42
42
|
def self.parse(input)
|
43
|
+
# the input is a comment
|
44
|
+
if input.to_s =~ /^\s*#/
|
45
|
+
return [input]
|
46
|
+
end
|
43
47
|
result = []
|
44
48
|
# first, build up a temporary command string
|
45
49
|
# swap in well known tokens so we can split it safely
|
@@ -37,11 +37,11 @@ class Morpheus::Cli::FileCopyRequestCommand
|
|
37
37
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
38
38
|
opts.banner = subcommand_usage("[uid]")
|
39
39
|
build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
40
|
-
opts.on('--refresh', String, "Refresh until
|
40
|
+
opts.on('--refresh [SECONDS]', String, "Refresh until execution is finished. Default interval is 5 seconds.") do |val|
|
41
41
|
options[:refresh_until_finished] = true
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
if !val.to_s.empty?
|
43
|
+
options[:refresh_interval] = val.to_f
|
44
|
+
end
|
45
45
|
end
|
46
46
|
opts.footer = "Get details about a file copy request." + "\n" +
|
47
47
|
"[uid] is required. This is the unique id of a file copy request."
|
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -254,15 +254,14 @@ class Morpheus::Cli::Hosts
|
|
254
254
|
options = {}
|
255
255
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
256
256
|
opts.banner = subcommand_usage("[name]")
|
257
|
-
opts.on('--refresh [
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
options[:refresh_until_status] = val.to_s.downcase
|
257
|
+
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is 5 seconds.") do |val|
|
258
|
+
options[:refresh_until_status] ||= "provisioned,failed"
|
259
|
+
if !val.to_s.empty?
|
260
|
+
options[:refresh_interval] = val.to_f
|
262
261
|
end
|
263
262
|
end
|
264
|
-
opts.on('--refresh-
|
265
|
-
options[:
|
263
|
+
opts.on('--refresh-until STATUS', String, "Refresh until a specified status is reached.") do |val|
|
264
|
+
options[:refresh_until_status] = val.to_s.downcase
|
266
265
|
end
|
267
266
|
build_common_options(opts, options, [:json, :csv, :yaml, :fields, :dry_run, :remote])
|
268
267
|
end
|
@@ -337,8 +336,7 @@ class Morpheus::Cli::Hosts
|
|
337
336
|
statuses = options[:refresh_until_status].to_s.downcase.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
|
338
337
|
if !statuses.include?(server['status'])
|
339
338
|
print cyan
|
340
|
-
print "
|
341
|
-
#sleep(options[:refresh_interval])
|
339
|
+
print cyan, "Refreshing in #{options[:refresh_interval]} seconds"
|
342
340
|
sleep_with_dots(options[:refresh_interval])
|
343
341
|
print "\n"
|
344
342
|
_get(arg, options)
|
@@ -763,16 +761,16 @@ class Morpheus::Cli::Hosts
|
|
763
761
|
# query_params[:removeResources] = 'off'
|
764
762
|
# end
|
765
763
|
opts.on('--remove-resources [on|off]', ['on','off'], "Remove Infrastructure. Default is on if server is managed.") do |val|
|
766
|
-
query_params[:removeResources] = val
|
764
|
+
query_params[:removeResources] = val.nil? ? 'on' : val
|
767
765
|
end
|
768
766
|
opts.on('--preserve-volumes [on|off]', ['on','off'], "Preserve Volumes. Default is off.") do |val|
|
769
|
-
query_params[:preserveVolumes] = val
|
767
|
+
query_params[:preserveVolumes] = val.nil? ? 'on' : val
|
770
768
|
end
|
771
769
|
opts.on('--remove-instances [on|off]', ['on','off'], "Remove Associated Instances. Default is off.") do |val|
|
772
|
-
query_params[:removeInstances] = val
|
770
|
+
query_params[:removeInstances] = val.nil? ? 'on' : val
|
773
771
|
end
|
774
772
|
opts.on('--release-eips [on|off]', ['on','off'], "Release EIPs, default is on. Amazon only.") do |val|
|
775
|
-
params[:releaseEIPs] = val
|
773
|
+
params[:releaseEIPs] = val.nil? ? 'on' : val
|
776
774
|
end
|
777
775
|
opts.on( '-f', '--force', "Force Delete" ) do
|
778
776
|
query_params[:force] = 'on'
|
@@ -226,6 +226,9 @@ class Morpheus::Cli::Instances
|
|
226
226
|
opts.on( '--name NAME', "Instance Name" ) do |val|
|
227
227
|
options[:instance_name] = val
|
228
228
|
end
|
229
|
+
opts.on("--description [TEXT]", String, "Description") do |val|
|
230
|
+
options[:description] = val.to_s
|
231
|
+
end
|
229
232
|
opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
|
230
233
|
options[:copies] = val.to_i
|
231
234
|
end
|
@@ -250,8 +253,8 @@ class Morpheus::Cli::Instances
|
|
250
253
|
opts.on("--expire-days NUMBER", Integer, "Automation: Expiration Days") do |val|
|
251
254
|
options[:expire_days] = val.to_i
|
252
255
|
end
|
253
|
-
opts.on("--create-backup on|off", String, "Automation: Create Backups.
|
254
|
-
options[:create_backup] = ['on','true','1'].include?(val.to_s.downcase) ? 'on' : 'off'
|
256
|
+
opts.on("--create-backup [on|off]", String, "Automation: Create Backups.") do |val|
|
257
|
+
options[:create_backup] = ['on','true','1',''].include?(val.to_s.downcase) ? 'on' : 'off'
|
255
258
|
end
|
256
259
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
|
257
260
|
opts.footer = "Create a new instance." + "\n" +
|
@@ -301,17 +304,17 @@ class Morpheus::Cli::Instances
|
|
301
304
|
end
|
302
305
|
end
|
303
306
|
end
|
304
|
-
|
307
|
+
payload['instance'] ||= {}
|
305
308
|
if options[:instance_name]
|
306
|
-
payload['instance'] ||= payload['instance']
|
307
309
|
payload['instance']['name'] = options[:instance_name]
|
308
310
|
end
|
309
311
|
payload[:copies] = options[:copies] if options[:copies] && options[:copies] > 0
|
310
312
|
payload[:layoutSize] = options[:layout_size] if options[:layout_size] && options[:layout_size] > 0 # aka Scale Factor
|
311
|
-
payload[:createBackup] = options[:create_backup]
|
313
|
+
payload[:createBackup] = options[:create_backup] if !options[:create_backup].nil?
|
312
314
|
payload['instance']['expireDays'] = options[:expire_days] if options[:expire_days]
|
313
315
|
payload['instance']['shutdownDays'] = options[:shutdown_days] if options[:shutdown_days]
|
314
316
|
if options.key?(:create_user)
|
317
|
+
payload['config'] ||= {}
|
315
318
|
payload['config']['createUser'] = options[:create_user]
|
316
319
|
end
|
317
320
|
if options[:user_group_id]
|
@@ -743,15 +746,14 @@ class Morpheus::Cli::Instances
|
|
743
746
|
opts.on( nil, '--scaling', "Display Instance Scaling Settings" ) do
|
744
747
|
options[:include_scaling] = true
|
745
748
|
end
|
746
|
-
opts.on('--refresh [
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
options[:refresh_until_status] = val.to_s.downcase
|
749
|
+
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is 5 seconds.") do |val|
|
750
|
+
options[:refresh_until_status] ||= "running,failed"
|
751
|
+
if !val.to_s.empty?
|
752
|
+
options[:refresh_interval] = val.to_f
|
751
753
|
end
|
752
754
|
end
|
753
|
-
opts.on('--refresh-
|
754
|
-
options[:
|
755
|
+
opts.on('--refresh-until STATUS', String, "Refresh until a specified status is reached.") do |val|
|
756
|
+
options[:refresh_until_status] = val.to_s.downcase
|
755
757
|
end
|
756
758
|
# opts.on( nil, '--threshold', "Alias for --scaling" ) do
|
757
759
|
# options[:include_scaling] = true
|
@@ -957,9 +959,7 @@ class Morpheus::Cli::Instances
|
|
957
959
|
end
|
958
960
|
statuses = options[:refresh_until_status].to_s.downcase.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
|
959
961
|
if !statuses.include?(instance['status'])
|
960
|
-
print cyan
|
961
|
-
print "Status is #{instance['status'] || 'unknown'}. Refreshing in #{options[:refresh_interval]} seconds"
|
962
|
-
#sleep(options[:refresh_interval])
|
962
|
+
print cyan, "Refreshing in #{options[:refresh_interval]} seconds"
|
963
963
|
sleep_with_dots(options[:refresh_interval])
|
964
964
|
print "\n"
|
965
965
|
_get(arg, options)
|
@@ -1066,7 +1066,7 @@ class Morpheus::Cli::Instances
|
|
1066
1066
|
options = {}
|
1067
1067
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1068
1068
|
opts.banner = subcommand_usage("[name]")
|
1069
|
-
build_common_options(opts, options, [:
|
1069
|
+
build_common_options(opts, options, [:json, :dry_run, :remote])
|
1070
1070
|
end
|
1071
1071
|
optparse.parse!(args)
|
1072
1072
|
if args.count < 1
|
@@ -1086,20 +1086,68 @@ class Morpheus::Cli::Instances
|
|
1086
1086
|
puts as_json(json_response, options)
|
1087
1087
|
return
|
1088
1088
|
end
|
1089
|
-
|
1089
|
+
|
1090
|
+
if json_response['backups'] && json_response['backups'][0] && json_response['backups'][0]['backupResults']
|
1091
|
+
# new format
|
1092
|
+
print_h1 "Instance Backups: #{instance['name']} (#{instance['instanceType']['name']})"
|
1090
1093
|
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1094
|
+
|
1095
|
+
backup = json_response['backups'][0]
|
1096
|
+
|
1097
|
+
description_cols = {
|
1098
|
+
"Backup ID" => lambda {|it| it['id'] },
|
1099
|
+
"Name" => lambda {|it| it['name'] },
|
1100
|
+
"Type" => lambda {|it| it['backupType'] ? (it['backupType']['name'] || it['backupType']['code']) : '' },
|
1101
|
+
"Storage" => lambda {|it| it['storageProvider'] ? it['storageProvider']['name'] : '' },
|
1102
|
+
"Schedule" => lambda {|it| it['cronDescription'] || it['cronExpression'] }
|
1103
|
+
}
|
1104
|
+
print_description_list(description_cols, backup)
|
1105
|
+
|
1106
|
+
backup_results = backup ? backup['backupResults'] : nil
|
1107
|
+
backup_rows = backup_results.collect {|it|
|
1108
|
+
status_str = it['status'].to_s.upcase
|
1109
|
+
# 'START_REQUESTED' //START_REQUESTED, IN_PROGRESS, CANCEL_REQUESTED, CANCELLED, SUCCEEDED, FAILED
|
1110
|
+
if status_str == 'SUCCEEDED'
|
1111
|
+
status_str = "#{green}#{status_str.upcase}#{cyan}"
|
1112
|
+
elsif status_str == 'FAILED'
|
1113
|
+
status_str = "#{red}#{status_str.upcase}#{cyan}"
|
1114
|
+
else
|
1115
|
+
status_str = "#{cyan}#{status_str.upcase}#{cyan}"
|
1116
|
+
end
|
1117
|
+
{id: it['id'], startDate: format_local_dt(it['dateCreated']), duration: format_duration_milliseconds(it['durationMillis']),
|
1118
|
+
size: format_bytes(it['sizeInMb'], 'MB'), status: status_str }
|
1119
|
+
}
|
1120
|
+
print_h1 "Backup Results"
|
1121
|
+
print cyan
|
1122
|
+
puts as_pretty_table backup_rows, [
|
1123
|
+
:id,
|
1124
|
+
{:startDate => {:display_name => "Started"} },
|
1125
|
+
:duration,
|
1126
|
+
:size,
|
1127
|
+
:status
|
1128
|
+
]
|
1129
|
+
print reset, "\n"
|
1130
|
+
elsif json_response['backups'].size == 0
|
1131
|
+
# no backup configured
|
1132
|
+
print_h1 "Instance Backups: #{instance['name']} (#{instance['instanceType']['name']})"
|
1133
|
+
print "#{yellow}No backups configured#{reset}\n\n"
|
1134
|
+
else
|
1135
|
+
# old format
|
1136
|
+
print_h1 "Instance Backups: #{instance['name']} (#{instance['instanceType']['name']})"
|
1137
|
+
backups = json_response['backups']
|
1138
|
+
backup_rows = backups.collect {|r|
|
1139
|
+
it = r['backup']
|
1140
|
+
{id: it['id'], name: it['name'], dateCreated: format_local_dt(it['dateCreated'])}
|
1141
|
+
}
|
1142
|
+
print cyan
|
1143
|
+
puts as_pretty_table backup_rows, [
|
1144
|
+
:id,
|
1145
|
+
:name,
|
1146
|
+
{:dateCreated => {:display_name => "Date Created"} }
|
1147
|
+
]
|
1148
|
+
print reset, "\n"
|
1149
|
+
end
|
1150
|
+
return 0
|
1103
1151
|
rescue RestClient::Exception => e
|
1104
1152
|
print_rest_exception(e, options)
|
1105
1153
|
exit 1
|
@@ -1114,23 +1162,26 @@ class Morpheus::Cli::Instances
|
|
1114
1162
|
opts.on( '-g', '--group GROUP', "Group Name or ID for the new instance" ) do |val|
|
1115
1163
|
options[:group] = val
|
1116
1164
|
end
|
1165
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID for the new instance" ) do |val|
|
1166
|
+
options[:cloud] = val
|
1167
|
+
end
|
1117
1168
|
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
1118
1169
|
end
|
1119
1170
|
optparse.parse!(args)
|
1120
1171
|
if args.count < 1
|
1121
1172
|
puts optparse
|
1122
|
-
|
1123
|
-
end
|
1124
|
-
if !options[:group]
|
1125
|
-
print_red_alert "GROUP is required."
|
1126
|
-
puts optparse
|
1127
|
-
exit 1
|
1173
|
+
return 1
|
1128
1174
|
end
|
1175
|
+
# if !options[:group]
|
1176
|
+
# print_red_alert "GROUP is required."
|
1177
|
+
# puts optparse
|
1178
|
+
# exit 1
|
1179
|
+
# end
|
1129
1180
|
connect(options)
|
1130
1181
|
begin
|
1131
1182
|
options[:options] ||= {}
|
1132
1183
|
# use the -g GROUP or active group by default
|
1133
|
-
options[:options]['group'] ||= options[:group]
|
1184
|
+
options[:options]['group'] ||= options[:group] || @active_group_id
|
1134
1185
|
# support [new-name]
|
1135
1186
|
# if args[1]
|
1136
1187
|
# options[:options]['name'] = args[1]
|
@@ -1143,6 +1194,10 @@ class Morpheus::Cli::Instances
|
|
1143
1194
|
payload.merge!(params)
|
1144
1195
|
payload['group'] = {id: group['id']}
|
1145
1196
|
|
1197
|
+
cloud = options[:cloud] ? find_zone_by_name_or_id(nil, options[:cloud]) : nil
|
1198
|
+
if cloud
|
1199
|
+
payload['cloud'] = {id: cloud['id']}
|
1200
|
+
end
|
1146
1201
|
instance = find_instance_by_name_or_id(args[0])
|
1147
1202
|
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to clone the instance '#{instance['name']}'?", options)
|
1148
1203
|
exit 1
|
@@ -1808,8 +1863,21 @@ class Morpheus::Cli::Instances
|
|
1808
1863
|
puts as_json(json_response, options)
|
1809
1864
|
return 0
|
1810
1865
|
else
|
1811
|
-
|
1812
|
-
|
1866
|
+
bad_results = []
|
1867
|
+
if json_response['results']
|
1868
|
+
json_response['results'].each do |result_id, result|
|
1869
|
+
if result['success'] != true
|
1870
|
+
bad_results << result['msg'] || "Failed to create backup for instance #{result_id}"
|
1871
|
+
end
|
1872
|
+
end
|
1873
|
+
end
|
1874
|
+
if bad_results.empty?
|
1875
|
+
print_green_success "Backup initiated."
|
1876
|
+
return 0
|
1877
|
+
else
|
1878
|
+
print_red_alert bad_results.join("\n")
|
1879
|
+
return 1
|
1880
|
+
end
|
1813
1881
|
end
|
1814
1882
|
rescue RestClient::Exception => e
|
1815
1883
|
print_rest_exception(e, options)
|
@@ -1826,10 +1894,10 @@ class Morpheus::Cli::Instances
|
|
1826
1894
|
query_params[:keepBackups] = 'on'
|
1827
1895
|
end
|
1828
1896
|
opts.on('--preserve-volumes [on|off]', ['on','off'], "Preserve Volumes. Default is off. Applies to certain types only.") do |val|
|
1829
|
-
query_params[:preserveVolumes] = val
|
1897
|
+
query_params[:preserveVolumes] = val.nil? ? 'on' : val
|
1830
1898
|
end
|
1831
1899
|
opts.on('--releaseEIPs [on|off]', ['on','off'], "Release EIPs. Default is on. Applies to Amazon only.") do |val|
|
1832
|
-
query_params[:releaseEIPs] = val
|
1900
|
+
query_params[:releaseEIPs] = val.nil? ? 'on' : val
|
1833
1901
|
end
|
1834
1902
|
opts.on( '-f', '--force', "Force Delete" ) do
|
1835
1903
|
query_params[:force] = 'on'
|
@@ -2128,7 +2196,7 @@ class Morpheus::Cli::Instances
|
|
2128
2196
|
if options[:json]
|
2129
2197
|
puts as_json(json_response, options)
|
2130
2198
|
else
|
2131
|
-
|
2199
|
+
print_green_success "Snapshot import initiated."
|
2132
2200
|
end
|
2133
2201
|
return 0
|
2134
2202
|
rescue RestClient::Exception => e
|