morpheus-cli 8.0.1 → 8.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/cli/cli_command.rb +18 -3
- data/lib/morpheus/cli/commands/clusters.rb +48 -11
- data/lib/morpheus/cli/commands/hosts.rb +9 -3
- data/lib/morpheus/cli/commands/instances.rb +17 -3
- data/lib/morpheus/cli/commands/library_cluster_layouts_command.rb +1 -1
- data/lib/morpheus/cli/commands/shell.rb +18 -39
- data/lib/morpheus/cli/commands/virtual_images.rb +71 -17
- data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -324
- data/lib/morpheus/cli/version.rb +1 -1
- data/test/cli/auth_test.rb +6 -0
- data/test/cli/roles_test.rb +15 -2
- data/test/test_case.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06ea65156f0a57e7af971494347aae4844608a6cb877087dc9394a127841a75e
|
4
|
+
data.tar.gz: a93ddec1dc9e647e23a111a168126dbfc3b683d04844731f5bc53a461305b140
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ca9b136bd006211eed46cd89103c2e7af9157d8111595f4e90b09a7a1e014570405256d64401c78311503e3d4b0aaecf5690526b2014985d79c515e0093eba3
|
7
|
+
data.tar.gz: f1355c6ec99b7a05e068e215ba4581a75a712bef545b661a04e7a31ad0b1711071d7f65c316e938171da60d66d0a297898068f5efb70e750a7dc987b2f12014e
|
data/Dockerfile
CHANGED
@@ -1278,7 +1278,7 @@ module Morpheus
|
|
1278
1278
|
elsif options[:remote_url]
|
1279
1279
|
credentials = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url)
|
1280
1280
|
unless options[:skip_login]
|
1281
|
-
@wallet = credentials.request_credentials(options, @do_save_credentials)
|
1281
|
+
@wallet = credentials.request_credentials(options.merge({dry_run:false}), @do_save_credentials)
|
1282
1282
|
end
|
1283
1283
|
else
|
1284
1284
|
credentials = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url)
|
@@ -1293,7 +1293,7 @@ module Morpheus
|
|
1293
1293
|
|
1294
1294
|
if @wallet.nil? || @wallet['access_token'].nil?
|
1295
1295
|
unless options[:skip_login]
|
1296
|
-
@wallet = credentials.request_credentials(options, @do_save_credentials)
|
1296
|
+
@wallet = credentials.request_credentials(options.merge({dry_run:false}), @do_save_credentials)
|
1297
1297
|
end
|
1298
1298
|
end
|
1299
1299
|
|
@@ -1767,7 +1767,22 @@ module Morpheus
|
|
1767
1767
|
output = records.collect { |record|
|
1768
1768
|
options[:select_fields].collect { |field|
|
1769
1769
|
value = get_object_value(record, field)
|
1770
|
-
value.is_a?(String)
|
1770
|
+
if value.is_a?(String)
|
1771
|
+
value
|
1772
|
+
else
|
1773
|
+
if options[:json]
|
1774
|
+
as_json(value, options)
|
1775
|
+
elsif options[:yaml]
|
1776
|
+
output = as_yaml(value, options)
|
1777
|
+
elsif options[:csv]
|
1778
|
+
as_csv(value, nil, options)
|
1779
|
+
else
|
1780
|
+
# default behavior
|
1781
|
+
# value.is_a?(String) ? value : as_json(value, options)
|
1782
|
+
do_pretty = options.key?(:pretty_json) ? options[:pretty_json] : false # or true?
|
1783
|
+
do_pretty ? JSON.pretty_generate(value) : JSON.fast_generate(value)
|
1784
|
+
end
|
1785
|
+
end
|
1771
1786
|
}.join(options[:delim] || ",")
|
1772
1787
|
}.join(options[:newline] || "\n")
|
1773
1788
|
elsif options[:json]
|
@@ -6,6 +6,7 @@ class Morpheus::Cli::Clusters
|
|
6
6
|
include Morpheus::Cli::ProcessesHelper
|
7
7
|
include Morpheus::Cli::WhoamiHelper
|
8
8
|
include Morpheus::Cli::AccountsHelper
|
9
|
+
include Morpheus::Cli::ExecutionRequestHelper
|
9
10
|
|
10
11
|
register_subcommands :list, :count, :get, :view, :add, :update, :remove, :logs, :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details}
|
11
12
|
register_subcommands :list_workers, :add_worker, :remove_worker, :update_worker_count
|
@@ -607,7 +608,7 @@ class Morpheus::Cli::Clusters
|
|
607
608
|
end
|
608
609
|
|
609
610
|
# Controller type
|
610
|
-
server_types = @server_types_interface.list({computeTypeId: cluster_type['controllerTypes'].first['id'], zoneTypeId: cloud['zoneType']['id'], useZoneProvisionTypes: true})['serverTypes'].reject {|it| it['provisionType']['code'] == 'manual'}
|
611
|
+
server_types = @server_types_interface.list({computeTypeId: cluster_type['controllerTypes'].first['id'], zoneTypeId: cloud['zoneType']['id'], useZoneProvisionTypes: true})['serverTypes'].reject {|it| it['provisionType']['code'] == 'manual'} unless ['kubernetes-cluster', 'mvm-cluster'].include?(cluster_type_code)
|
611
612
|
controller_provision_type = nil
|
612
613
|
resource_pool = nil
|
613
614
|
|
@@ -802,6 +803,9 @@ class Morpheus::Cli::Clusters
|
|
802
803
|
opts.on('--managed [on|off]', String, "Can be used to enable / disable managed cluster. Default is on") do |val|
|
803
804
|
options[:managed] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
804
805
|
end
|
806
|
+
opts.on('--useAgent [on|off]', String, "Use the Agent to relay communications for the Kubernetes API instead of direct.") do |val|
|
807
|
+
options[:useAgent] = val.to_s
|
808
|
+
end
|
805
809
|
opts.on('--autoRecoverPowerState [on|off]', String, "Automatically Power On VMs") do |val|
|
806
810
|
options[:autoRecoverPowerState] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
807
811
|
end
|
@@ -855,6 +859,7 @@ class Morpheus::Cli::Clusters
|
|
855
859
|
cluster_payload['refresh'] = options[:refresh] if options[:refresh] == true
|
856
860
|
cluster_payload['tenant'] = options[:tenant] if !options[:tenant].nil?
|
857
861
|
cluster_payload['integrations'] = options[:integrations] if !options[:integrations].nil?
|
862
|
+
cluster_payload['useAgent'] = options[:useAgent] if !options[:useAgent].nil?
|
858
863
|
payload = {"cluster" => cluster_payload}
|
859
864
|
end
|
860
865
|
|
@@ -3004,6 +3009,12 @@ class Morpheus::Cli::Clusters
|
|
3004
3009
|
options = {}
|
3005
3010
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3006
3011
|
opts.banner = subcommand_usage( "[cluster] [options]")
|
3012
|
+
opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
|
3013
|
+
options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
|
3014
|
+
end
|
3015
|
+
opts.on(nil, '--no-refresh', "Do not refresh" ) do
|
3016
|
+
options[:no_refresh] = true
|
3017
|
+
end
|
3007
3018
|
build_option_type_options(opts, options, add_datastore_option_types)
|
3008
3019
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
3009
3020
|
opts.footer = "Add datastore to a cluster.\n" +
|
@@ -3059,11 +3070,19 @@ class Morpheus::Cli::Clusters
|
|
3059
3070
|
json_response = @clusters_interface.create_datastore(cluster['id'], payload)
|
3060
3071
|
if options[:json]
|
3061
3072
|
puts as_json(json_response)
|
3062
|
-
|
3063
|
-
if json_response['
|
3064
|
-
|
3073
|
+
else
|
3074
|
+
if json_response['success']
|
3075
|
+
if json_response['msg'] == nil
|
3076
|
+
print_green_success "Adding datastore to cluster #{cluster['name']}"
|
3077
|
+
else
|
3078
|
+
print_green_success json_response['msg']
|
3079
|
+
end
|
3080
|
+
execution_id = json_response['executionId']
|
3081
|
+
if !options[:no_refresh] && execution_id
|
3082
|
+
wait_for_execution_request(json_response['executionId'], options.merge({waiting_status:['new', 'pending', 'executing']}))
|
3083
|
+
end
|
3065
3084
|
else
|
3066
|
-
|
3085
|
+
print_red_alert "Failed to create cluster datastore #{json_response['msg']}"
|
3067
3086
|
end
|
3068
3087
|
end
|
3069
3088
|
return 0
|
@@ -3074,6 +3093,7 @@ class Morpheus::Cli::Clusters
|
|
3074
3093
|
end
|
3075
3094
|
|
3076
3095
|
def remove_datastore(args)
|
3096
|
+
default_refresh_interval = 5
|
3077
3097
|
params = {}
|
3078
3098
|
options = {}
|
3079
3099
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
@@ -3081,6 +3101,12 @@ class Morpheus::Cli::Clusters
|
|
3081
3101
|
opts.on( '-f', '--force', "Force Delete" ) do
|
3082
3102
|
params[:force] = 'on'
|
3083
3103
|
end
|
3104
|
+
opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
|
3105
|
+
options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
|
3106
|
+
end
|
3107
|
+
opts.on(nil, '--no-refresh', "Do not refresh" ) do
|
3108
|
+
options[:no_refresh] = true
|
3109
|
+
end
|
3084
3110
|
build_standard_remove_options(opts, options)
|
3085
3111
|
opts.footer = "Delete a datastore from a cluster.\n" +
|
3086
3112
|
"[cluster] is required. This is the name or id of an existing cluster.\n" +
|
@@ -3114,12 +3140,18 @@ class Morpheus::Cli::Clusters
|
|
3114
3140
|
return
|
3115
3141
|
end
|
3116
3142
|
json_response = @clusters_interface.destroy_datastore(cluster['id'], datastore['id'], params)
|
3117
|
-
|
3118
|
-
|
3119
|
-
|
3120
|
-
|
3143
|
+
if options[:json]
|
3144
|
+
puts as_json(json_response)
|
3145
|
+
else
|
3146
|
+
if json_response['success']
|
3147
|
+
print_green_success "Datastore #{datastore['name']} is being removed from cluster #{cluster['name']}"
|
3148
|
+
execution_id = json_response['executionId']
|
3149
|
+
if !options[:no_refresh] && execution_id
|
3150
|
+
wait_for_execution_request(execution_id, options.merge({waiting_status:['new', 'pending', 'executing']}))
|
3151
|
+
end
|
3152
|
+
else
|
3153
|
+
print_red_alert "Failed to remove cluster datastore #{json_response['msg']}"
|
3121
3154
|
end
|
3122
|
-
print_green_success msg
|
3123
3155
|
end
|
3124
3156
|
return 0, nil
|
3125
3157
|
end
|
@@ -4535,7 +4567,12 @@ class Morpheus::Cli::Clusters
|
|
4535
4567
|
elsif resource_pool_options.count > 1 && !options[:no_prompt]
|
4536
4568
|
resource_pool_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'resourcePool', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.'}],options[:options],api_client, {})['resourcePool']
|
4537
4569
|
else
|
4538
|
-
|
4570
|
+
first_option = resource_pool_options.find {|it| !it['id'].nil? }
|
4571
|
+
if first_option.nil?
|
4572
|
+
print_red_alert "Cloud #{cloud['name']} has no available resource pools"
|
4573
|
+
exit 1
|
4574
|
+
end
|
4575
|
+
resource_pool_id = first_option['id']
|
4539
4576
|
end
|
4540
4577
|
if resource_pool_id.to_s["poolGroup-"]
|
4541
4578
|
resource_pool = @resource_pool_groups_interface.get(resource_pool_id)['resourcePoolGroup']
|
@@ -1337,14 +1337,20 @@ class Morpheus::Cli::Hosts
|
|
1337
1337
|
payload[:server][:plan] = {id: service_plan["id"]}
|
1338
1338
|
|
1339
1339
|
# fetch volumes
|
1340
|
-
|
1341
|
-
|
1340
|
+
current_volumes = nil
|
1341
|
+
if server['volumes']
|
1342
|
+
current_volumes = server['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
1343
|
+
else
|
1344
|
+
volumes_response = @servers_interface.volumes(server['id'])
|
1345
|
+
current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
1346
|
+
end
|
1342
1347
|
|
1343
1348
|
# prompt for volumes
|
1344
1349
|
vol_options = options
|
1345
1350
|
vol_options['siteId'] = group_id
|
1346
1351
|
vol_options['zoneId'] = cloud_id
|
1347
|
-
|
1352
|
+
vol_options['resourcePoolId'] = server['resourcePool']['id'] if server['resourcePool']
|
1353
|
+
volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options, server)
|
1348
1354
|
if !volumes.empty?
|
1349
1355
|
payload[:volumes] = volumes
|
1350
1356
|
end
|
@@ -2756,7 +2756,10 @@ class Morpheus::Cli::Instances
|
|
2756
2756
|
connect(options)
|
2757
2757
|
instance = find_instance_by_name_or_id(args[0])
|
2758
2758
|
return 1, "instance not found" if instance.nil?
|
2759
|
-
|
2759
|
+
# need to load full instance details in case fetched by name
|
2760
|
+
if instance['containerDetails'].nil?
|
2761
|
+
instance = find_instance_by_id(instance['id'])
|
2762
|
+
end
|
2760
2763
|
payload = {}
|
2761
2764
|
if options[:payload]
|
2762
2765
|
payload = options[:payload]
|
@@ -2811,13 +2814,24 @@ class Morpheus::Cli::Instances
|
|
2811
2814
|
payload["instance"]["plan"] = {"id" => service_plan["id"]}
|
2812
2815
|
|
2813
2816
|
volumes_response = @instances_interface.volumes(instance['id'])
|
2814
|
-
current_volumes =
|
2817
|
+
current_volumes = nil
|
2815
2818
|
|
2816
2819
|
# prompt for volumes
|
2817
2820
|
vol_options = options
|
2818
2821
|
vol_options['siteId'] = group_id
|
2819
2822
|
vol_options['zoneId'] = cloud_id
|
2820
|
-
|
2823
|
+
vol_options['resourcePoolId'] = resource_pool_id # server['resourcePool']['id'] if server['resourcePool']
|
2824
|
+
server = instance['containerDetails'][0]['server'] rescue nil
|
2825
|
+
if server.nil?
|
2826
|
+
Morpheus::Logging::DarkPrinter.puts "Failed to load server info"
|
2827
|
+
volumes_response = @instances_interface.volumes(instance['id'])
|
2828
|
+
current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
2829
|
+
else
|
2830
|
+
# or just use instance['volumes'] ?
|
2831
|
+
current_volumes = server['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
2832
|
+
end
|
2833
|
+
vol_options['resourcePoolId'] = server['resourcePool']['id'] if server && server['resourcePool']
|
2834
|
+
volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options, server)
|
2821
2835
|
if !volumes.empty?
|
2822
2836
|
payload["volumes"] = volumes
|
2823
2837
|
end
|
@@ -845,7 +845,7 @@ class Morpheus::Cli::LibraryClusterLayoutsCommand
|
|
845
845
|
end
|
846
846
|
|
847
847
|
def find_layout_by_name(name)
|
848
|
-
layouts = @library_cluster_layouts_interface.list(
|
848
|
+
layouts = @library_cluster_layouts_interface.list({name: name.to_s})['layouts']
|
849
849
|
if layouts.empty?
|
850
850
|
print_red_alert "Cluster layout not found by name #{name}"
|
851
851
|
return nil
|
@@ -635,8 +635,8 @@ class Morpheus::Cli::Shell
|
|
635
635
|
# @return Hash like {:commands => [], :command_count => total}
|
636
636
|
def load_history_commands(options={})
|
637
637
|
phrase = options[:phrase]
|
638
|
-
sort_key = options[:sort] ? options[:sort].to_sym : nil
|
639
|
-
|
638
|
+
#sort_key = options[:sort] ? options[:sort].to_sym : nil
|
639
|
+
#direction = options[:direction] # default sort is reversed to get newest first
|
640
640
|
offset = options[:offset].to_i > 0 ? options[:offset].to_i : 0
|
641
641
|
max = options[:max].to_i > 0 ? options[:max].to_i : 25
|
642
642
|
|
@@ -648,40 +648,21 @@ class Morpheus::Cli::Shell
|
|
648
648
|
# collect records as [{:number => 1, :command => "instances list"}, etc]
|
649
649
|
history_records = []
|
650
650
|
history_count = 0
|
651
|
-
|
652
|
-
# sort is a bit different for this command, the default sort is by number
|
653
|
-
# it sorts oldest -> newest, but shows the very last page by default.
|
654
|
-
if options[:sort] && ![:number, :command].include?(options[:sort])
|
655
|
-
sort_key = :number # nil
|
656
|
-
end
|
657
651
|
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
history_records = history_records.sort {|x,y| x[sort_key] <=> y[sort_key] }
|
666
|
-
end
|
667
|
-
if phrase
|
668
|
-
history_records = history_records.select {|it| it[:command].include?(phrase) || it[:number].to_s == phrase }
|
669
|
-
end
|
670
|
-
command_count = history_records.size
|
671
|
-
history_records = history_records[offset..(max-1)]
|
672
|
-
else
|
673
|
-
# default should try to be as fast as possible..
|
674
|
-
# no searching or sorting, default order by :number works
|
675
|
-
if offset != 0
|
676
|
-
cmd_numbers = @history.keys.last(max + offset).first(max)
|
677
|
-
else
|
678
|
-
cmd_numbers = @history.keys.last(max)
|
679
|
-
end
|
680
|
-
history_records = cmd_numbers.collect { |k| {number: k, command: @history[k]} }
|
681
|
-
command_count = @history.size
|
652
|
+
# only go so far back in command history, 1 million commands
|
653
|
+
# this could be a large object...need to index our shell_history file lol
|
654
|
+
# todo: this max needs to be done in load_history_from_log_file()
|
655
|
+
history_keys = @history.keys.last(1000000).reverse
|
656
|
+
# filter by phrase
|
657
|
+
if phrase
|
658
|
+
history_keys = history_keys.select {|k| (@history[k] && @history[k].include?(phrase)) || k.to_s == phrase }
|
682
659
|
end
|
660
|
+
# no offset, just max
|
661
|
+
history_records = history_keys.first(max).collect { |k| {number: k, command: @history[k]} }
|
662
|
+
command_count = history_keys.size
|
663
|
+
|
683
664
|
meta = {size:history_records.size, total:command_count.to_i, max:max, offset:offset}
|
684
|
-
return {:
|
665
|
+
return {commands: history_records, command_count: command_count, meta: meta}
|
685
666
|
end
|
686
667
|
|
687
668
|
def print_history(options={})
|
@@ -696,16 +677,14 @@ class Morpheus::Cli::Shell
|
|
696
677
|
end
|
697
678
|
else
|
698
679
|
print cyan
|
680
|
+
# by default show old->new as the shell history should bash history
|
681
|
+
history_records.reverse! unless options[:direction] == "desc"
|
699
682
|
history_records.each do |history_record|
|
700
683
|
puts "#{history_record[:number].to_s.rjust(3, ' ')} #{history_record[:command]}"
|
701
684
|
end
|
702
685
|
if options[:show_pagination]
|
703
|
-
|
704
|
-
|
705
|
-
else
|
706
|
-
# default order is weird, it's the last page of results, 1-25 is misleading and showing the indexes is stranger
|
707
|
-
print_results_pagination(history_result[:meta], {:message =>"Viewing most recent %{size} of %{total} %{label}"})
|
708
|
-
end
|
686
|
+
pagination_msg = options[:phrase] ? "Viewing most recent %{size} of %{total} commands matching '#{options[:phrase]}'" : "Viewing most recent %{size} of %{total} commands"
|
687
|
+
print_results_pagination(history_result[:meta], {:message =>pagination_msg})
|
709
688
|
print reset, "\n"
|
710
689
|
else
|
711
690
|
print reset
|
@@ -172,11 +172,8 @@ EOT
|
|
172
172
|
id
|
173
173
|
else
|
174
174
|
image = find_virtual_image_by_name_or_id(id)
|
175
|
-
if image
|
176
|
-
|
177
|
-
else
|
178
|
-
raise_command_error "virtual image not found for name '#{id}'"
|
179
|
-
end
|
175
|
+
return 1, "virtual image not found for name '#{id}'" if image.nil?
|
176
|
+
image['id']
|
180
177
|
end
|
181
178
|
end
|
182
179
|
return run_command_for_each_arg(id_list) do |arg|
|
@@ -383,15 +380,16 @@ EOT
|
|
383
380
|
# storageProviderId, format, name
|
384
381
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
385
382
|
opts.banner = subcommand_usage("[image] [options]")
|
386
|
-
opts.on('-n', '--name NAME', String, "Name (optional) of the new converted image. Default is name of the original image.") do |val|
|
387
|
-
|
388
|
-
end
|
389
|
-
opts.on('-f', '--format FORMAT', String, "Format (optional). Default is 'qcow2'") do |val|
|
390
|
-
|
391
|
-
end
|
392
|
-
opts.on('--storageProvider VALUE', String, "Storage Provider ID (optional). Default is storage provider of the original image.") do |val|
|
393
|
-
|
394
|
-
end
|
383
|
+
# opts.on('-n', '--name NAME', String, "Name (optional) of the new converted image. Default is name of the original image.") do |val|
|
384
|
+
# options[:options]['name'] = val
|
385
|
+
# end
|
386
|
+
# opts.on('-f', '--format FORMAT', String, "Format (optional). Default is 'qcow2'") do |val|
|
387
|
+
# options[:options]['format'] = val
|
388
|
+
# end
|
389
|
+
# opts.on('--storageProvider VALUE', String, "Storage Provider ID (optional). Default is storage provider of the original image.") do |val|
|
390
|
+
# options[:options]['storageProvider'] = val.to_s
|
391
|
+
# end
|
392
|
+
build_option_type_options(opts, options, convert_virtual_image_option_types)
|
395
393
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
396
394
|
opts.footer = "Convert a virtual image to a new format." + "\n" +
|
397
395
|
"[image] is required. This is the name or id of a virtual image."
|
@@ -411,7 +409,18 @@ EOT
|
|
411
409
|
payload.deep_merge!({virtual_image_object_key => passed_options}) unless passed_options.empty?
|
412
410
|
else
|
413
411
|
virtual_image_payload = passed_options
|
414
|
-
|
412
|
+
source_format = virtual_image['imageType']
|
413
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(convert_virtual_image_option_types(source_format), options[:options], @api_client, {'virtualImageId': virtual_image['id']})
|
414
|
+
v_prompt.deep_compact!
|
415
|
+
virtual_image_payload.deep_merge!(v_prompt)
|
416
|
+
# support "storageProviderId" too
|
417
|
+
if virtual_image_payload['storageProviderId']
|
418
|
+
virtual_image_payload['storageProvider'] = virtual_image_payload.delete('storageProviderId')
|
419
|
+
end
|
420
|
+
# convert "storageProvider":1 to "storageProvider": {"id":1}
|
421
|
+
if virtual_image_payload['storageProvider'] && !virtual_image_payload['storageProvider'].is_a?(Hash)
|
422
|
+
virtual_image_payload['storageProvider'] = {'id' => virtual_image_payload['storageProvider'].to_i }
|
423
|
+
end
|
415
424
|
payload = virtual_image_payload
|
416
425
|
end
|
417
426
|
@virtual_images_interface.setopts(options)
|
@@ -990,11 +999,20 @@ EOT
|
|
990
999
|
|
991
1000
|
def find_virtual_image_by_name(name)
|
992
1001
|
json_results = @virtual_images_interface.list({name: name.to_s})
|
993
|
-
|
1002
|
+
records = json_results['virtualImages']
|
1003
|
+
if records.empty?
|
994
1004
|
print_red_alert "Virtual Image not found by name #{name}"
|
995
1005
|
return nil
|
1006
|
+
elsif records.size > 1
|
1007
|
+
print_red_alert "More than one Virtual Image found by name '#{name}'"
|
1008
|
+
print_error "\n"
|
1009
|
+
puts_error as_pretty_table(records, [:id, :name], {color:red})
|
1010
|
+
print_red_alert "Try using ID instead"
|
1011
|
+
print_error reset,"\n"
|
1012
|
+
return nil
|
1013
|
+
else
|
1014
|
+
virtual_image = records[0]
|
996
1015
|
end
|
997
|
-
virtual_image = json_results['virtualImages'][0]
|
998
1016
|
return virtual_image
|
999
1017
|
end
|
1000
1018
|
|
@@ -1074,6 +1092,42 @@ EOT
|
|
1074
1092
|
list
|
1075
1093
|
end
|
1076
1094
|
|
1095
|
+
def convert_virtual_image_option_types(source_format=nil)
|
1096
|
+
[
|
1097
|
+
{'shorthand' => '-f', 'fieldName' => 'format', 'type' => 'select', 'fieldLabel' => 'Format', 'selectOptions' => get_convert_image_formats(source_format), 'required' => true, 'defaultValue' => (source_format == 'qcow2' ? nil : 'qcow2')},
|
1098
|
+
{'shorthand' => '-b', 'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Bucket', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider Bucket or File Share.'},
|
1099
|
+
{'shorthand' => '-n', 'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false}
|
1100
|
+
]
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
def convert_source_types
|
1104
|
+
["raw","qcow2","vmdk",'vmware', "vhd","ovf"]
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
def convert_destination_types
|
1108
|
+
#["raw", "qcow2", "vmdk",'vmware',"vhd","ovf"]
|
1109
|
+
convert_source_types
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def get_convert_image_formats(source_format=nil)
|
1113
|
+
categories = [
|
1114
|
+
{'name' => 'QCOW2', 'value' => 'qcow2'},
|
1115
|
+
{'name' => 'VMDK', 'value' => 'ovf'},
|
1116
|
+
{'name' => 'VHD', 'value' => 'vhd'},
|
1117
|
+
{'name' => 'Raw', 'value' => 'raw'}
|
1118
|
+
]
|
1119
|
+
# if source format (imageType) is not in the list, then no options
|
1120
|
+
# else reject the current value
|
1121
|
+
if source_format
|
1122
|
+
if !convert_source_types.include?(source_format.to_s.downcase)
|
1123
|
+
categories = []
|
1124
|
+
else
|
1125
|
+
categories = categories.select {|it| it['value'] != source_format.to_s.downcase }
|
1126
|
+
end
|
1127
|
+
end
|
1128
|
+
return categories
|
1129
|
+
end
|
1130
|
+
|
1077
1131
|
def format_tenants(accounts)
|
1078
1132
|
if accounts && accounts.size > 0
|
1079
1133
|
accounts = accounts.sort {|a,b| a['name'] <=> b['name'] }.uniq {|it| it['id'] }
|
@@ -29,7 +29,7 @@ module Morpheus::Cli::ExecutionRequestHelper
|
|
29
29
|
# unless options[:quiet]
|
30
30
|
# print cyan, "Execution request has not yet finished. Refreshing every #{refresh_display_seconds} seconds...", "\n", reset
|
31
31
|
# end
|
32
|
-
while
|
32
|
+
while (options[:waiting_status] || ['new', 'pending']).include?(execution_request['status']) do
|
33
33
|
sleep(refresh_interval)
|
34
34
|
execution_request = execution_request_interface.get(execution_request_id)['executionRequest']
|
35
35
|
end
|