morpheus-cli 5.5.1.5 → 5.5.2.1
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/api/api_client.rb +25 -0
- data/lib/morpheus/api/archive_buckets_interface.rb +1 -1
- data/lib/morpheus/api/body_io.rb +22 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +5 -1
- data/lib/morpheus/api/clients_interface.rb +41 -0
- data/lib/morpheus/api/clouds_interface.rb +21 -0
- data/lib/morpheus/api/instances_interface.rb +8 -1
- data/lib/morpheus/api/integrations_interface.rb +30 -0
- data/lib/morpheus/api/library_instance_types_interface.rb +15 -3
- data/lib/morpheus/api/network_pool_server_types_interface.rb +9 -0
- data/lib/morpheus/api/plugins_interface.rb +22 -0
- data/lib/morpheus/api/roles_interface.rb +20 -1
- data/lib/morpheus/api/security_package_types_interface.rb +9 -0
- data/lib/morpheus/api/security_packages_interface.rb +9 -0
- data/lib/morpheus/api/security_scans_interface.rb +9 -0
- data/lib/morpheus/api/servers_interface.rb +17 -17
- data/lib/morpheus/api/storage_providers_interface.rb +1 -1
- data/lib/morpheus/api/virtual_images_interface.rb +1 -23
- data/lib/morpheus/cli/cli_command.rb +81 -7
- data/lib/morpheus/cli/commands/apps.rb +28 -2
- data/lib/morpheus/cli/commands/archives_command.rb +2 -2
- data/lib/morpheus/cli/commands/blueprints_command.rb +16 -0
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +34 -2
- data/lib/morpheus/cli/commands/clients_command.rb +338 -0
- data/lib/morpheus/cli/commands/clouds.rb +127 -1
- data/lib/morpheus/cli/commands/clusters.rb +42 -12
- data/lib/morpheus/cli/commands/curl_command.rb +114 -135
- data/lib/morpheus/cli/commands/hosts.rb +108 -11
- data/lib/morpheus/cli/commands/instances.rb +115 -14
- data/lib/morpheus/cli/commands/integrations_command.rb +215 -4
- data/lib/morpheus/cli/commands/invoices_command.rb +20 -11
- data/lib/morpheus/cli/commands/jobs_command.rb +299 -190
- data/lib/morpheus/cli/commands/library_cluster_layouts_command.rb +16 -2
- data/lib/morpheus/cli/commands/library_container_scripts_command.rb +14 -0
- data/lib/morpheus/cli/commands/library_container_templates_command.rb +131 -48
- data/lib/morpheus/cli/commands/library_container_types_command.rb +17 -4
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +85 -7
- data/lib/morpheus/cli/commands/library_layouts_command.rb +32 -1
- data/lib/morpheus/cli/commands/library_option_lists_command.rb +30 -18
- data/lib/morpheus/cli/commands/library_option_types_command.rb +31 -14
- data/lib/morpheus/cli/commands/library_spec_templates_command.rb +14 -0
- data/lib/morpheus/cli/commands/library_upgrades_command.rb +2 -2
- data/lib/morpheus/cli/commands/network_pool_server_types.rb +20 -0
- data/lib/morpheus/cli/commands/network_pool_servers_command.rb +55 -158
- data/lib/morpheus/cli/commands/network_pools_command.rb +49 -23
- data/lib/morpheus/cli/commands/networks_command.rb +262 -45
- data/lib/morpheus/cli/commands/plugins.rb +213 -0
- data/lib/morpheus/cli/commands/price_sets_command.rb +27 -8
- data/lib/morpheus/cli/commands/prices_command.rb +17 -5
- data/lib/morpheus/cli/commands/processes_command.rb +2 -1
- data/lib/morpheus/cli/commands/remote.rb +7 -10
- data/lib/morpheus/cli/commands/roles.rb +924 -335
- data/lib/morpheus/cli/commands/search_command.rb +2 -0
- data/lib/morpheus/cli/commands/security_groups.rb +72 -84
- data/lib/morpheus/cli/commands/security_package_types.rb +32 -0
- data/lib/morpheus/cli/commands/security_packages.rb +84 -0
- data/lib/morpheus/cli/commands/security_scans.rb +107 -0
- data/lib/morpheus/cli/commands/service_plans_command.rb +16 -14
- data/lib/morpheus/cli/commands/subnets_command.rb +15 -1
- data/lib/morpheus/cli/commands/tasks.rb +34 -1
- data/lib/morpheus/cli/commands/tenants_command.rb +1 -1
- data/lib/morpheus/cli/commands/user_settings_command.rb +11 -2
- data/lib/morpheus/cli/commands/users.rb +50 -9
- data/lib/morpheus/cli/commands/virtual_images.rb +14 -0
- data/lib/morpheus/cli/commands/workflows.rb +14 -0
- data/lib/morpheus/cli/mixins/accounts_helper.rb +6 -5
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +79 -0
- data/lib/morpheus/cli/mixins/jobs_helper.rb +4 -5
- data/lib/morpheus/cli/mixins/library_helper.rb +2 -0
- data/lib/morpheus/cli/mixins/logs_helper.rb +3 -0
- data/lib/morpheus/cli/mixins/monitoring_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +29 -4
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +38 -9
- data/lib/morpheus/cli/mixins/rest_command.rb +106 -8
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +6 -2
- data/lib/morpheus/cli/option_types.rb +94 -25
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.rb +10 -1
- metadata +15 -2
@@ -57,6 +57,10 @@ module Morpheus::Cli::ProvisioningHelper
|
|
57
57
|
@api_client.accounts
|
58
58
|
end
|
59
59
|
|
60
|
+
def datastores_interface
|
61
|
+
@api_client.datastores
|
62
|
+
end
|
63
|
+
|
60
64
|
def get_available_groups(params = {}, refresh=false)
|
61
65
|
if !@available_groups || refresh
|
62
66
|
option_results = options_interface.options_for_source('groups', params)
|
@@ -601,11 +605,13 @@ module Morpheus::Cli::ProvisioningHelper
|
|
601
605
|
payload['instance']['instanceContext'] = v_prompt['environment'] if !v_prompt['environment'].empty?
|
602
606
|
|
603
607
|
# Labels (used to be called tags)
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
608
|
+
unless options[:skip_labels_prompt]
|
609
|
+
if options[:labels]
|
610
|
+
payload['instance']['labels'] = options[:labels].is_a?(Array) ? options[:labels] : options[:labels].to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq
|
611
|
+
else
|
612
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false, 'defaultValue' => options[:default_labels]}], options[:options])
|
613
|
+
payload['instance']['labels'] = v_prompt['labels'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['labels'].empty?
|
614
|
+
end
|
609
615
|
end
|
610
616
|
|
611
617
|
# Version and Layout
|
@@ -634,6 +640,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
634
640
|
version_value = options[:options]['version']
|
635
641
|
else
|
636
642
|
available_versions = options_interface.options_for_source('instanceVersions',{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})['data']
|
643
|
+
# filter versions with no layouts.. api should probably do that too eh?
|
644
|
+
available_versions.reject! { |available_version| available_version["layouts"].nil? || available_version["layouts"].empty? }
|
637
645
|
default_version_value = payload['instance']['version'] ? payload['instance']['version'] : payload['version']
|
638
646
|
#default_layout_value = options[:layout]
|
639
647
|
if default_layout_value.nil?
|
@@ -953,6 +961,14 @@ module Morpheus::Cli::ProvisioningHelper
|
|
953
961
|
api_params['config'] = payload['config'] if payload['config']
|
954
962
|
api_params['poolId'] = payload['config']['resourcePoolId'] if payload['config'] && payload['config']['resourcePoolId']
|
955
963
|
api_params['resourcePoolId'] = api_params['poolId']
|
964
|
+
# some option sources expect networkIntefaces passed as networkInterfaceIds[] eg. oraclecloudAvailabilityDomains
|
965
|
+
if payload['networkInterfaces']
|
966
|
+
begin
|
967
|
+
api_params['networkInterfaceIds[]'] = payload['networkInterfaces'].collect {|it| it['network']['id'] }
|
968
|
+
rescue => netex
|
969
|
+
Morpheus::Logging::DarkPrinter.puts "Unable to parse networkInterfaces parameter" if Morpheus::Logging.debug?
|
970
|
+
end
|
971
|
+
end
|
956
972
|
|
957
973
|
# set option type defaults from config
|
958
974
|
if options[:default_config]
|
@@ -1338,7 +1354,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1338
1354
|
'id' => current_root_volume['id'],
|
1339
1355
|
'rootVolume' => true,
|
1340
1356
|
'name' => current_root_volume['name'],
|
1341
|
-
'size' => current_root_volume['size'] >
|
1357
|
+
'size' => current_root_volume['size'] > 0 ? current_root_volume['size'] : plan_size,
|
1342
1358
|
'sizeId' => nil,
|
1343
1359
|
'storageType' => storage_type_id,
|
1344
1360
|
'datastoreId' => current_root_volume['datastoreId']
|
@@ -1464,9 +1480,11 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1464
1480
|
while add_another_volume do
|
1465
1481
|
#puts "Configure Data #{volume_index} Volume"
|
1466
1482
|
|
1483
|
+
current_root_volume_type = current_root_volume['type']
|
1484
|
+
storage_type_match = storage_types.find {|type| type['value'] == current_root_volume_type}
|
1485
|
+
default_storage_type = storage_type_match ? current_root_volume_type : storage_types[0]['value']
|
1467
1486
|
field_context = "dataVolume#{volume_index}"
|
1468
|
-
|
1469
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'defaultFirstOption' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
|
1487
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'defaultValue' => default_storage_type, 'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'defaultFirstOption' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
|
1470
1488
|
storage_type_id = v_prompt[field_context]['storageType']
|
1471
1489
|
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
1472
1490
|
|
@@ -1510,8 +1528,19 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1510
1528
|
# volume['size'] = plan_size
|
1511
1529
|
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1512
1530
|
end
|
1531
|
+
|
1532
|
+
if datastore_options.empty? && storage_type['hasDatastore'] != false
|
1533
|
+
begin
|
1534
|
+
datastore_res = datastores_interface.list({'resourcePoolId' => current_root_volume['resourcePoolId'], 'zoneId' => options['zoneId'], 'siteId' => options['siteId']})['datastores']
|
1535
|
+
datastore_res.each do |opt|
|
1536
|
+
datastore_options << {'name' => opt['name'], 'value' => opt['id']}
|
1537
|
+
end
|
1538
|
+
rescue
|
1539
|
+
datastore_options = []
|
1540
|
+
end
|
1541
|
+
end
|
1513
1542
|
if !datastore_options.empty?
|
1514
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Datastore", 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
|
1543
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'defaultValue' => current_root_volume['datastoreId'],'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Datastore", 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
|
1515
1544
|
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1516
1545
|
end
|
1517
1546
|
|
@@ -425,10 +425,6 @@ module Morpheus::Cli::RestCommand
|
|
425
425
|
self.class.rest_type_arg
|
426
426
|
end
|
427
427
|
|
428
|
-
def rest_has_name
|
429
|
-
self.class.rest_type_arg
|
430
|
-
end
|
431
|
-
|
432
428
|
def rest_type_label
|
433
429
|
self.class.rest_type_label
|
434
430
|
end
|
@@ -524,7 +520,10 @@ EOT
|
|
524
520
|
json_response = rest_interface.list(params)
|
525
521
|
render_response(json_response, options, rest_list_key) do
|
526
522
|
records = json_response[rest_list_key]
|
527
|
-
|
523
|
+
title = "Morpheus #{rest_label_plural}"
|
524
|
+
subtitles = []
|
525
|
+
subtitles += parse_list_subtitles(options)
|
526
|
+
print_h1 title, subtitles, options
|
528
527
|
if records.nil? || records.empty?
|
529
528
|
print cyan,"No #{rest_label_plural.downcase} found.",reset,"\n"
|
530
529
|
else
|
@@ -586,7 +585,7 @@ EOT
|
|
586
585
|
# print_description_list(config.keys, config)
|
587
586
|
# end
|
588
587
|
# Option Types
|
589
|
-
if record['optionTypes'] && record['optionTypes'].size > 0
|
588
|
+
if record['optionTypes'] && record['optionTypes'].sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.size > 0
|
590
589
|
print_h2 "Option Types", options
|
591
590
|
print format_option_types_table(record['optionTypes'], options, rest_object_key)
|
592
591
|
end
|
@@ -603,7 +602,11 @@ EOT
|
|
603
602
|
advanced_option_types = respond_to?("add_#{rest_key}_advanced_option_types", true) ? send("add_#{rest_key}_advanced_option_types") : []
|
604
603
|
type_option_type = option_types.find {|it| it['fieldName'] == 'type'}
|
605
604
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
606
|
-
|
605
|
+
if rest_has_name
|
606
|
+
opts.banner = subcommand_usage("[name]")
|
607
|
+
else
|
608
|
+
opts.banner = subcommand_usage()
|
609
|
+
end
|
607
610
|
if rest_has_type && type_option_type.nil?
|
608
611
|
opts.on( '-t', "--#{rest_type_arg} TYPE", "#{rest_type_label}" ) do |val|
|
609
612
|
record_type_id = val
|
@@ -614,7 +617,7 @@ EOT
|
|
614
617
|
build_standard_add_options(opts, options)
|
615
618
|
opts.footer = <<-EOT
|
616
619
|
Create a new #{rest_label.downcase}.
|
617
|
-
[
|
620
|
+
[name] is required. This is the name of the new #{rest_label.downcase}.
|
618
621
|
EOT
|
619
622
|
opts.footer += send "add_#{rest_key}_footer_addn" if respond_to?("add_#{rest_key}_footer_addn", true)
|
620
623
|
end
|
@@ -888,5 +891,100 @@ EOT
|
|
888
891
|
return 0, nil
|
889
892
|
end
|
890
893
|
|
894
|
+
def list_types(args)
|
895
|
+
params = {}
|
896
|
+
options = {}
|
897
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
898
|
+
opts.banner = subcommand_usage("[search]")
|
899
|
+
build_list_options(opts, options, params)
|
900
|
+
opts.footer = <<-EOT
|
901
|
+
List #{rest_type_label_plural.downcase}.
|
902
|
+
[search] is optional. This is a search phrase to filter the results.
|
903
|
+
EOT
|
904
|
+
end
|
905
|
+
optparse.parse!(args)
|
906
|
+
connect(options)
|
907
|
+
parse_list_options!(args, options, params)
|
908
|
+
rest_type_interface.setopts(options)
|
909
|
+
if options[:dry_run]
|
910
|
+
print_dry_run rest_type_interface.dry.list(params)
|
911
|
+
return
|
912
|
+
end
|
913
|
+
json_response = rest_type_interface.list(params)
|
914
|
+
render_response(json_response, options, rest_type_list_key) do
|
915
|
+
records = json_response[rest_type_list_key]
|
916
|
+
title = "Morpheus #{rest_type_label_plural}"
|
917
|
+
subtitles = []
|
918
|
+
subtitles += parse_list_subtitles(options)
|
919
|
+
print_h1 title, subtitles, options
|
920
|
+
if records.nil? || records.empty?
|
921
|
+
print cyan,"No #{rest_type_label_plural.downcase} found.",reset,"\n"
|
922
|
+
else
|
923
|
+
print as_pretty_table(records, rest_type_list_column_definitions(options).upcase_keys!, options)
|
924
|
+
print_results_pagination(json_response) if json_response['meta']
|
925
|
+
end
|
926
|
+
print reset,"\n"
|
927
|
+
end
|
928
|
+
return 0, nil
|
929
|
+
end
|
930
|
+
|
931
|
+
def get_type(args)
|
932
|
+
params = {}
|
933
|
+
options = {}
|
934
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
935
|
+
opts.banner = subcommand_usage("[#{rest_type_arg}]")
|
936
|
+
build_get_options(opts, options, params)
|
937
|
+
opts.footer = <<-EOT
|
938
|
+
Get details about #{a_or_an(rest_type_label)} #{rest_type_label.downcase}.
|
939
|
+
[#{rest_type_arg}] is required. This is the name or id of #{a_or_an(rest_type_label)} #{rest_type_label.downcase}.
|
940
|
+
EOT
|
941
|
+
end
|
942
|
+
optparse.parse!(args)
|
943
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
944
|
+
connect(options)
|
945
|
+
parse_get_options!(args, options, params)
|
946
|
+
id = args.join(" ")
|
947
|
+
_get_type(id, params, options)
|
948
|
+
end
|
949
|
+
|
950
|
+
def _get_type(id, params, options)
|
951
|
+
if id !~ /\A\d{1,}\Z/ # && rest_type_has_name
|
952
|
+
record = rest_type_find_by_name_or_id(id)
|
953
|
+
if record.nil?
|
954
|
+
return 1, "#{rest_type_label} not found for '#{id}'"
|
955
|
+
end
|
956
|
+
id = record['id']
|
957
|
+
end
|
958
|
+
rest_type_interface.setopts(options)
|
959
|
+
if options[:dry_run]
|
960
|
+
print_dry_run rest_type_interface.dry.get(id, params)
|
961
|
+
return
|
962
|
+
end
|
963
|
+
json_response = rest_type_interface.get(id, params)
|
964
|
+
render_response_for_get_type(json_response, options)
|
965
|
+
return 0, nil
|
966
|
+
end
|
967
|
+
|
968
|
+
def render_response_for_get_type(json_response, options)
|
969
|
+
render_response(json_response, options, rest_type_object_key) do
|
970
|
+
record = json_response[rest_type_object_key]
|
971
|
+
print_h1 rest_type_label, [], options
|
972
|
+
print cyan
|
973
|
+
print_description_list(rest_type_column_definitions(options), record, options)
|
974
|
+
# # could always show config eh? or maybe only with --config if that is nicer.
|
975
|
+
# # config = record['config'].is_a?(Hash) && !record['config'].empty?
|
976
|
+
# if config && !config.empty?
|
977
|
+
# print_h2 "Configuration"
|
978
|
+
# print_description_list(config.keys, config)
|
979
|
+
# end
|
980
|
+
# Option Types
|
981
|
+
if record['optionTypes'] && record['optionTypes'].sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.size > 0
|
982
|
+
print_h2 "Option Types", options
|
983
|
+
print format_option_types_table(record['optionTypes'], options, rest_object_key)
|
984
|
+
end
|
985
|
+
print reset,"\n"
|
986
|
+
end
|
987
|
+
end
|
988
|
+
|
891
989
|
end
|
892
990
|
|
@@ -369,7 +369,11 @@ EOT
|
|
369
369
|
advanced_option_types = respond_to?("add_#{rest_key}_advanced_option_types", true) ? send("add_#{rest_key}_advanced_option_types") : []
|
370
370
|
type_option_type = option_types.find {|it| it['fieldName'] == 'type'}
|
371
371
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
372
|
-
|
372
|
+
if rest_has_name
|
373
|
+
opts.banner = subcommand_usage("[#{rest_parent_arg}] [name]")
|
374
|
+
else
|
375
|
+
opts.banner = subcommand_usage("[#{rest_parent_arg}]")
|
376
|
+
end
|
373
377
|
if rest_has_type && type_option_type.nil?
|
374
378
|
opts.on( '-t', "--#{rest_type_arg} TYPE", "#{rest_type_label}" ) do |val|
|
375
379
|
record_type_id = val
|
@@ -381,7 +385,7 @@ EOT
|
|
381
385
|
opts.footer = <<-EOT
|
382
386
|
Create a new #{rest_label.downcase}.
|
383
387
|
[#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
384
|
-
[
|
388
|
+
[name] is required. This is the name of the new #{rest_label.downcase}.
|
385
389
|
EOT
|
386
390
|
end
|
387
391
|
optparse.parse!(args)
|
@@ -75,6 +75,10 @@ module Morpheus
|
|
75
75
|
|
76
76
|
# puts "Options Prompt #{options}"
|
77
77
|
# Sort options by default, group, advanced
|
78
|
+
# add displayOrder if it's missing, so it doesn't end up using a random order
|
79
|
+
if !option_types.find {|it| it['displayOrder'] }
|
80
|
+
option_types.each_with_index {|it, i| it['displayOrder'] = i+1 }
|
81
|
+
end
|
78
82
|
cur_field_group = 'default'
|
79
83
|
prompt_local_credentials = true
|
80
84
|
self.sort_option_types(option_types.reject {|it| it[:for_help_only]}).each do |option_type|
|
@@ -86,7 +90,7 @@ module Morpheus
|
|
86
90
|
|
87
91
|
if cur_field_group != field_group
|
88
92
|
cur_field_group = field_group
|
89
|
-
if !no_prompt
|
93
|
+
if !no_prompt && option_type['noPrompt'] != true
|
90
94
|
print "\n#{cur_field_group.upcase} OPTIONS\n#{"=" * ("#{cur_field_group} OPTIONS".length)}\n\n"
|
91
95
|
end
|
92
96
|
end
|
@@ -114,8 +118,11 @@ module Morpheus
|
|
114
118
|
if !option_type['visibleOnCode'].to_s.empty?
|
115
119
|
visible_option_check_value = option_type['visibleOnCode']
|
116
120
|
end
|
117
|
-
|
118
|
-
|
121
|
+
# adding a slight hack for dependencies on the network component since its not an option type
|
122
|
+
extra_option_params = {}
|
123
|
+
if visible_option_check_value == 'networkInterfaces'
|
124
|
+
# extra_option_params["networkInterfaceIds[]"] = []
|
125
|
+
elsif !visible_option_check_value.to_s.empty?
|
119
126
|
match_type = 'any'
|
120
127
|
|
121
128
|
if visible_option_check_value.include?('::')
|
@@ -161,6 +168,7 @@ module Morpheus
|
|
161
168
|
# build parameters for option source api request
|
162
169
|
option_params = (option_type['noParams'] ? {} : (api_params || {}).deep_merge(results))
|
163
170
|
option_params.merge!(option_type['optionParams']) if option_type['optionParams']
|
171
|
+
# option_params.merge!(extra_option_params) if extra_option_params && !extra_option_params.empty?
|
164
172
|
|
165
173
|
cur_namespace = options
|
166
174
|
parent_context_map = context_map
|
@@ -243,7 +251,7 @@ module Morpheus
|
|
243
251
|
end
|
244
252
|
# no_prompt means skip prompting and instead
|
245
253
|
# use default value or error if a required option is not present
|
246
|
-
if no_prompt
|
254
|
+
if no_prompt || option_type['noPrompt'] == true
|
247
255
|
if !value_found
|
248
256
|
if option_type['defaultValue'] != nil && !['select', 'multiSelect','typeahead','multiTypeahead'].include?(option_type['type'])
|
249
257
|
value = option_type['defaultValue']
|
@@ -356,6 +364,11 @@ module Morpheus
|
|
356
364
|
end
|
357
365
|
end
|
358
366
|
|
367
|
+
# --labels x,y,z uses processValue proc to convert strings to an array
|
368
|
+
if option_type['processValue'].is_a?(Proc)
|
369
|
+
value = option_type['processValue'].call(value)
|
370
|
+
end
|
371
|
+
|
359
372
|
if option_type['type'] == 'multiSelect'
|
360
373
|
value = [value] if !value.nil? && !value.is_a?(Array)
|
361
374
|
elsif option_type['type'] == 'multiText'
|
@@ -474,7 +487,22 @@ module Morpheus
|
|
474
487
|
|
475
488
|
# ensure the preselected value (passed as an option) is in the dropdown
|
476
489
|
if !use_value.nil?
|
477
|
-
matched_option = select_options.find {|
|
490
|
+
matched_option = select_options.find {|it| it[value_field].to_s == use_value.to_s }
|
491
|
+
if matched_option.nil?
|
492
|
+
matched_options = select_options.select {|it| opt['name'].to_s == use_value.to_s }
|
493
|
+
if matched_options.size > 1
|
494
|
+
print Term::ANSIColor.red, "\nInvalid Option #{option_type['fieldLabel']}: [#{use_value}]\n\n", Term::ANSIColor.reset
|
495
|
+
print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
|
496
|
+
display_select_options(option_type, matched_options)
|
497
|
+
print "The value '#{input}' matched #{matched_options.size()} options.\n"
|
498
|
+
# print "Perhaps you meant one of these? #{ored_list(matched_options.collect {|i|i[value_field]}, 3)}\n"
|
499
|
+
print "Try using value instead of name.\n"
|
500
|
+
print "\n"
|
501
|
+
exit 1
|
502
|
+
elsif matched_options.size == 1
|
503
|
+
matched_option = matched_options[0]
|
504
|
+
end
|
505
|
+
end
|
478
506
|
if !matched_option.nil?
|
479
507
|
value = matched_option[value_field]
|
480
508
|
value_found = true
|
@@ -522,10 +550,39 @@ module Morpheus
|
|
522
550
|
|
523
551
|
if no_prompt
|
524
552
|
if !value_found
|
525
|
-
if !default_value.nil? && !select_options.nil?
|
526
|
-
|
527
|
-
|
528
|
-
|
553
|
+
if !default_value.nil? && !select_options.nil?
|
554
|
+
matched_option = select_options.find {|it| it[value_field].to_s == default_value.to_s }
|
555
|
+
if matched_option.nil?
|
556
|
+
matched_options = select_options.select {|it| it['name'].to_s == default_value.to_s }
|
557
|
+
if matched_options.size > 1
|
558
|
+
print Term::ANSIColor.red, "\nInvalid Option #{option_type['fieldLabel']}: [#{default_value}]\n\n", Term::ANSIColor.reset
|
559
|
+
print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
|
560
|
+
display_select_options(option_type, matched_options)
|
561
|
+
print "The value '#{default_value}' matched #{matched_options.size()} options.\n"
|
562
|
+
# print "Perhaps you meant one of these? #{ored_list(matched_options.collect {|i|i[value_field]}, 3)}\n"
|
563
|
+
print "Try using value instead of name.\n"
|
564
|
+
print "\n"
|
565
|
+
exit 1
|
566
|
+
elsif matched_options.size == 1
|
567
|
+
matched_option = matched_options[0]
|
568
|
+
end
|
569
|
+
end
|
570
|
+
if !matched_option.nil?
|
571
|
+
value = matched_option[value_field]
|
572
|
+
value_found = true
|
573
|
+
else
|
574
|
+
print Term::ANSIColor.red, "\nInvalid Option #{option_type['fieldLabel']}: [#{default_value}]\n\n", Term::ANSIColor.reset
|
575
|
+
print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
|
576
|
+
if select_options && select_options.size > 10
|
577
|
+
display_select_options(option_type, select_options.first(10))
|
578
|
+
puts " (#{select_options.size-10} more)"
|
579
|
+
else
|
580
|
+
display_select_options(option_type, select_options)
|
581
|
+
end
|
582
|
+
print "\n"
|
583
|
+
exit 1
|
584
|
+
end
|
585
|
+
elsif !select_options.nil? && select_options.count > 0 && option_type['autoPickOption'] == true
|
529
586
|
value_found = true
|
530
587
|
value = select_options[0][value_field]
|
531
588
|
elsif option_type['required']
|
@@ -577,10 +634,26 @@ module Morpheus
|
|
577
634
|
if input.empty? && default_value
|
578
635
|
input = default_value.to_s
|
579
636
|
end
|
580
|
-
|
581
|
-
if
|
582
|
-
|
583
|
-
|
637
|
+
matched_option = select_options.find{|it| (!it['value'].nil? && it['value'].to_s == input) || (!it[value_field].nil? && it[value_field].to_s == input) || (it[value_field].nil? && input.empty?)}
|
638
|
+
if matched_option.nil?
|
639
|
+
matched_options = select_options.select {|it| it['name'] == input } # should probably be case insensitive
|
640
|
+
if matched_options.size > 1
|
641
|
+
print Term::ANSIColor.red, "\nInvalid Option #{option_type['fieldLabel']}: [#{input}]\n\n", Term::ANSIColor.reset
|
642
|
+
print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
|
643
|
+
display_select_options(option_type, matched_options)
|
644
|
+
print "The value '#{input}' matched #{matched_options.size()} options.\n"
|
645
|
+
# print "Perhaps you meant one of these? #{ored_list(matched_options.collect {|i|i[value_field]}, 3)}\n"
|
646
|
+
print "Try using value instead of name.\n"
|
647
|
+
print "\n"
|
648
|
+
exit 1
|
649
|
+
elsif matched_options.size == 1
|
650
|
+
matched_option = matched_options[0]
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
if matched_option
|
655
|
+
value = matched_option[value_field]
|
656
|
+
set_last_select(matched_option)
|
584
657
|
elsif !input.nil? && !input.to_s.empty?
|
585
658
|
input = '?'
|
586
659
|
end
|
@@ -780,32 +853,28 @@ module Morpheus
|
|
780
853
|
value
|
781
854
|
end
|
782
855
|
|
783
|
-
# this is a funky one, the user is prompted for yes/no
|
784
|
-
# but the return value is 'on','off',nil
|
785
|
-
# todo: maybe make this easier to use, and have the api's be flexible too..
|
786
|
-
# @param option_type [Hash] option type object with type,fieldName,fieldLabel,etc..
|
787
|
-
# @return 'on', 'off' or nil
|
788
856
|
def self.checkbox_prompt(option_type)
|
789
857
|
value_found = false
|
790
858
|
value = nil
|
791
859
|
has_default = option_type['defaultValue'] != nil
|
792
|
-
|
860
|
+
default_on = has_default ? ['on', 'true', 'yes', '1'].include?(option_type['defaultValue'].to_s.downcase) : false
|
793
861
|
while !value_found do
|
794
|
-
print "#{option_type['fieldLabel']} (
|
862
|
+
print "#{option_type['fieldLabel']} (on/off)#{has_default ? ' ['+(default_on ? 'on' : 'off')+']' : ''}: "
|
795
863
|
input = $stdin.gets.chomp!
|
796
864
|
if input == '?'
|
797
865
|
help_prompt(option_type)
|
798
866
|
next
|
799
867
|
end
|
800
|
-
|
868
|
+
check_value = input.downcase.strip
|
869
|
+
if check_value == 'yes' || check_value == 'y' || check_value == 'on' || check_value == 'true' || check_value == '1'
|
801
870
|
value_found = true
|
802
871
|
value = 'on'
|
803
|
-
elsif
|
872
|
+
elsif check_value == 'no' || check_value == 'n' || check_value == 'off' || check_value == 'true' || check_value == '0'
|
804
873
|
value_found = true
|
805
874
|
value = 'off'
|
806
875
|
elsif input == '' && has_default
|
807
876
|
value_found = true
|
808
|
-
value =
|
877
|
+
value = default_on ? 'on' : 'off'
|
809
878
|
elsif input != ""
|
810
879
|
puts "Invalid Option... Please try again."
|
811
880
|
next
|
@@ -1170,6 +1239,7 @@ module Morpheus
|
|
1170
1239
|
def self.format_select_options_help(opt, select_options = [], paging = nil)
|
1171
1240
|
out = ""
|
1172
1241
|
header = opt['fieldLabel'] ? "#{opt['fieldLabel']} Options" : "Options"
|
1242
|
+
value_field = (opt['config'] ? opt['config']['valueField'] : nil) || 'value'
|
1173
1243
|
if paging
|
1174
1244
|
offset = paging[:cur_page] * paging[:page_size]
|
1175
1245
|
limit = [offset + paging[:page_size], select_options.count].min - 1
|
@@ -1180,9 +1250,8 @@ module Morpheus
|
|
1180
1250
|
out << "\n"
|
1181
1251
|
out << "#{header}\n"
|
1182
1252
|
out << "#{'=' * header.length}\n"
|
1183
|
-
|
1184
1253
|
select_options.each do |option|
|
1185
|
-
out << (option['isGroup'] ? "- #{option['name']}\n" : " * #{option['name']} [#{option[
|
1254
|
+
out << (option['isGroup'] ? "- #{option['name']}\n" : " * #{option['name']} [#{option[value_field]}]\n")
|
1186
1255
|
end
|
1187
1256
|
return out
|
1188
1257
|
end
|
data/lib/morpheus/cli/version.rb
CHANGED
data/lib/morpheus/formatters.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'time'
|
2
2
|
require 'filesize'
|
3
3
|
require 'money'
|
4
|
+
require 'cgi'
|
4
5
|
|
5
6
|
DEFAULT_DATE_FORMAT = "%x"
|
6
7
|
DEFAULT_TIME_FORMAT = "%x %I:%M %p"
|
@@ -366,7 +367,11 @@ def format_number(n, opts={})
|
|
366
367
|
decimal = parts[1] ? parts[1..-1].join('.') : nil
|
367
368
|
i = 0
|
368
369
|
whole_number.reverse.each_char do |c|
|
369
|
-
|
370
|
+
if c == "-"
|
371
|
+
out = "#{c}#{out}"
|
372
|
+
else
|
373
|
+
out = (i > 0 && i % 3 == 0) ? "#{c}#{delim}#{out}" : "#{c}#{out}"
|
374
|
+
end
|
370
375
|
i+= 1
|
371
376
|
end
|
372
377
|
if decimal
|
@@ -488,3 +493,7 @@ def format_ok_status(status)
|
|
488
493
|
end
|
489
494
|
"#{color}#{status.to_s.upcase}#{cyan}"
|
490
495
|
end
|
496
|
+
|
497
|
+
def escape_filepath(filepath)
|
498
|
+
filepath.to_s.split("/").select {|it| !it.to_s.empty? }.collect {|it| CGI::escape(it) }.join("/")
|
499
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.5.1
|
4
|
+
version: 5.5.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Estes
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2022-
|
14
|
+
date: 2022-11-23 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -191,10 +191,12 @@ files:
|
|
191
191
|
- lib/morpheus/api/backups_interface.rb
|
192
192
|
- lib/morpheus/api/billing_interface.rb
|
193
193
|
- lib/morpheus/api/blueprints_interface.rb
|
194
|
+
- lib/morpheus/api/body_io.rb
|
194
195
|
- lib/morpheus/api/budgets_interface.rb
|
195
196
|
- lib/morpheus/api/catalog_item_types_interface.rb
|
196
197
|
- lib/morpheus/api/certificate_types_interface.rb
|
197
198
|
- lib/morpheus/api/certificates_interface.rb
|
199
|
+
- lib/morpheus/api/clients_interface.rb
|
198
200
|
- lib/morpheus/api/cloud_datastores_interface.rb
|
199
201
|
- lib/morpheus/api/cloud_folders_interface.rb
|
200
202
|
- lib/morpheus/api/cloud_policies_interface.rb
|
@@ -264,6 +266,7 @@ files:
|
|
264
266
|
- lib/morpheus/api/network_edge_clusters_interface.rb
|
265
267
|
- lib/morpheus/api/network_groups_interface.rb
|
266
268
|
- lib/morpheus/api/network_pool_ips_interface.rb
|
269
|
+
- lib/morpheus/api/network_pool_server_types_interface.rb
|
267
270
|
- lib/morpheus/api/network_pool_servers_interface.rb
|
268
271
|
- lib/morpheus/api/network_pools_interface.rb
|
269
272
|
- lib/morpheus/api/network_proxies_interface.rb
|
@@ -280,6 +283,7 @@ files:
|
|
280
283
|
- lib/morpheus/api/options_interface.rb
|
281
284
|
- lib/morpheus/api/packages_interface.rb
|
282
285
|
- lib/morpheus/api/ping_interface.rb
|
286
|
+
- lib/morpheus/api/plugins_interface.rb
|
283
287
|
- lib/morpheus/api/policies_interface.rb
|
284
288
|
- lib/morpheus/api/power_schedules_interface.rb
|
285
289
|
- lib/morpheus/api/price_sets_interface.rb
|
@@ -300,6 +304,9 @@ files:
|
|
300
304
|
- lib/morpheus/api/secondary_rest_interface.rb
|
301
305
|
- lib/morpheus/api/security_group_rules_interface.rb
|
302
306
|
- lib/morpheus/api/security_groups_interface.rb
|
307
|
+
- lib/morpheus/api/security_package_types_interface.rb
|
308
|
+
- lib/morpheus/api/security_packages_interface.rb
|
309
|
+
- lib/morpheus/api/security_scans_interface.rb
|
303
310
|
- lib/morpheus/api/server_types_interface.rb
|
304
311
|
- lib/morpheus/api/servers_interface.rb
|
305
312
|
- lib/morpheus/api/service_catalog_interface.rb
|
@@ -355,6 +362,7 @@ files:
|
|
355
362
|
- lib/morpheus/cli/commands/catalog_item_types_command.rb
|
356
363
|
- lib/morpheus/cli/commands/certificates_command.rb
|
357
364
|
- lib/morpheus/cli/commands/change_password_command.rb
|
365
|
+
- lib/morpheus/cli/commands/clients_command.rb
|
358
366
|
- lib/morpheus/cli/commands/cloud_datastores_command.rb
|
359
367
|
- lib/morpheus/cli/commands/cloud_folders_command.rb
|
360
368
|
- lib/morpheus/cli/commands/cloud_resource_pools_command.rb
|
@@ -429,6 +437,7 @@ files:
|
|
429
437
|
- lib/morpheus/cli/commands/network_edge_clusters_command.rb
|
430
438
|
- lib/morpheus/cli/commands/network_firewalls_command.rb
|
431
439
|
- lib/morpheus/cli/commands/network_groups_command.rb
|
440
|
+
- lib/morpheus/cli/commands/network_pool_server_types.rb
|
432
441
|
- lib/morpheus/cli/commands/network_pool_servers_command.rb
|
433
442
|
- lib/morpheus/cli/commands/network_pools_command.rb
|
434
443
|
- lib/morpheus/cli/commands/network_proxies_command.rb
|
@@ -441,6 +450,7 @@ files:
|
|
441
450
|
- lib/morpheus/cli/commands/options.rb
|
442
451
|
- lib/morpheus/cli/commands/packages_command.rb
|
443
452
|
- lib/morpheus/cli/commands/ping.rb
|
453
|
+
- lib/morpheus/cli/commands/plugins.rb
|
444
454
|
- lib/morpheus/cli/commands/policies_command.rb
|
445
455
|
- lib/morpheus/cli/commands/power_schedules_command.rb
|
446
456
|
- lib/morpheus/cli/commands/preseed_scripts_command.rb
|
@@ -459,6 +469,9 @@ files:
|
|
459
469
|
- lib/morpheus/cli/commands/search_command.rb
|
460
470
|
- lib/morpheus/cli/commands/security_group_rules.rb
|
461
471
|
- lib/morpheus/cli/commands/security_groups.rb
|
472
|
+
- lib/morpheus/cli/commands/security_package_types.rb
|
473
|
+
- lib/morpheus/cli/commands/security_packages.rb
|
474
|
+
- lib/morpheus/cli/commands/security_scans.rb
|
462
475
|
- lib/morpheus/cli/commands/service_catalog_command.rb
|
463
476
|
- lib/morpheus/cli/commands/service_plans_command.rb
|
464
477
|
- lib/morpheus/cli/commands/set_prompt_command.rb
|