morpheus-cli 3.6.3 → 3.6.4
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/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
|