morpheus-cli 5.4.2 → 5.4.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/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +12 -1
- data/lib/morpheus/api/catalog_item_types_interface.rb +17 -0
- data/lib/morpheus/api/clusters_interface.rb +12 -0
- data/lib/morpheus/api/credential_types_interface.rb +9 -0
- data/lib/morpheus/api/credentials_interface.rb +9 -0
- data/lib/morpheus/api/instances_interface.rb +28 -0
- data/lib/morpheus/api/monitoring_apps_interface.rb +12 -4
- data/lib/morpheus/api/monitoring_checks_interface.rb +12 -4
- data/lib/morpheus/api/monitoring_groups_interface.rb +13 -5
- data/lib/morpheus/api/monitoring_incidents_interface.rb +12 -4
- data/lib/morpheus/api/options_interface.rb +8 -1
- data/lib/morpheus/api/ping_interface.rb +2 -0
- data/lib/morpheus/api/power_schedules_interface.rb +2 -2
- data/lib/morpheus/api/service_plans_interface.rb +6 -0
- data/lib/morpheus/api/setup_interface.rb +4 -0
- data/lib/morpheus/api/snapshots_interface.rb +19 -0
- data/lib/morpheus/cli/cli_command.rb +10 -17
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +156 -1
- data/lib/morpheus/cli/commands/clusters.rb +177 -50
- data/lib/morpheus/cli/commands/credential_types_command.rb +36 -0
- data/lib/morpheus/cli/commands/credentials_command.rb +124 -0
- data/lib/morpheus/cli/commands/hosts.rb +32 -2
- data/lib/morpheus/cli/commands/instances.rb +255 -2
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
- data/lib/morpheus/cli/commands/monitoring_apps_command.rb +8 -8
- data/lib/morpheus/cli/commands/monitoring_checks_command.rb +8 -8
- data/lib/morpheus/cli/commands/monitoring_groups_command.rb +8 -8
- data/lib/morpheus/cli/commands/monitoring_incidents_command.rb +8 -8
- data/lib/morpheus/cli/commands/network_static_routes_command.rb +5 -0
- data/lib/morpheus/cli/commands/networks_command.rb +2 -2
- data/lib/morpheus/cli/commands/ping.rb +3 -5
- data/lib/morpheus/cli/commands/policies_command.rb +1 -1
- data/lib/morpheus/cli/commands/power_schedules_command.rb +189 -258
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
- data/lib/morpheus/cli/commands/remote.rb +16 -10
- data/lib/morpheus/cli/commands/security_groups.rb +2 -2
- data/lib/morpheus/cli/commands/service_plans_command.rb +52 -5
- data/lib/morpheus/cli/commands/setup.rb +1 -1
- data/lib/morpheus/cli/commands/snapshots.rb +139 -0
- data/lib/morpheus/cli/commands/storage_server_types.rb +0 -5
- data/lib/morpheus/cli/commands/storage_servers.rb +0 -6
- data/lib/morpheus/cli/commands/storage_volume_types.rb +0 -5
- data/lib/morpheus/cli/commands/storage_volumes.rb +0 -6
- data/lib/morpheus/cli/commands/tasks.rb +5 -5
- data/lib/morpheus/cli/commands/user_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +117 -27
- data/lib/morpheus/cli/mixins/rest_command.rb +20 -4
- data/lib/morpheus/cli/mixins/storage_servers_helper.rb +0 -63
- data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +0 -43
- data/lib/morpheus/cli/option_types.rb +27 -11
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/routes.rb +13 -3
- metadata +13 -7
@@ -864,12 +864,18 @@ module Morpheus::Cli::ProvisioningHelper
|
|
864
864
|
if locked_fields.include?('volumes')
|
865
865
|
payload['volumes'] = options[:options]['volumes'] if options[:options]['volumes']
|
866
866
|
else
|
867
|
-
volumes = prompt_volumes(service_plan, options, api_client, {zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
|
867
|
+
volumes = prompt_volumes(service_plan, provision_type, options, api_client, {zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
|
868
868
|
if !volumes.empty?
|
869
869
|
payload['volumes'] = volumes
|
870
870
|
end
|
871
871
|
end
|
872
872
|
|
873
|
+
# plan customizations
|
874
|
+
plan_opts = prompt_service_plan_options(service_plan, options, api_client, {zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
|
875
|
+
if plan_opts && !plan_opts.empty?
|
876
|
+
payload['servicePlanOptions'] = plan_opts
|
877
|
+
end
|
878
|
+
|
873
879
|
# prompt networks
|
874
880
|
if locked_fields.include?('networks')
|
875
881
|
# payload['networkInterfaces'] = options[:options]['networkInterfaces'] if options[:options]['networkInterfaces']
|
@@ -906,7 +912,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
906
912
|
has_security_groups = !!sg_option_type
|
907
913
|
available_security_groups = []
|
908
914
|
if sg_option_type && sg_option_type['type'] == 'select' && sg_option_type['optionSource']
|
909
|
-
sg_option_results = options_interface.options_for_source(sg_option_type['optionSource'], sg_api_params)
|
915
|
+
sg_option_results = options_interface.options_for_source(sg_option_type['optionSource'], sg_api_params, sg_option_type['optionSourceType'])
|
910
916
|
available_security_groups = sg_option_results['data'].collect do |it|
|
911
917
|
{"id" => it["value"] || it["id"], "name" => it["name"], "value" => it["value"] || it["id"]}
|
912
918
|
end
|
@@ -1033,7 +1039,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1033
1039
|
|
1034
1040
|
# This recreates the behavior of multi_disk.js
|
1035
1041
|
# returns array of volumes based on service plan options (plan_info)
|
1036
|
-
def prompt_volumes(plan_info, options={}, api_client=nil, api_params={})
|
1042
|
+
def prompt_volumes(plan_info, provision_type, options={}, api_client=nil, api_params={})
|
1037
1043
|
#puts "Configure Volumes:"
|
1038
1044
|
# return [] if plan_info['noDisks']
|
1039
1045
|
|
@@ -1135,14 +1141,19 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1135
1141
|
volume['name'] = v_prompt[field_context]['name']
|
1136
1142
|
end
|
1137
1143
|
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
|
1138
|
-
|
1139
|
-
|
1140
|
-
volume['size'] =
|
1141
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1144
|
+
# provision_type['rootDiskSizeKnown'] == false means size cannot be changed
|
1145
|
+
if provision_type['rootDiskSizeKnown'] == false
|
1146
|
+
# volume['size'] = plan_size if plan_size.to_i != 0
|
1142
1147
|
else
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1148
|
+
if root_custom_size_options.empty?
|
1149
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => 'Root Volume Size (GB)', 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
1150
|
+
volume['size'] = v_prompt[field_context]['size']
|
1151
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
1152
|
+
else
|
1153
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => 'Root Volume Size', 'selectOptions' => root_custom_size_options, 'required' => true, 'description' => 'Choose a volume size.', 'defaultValue' => volume['sizeId']}], options[:options])
|
1154
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1155
|
+
volume['size'] = nil #volume.delete('size')
|
1156
|
+
end
|
1146
1157
|
end
|
1147
1158
|
else
|
1148
1159
|
# might need different logic here ? =o
|
@@ -1242,7 +1253,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1242
1253
|
|
1243
1254
|
# This recreates the behavior of multi_disk.js
|
1244
1255
|
# returns array of volumes based on service plan options (plan_info)
|
1245
|
-
def prompt_resize_volumes(current_volumes, plan_info, options={})
|
1256
|
+
def prompt_resize_volumes(current_volumes, plan_info, provision_type, options={})
|
1246
1257
|
#puts "Configure Volumes:"
|
1247
1258
|
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
1248
1259
|
|
@@ -1322,7 +1333,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1322
1333
|
'id' => current_root_volume['id'],
|
1323
1334
|
'rootVolume' => true,
|
1324
1335
|
'name' => current_root_volume['name'],
|
1325
|
-
'size' => current_root_volume['size'] > plan_size ? current_root_volume['size'] : plan_size,
|
1336
|
+
'size' => current_root_volume['size'] > (plan_size || 0) ? current_root_volume['size'] : plan_size,
|
1326
1337
|
'sizeId' => nil,
|
1327
1338
|
'storageType' => storage_type_id,
|
1328
1339
|
'datastoreId' => current_root_volume['datastoreId']
|
@@ -1333,19 +1344,24 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1333
1344
|
volume['name'] = v_prompt[field_context]['name']
|
1334
1345
|
end
|
1335
1346
|
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
|
1336
|
-
|
1337
|
-
|
1338
|
-
volume['size'] =
|
1339
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1347
|
+
# provision_type['rootDiskSizeKnown'] == false means size cannot be changed
|
1348
|
+
if provision_type['rootDiskSizeKnown'] == false
|
1349
|
+
# volume['size'] = plan_size if plan_size.to_i != 0
|
1340
1350
|
else
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1351
|
+
if root_custom_size_options.empty?
|
1352
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => 'Root Volume Size (GB)', 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
1353
|
+
volume['size'] = v_prompt[field_context]['size']
|
1354
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
1355
|
+
else
|
1356
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => 'Root Volume Size', 'selectOptions' => root_custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
|
1357
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1358
|
+
volume['size'] = nil #volume.delete('size')
|
1359
|
+
end
|
1344
1360
|
end
|
1345
1361
|
else
|
1346
1362
|
# might need different logic here ? =o
|
1347
|
-
volume['size'] = plan_size
|
1348
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1363
|
+
# volume['size'] = plan_size
|
1364
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1349
1365
|
end
|
1350
1366
|
# if !datastore_options.empty?
|
1351
1367
|
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => 'Root Datastore', 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
|
@@ -1373,7 +1389,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1373
1389
|
'id' => current_volume['id'].to_i,
|
1374
1390
|
'rootVolume' => false,
|
1375
1391
|
'name' => current_volume['name'],
|
1376
|
-
'size' => current_volume['size'] > plan_size ? current_volume['size'] : plan_size,
|
1392
|
+
'size' => current_volume['size'] > (plan_size || 0) ? current_volume['size'] : plan_size,
|
1377
1393
|
'sizeId' => nil,
|
1378
1394
|
'storageType' => (current_volume['type'] || current_volume['storageType']),
|
1379
1395
|
'datastoreId' => current_volume['datastoreId']
|
@@ -1398,7 +1414,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1398
1414
|
'id' => current_volume['id'].to_i,
|
1399
1415
|
'rootVolume' => false,
|
1400
1416
|
'name' => current_volume['name'],
|
1401
|
-
'size' => current_volume['size'] > plan_size ? current_volume['size'] : plan_size,
|
1417
|
+
'size' => current_volume['size'] > (plan_size || 0) ? current_volume['size'] : plan_size,
|
1402
1418
|
'sizeId' => nil,
|
1403
1419
|
'storageType' => (current_volume['type'] || current_volume['storageType']),
|
1404
1420
|
'datastoreId' => current_volume['datastoreId']
|
@@ -1420,8 +1436,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1420
1436
|
end
|
1421
1437
|
else
|
1422
1438
|
# might need different logic here ? =o
|
1423
|
-
volume['size'] = plan_size
|
1424
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1439
|
+
# volume['size'] = plan_size
|
1440
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1425
1441
|
end
|
1426
1442
|
# if !datastore_options.empty?
|
1427
1443
|
# 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])
|
@@ -1486,8 +1502,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1486
1502
|
end
|
1487
1503
|
else
|
1488
1504
|
# might need different logic here ? =o
|
1489
|
-
volume['size'] = plan_size
|
1490
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1505
|
+
# volume['size'] = plan_size
|
1506
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1491
1507
|
end
|
1492
1508
|
if !datastore_options.empty?
|
1493
1509
|
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])
|
@@ -2240,6 +2256,80 @@ module Morpheus::Cli::ProvisioningHelper
|
|
2240
2256
|
return ports
|
2241
2257
|
end
|
2242
2258
|
|
2259
|
+
def prompt_service_plan_options(plan_info, options={}, api_client=nil, api_params={}, instance=nil)
|
2260
|
+
plan_opts = {}
|
2261
|
+
# provisioning with blueprint can lock fields
|
2262
|
+
locked_fields = options[:locked_fields] || []
|
2263
|
+
if options[:options]['servicePlanOptions']
|
2264
|
+
plan_opts = options[:options]['servicePlanOptions']
|
2265
|
+
end
|
2266
|
+
default_max_cores = plan_info['maxCores'].to_i != 0 ? plan_info['maxCores'] : 1
|
2267
|
+
default_cores_per_socket = plan_info['coresPerSocket'].to_i != 0 ? plan_info['coresPerSocket'] : 1
|
2268
|
+
default_max_memory = plan_info['maxMemory'].to_i != 0 ? plan_info['maxMemory'] : nil
|
2269
|
+
# use defaults from the instance/server
|
2270
|
+
if instance
|
2271
|
+
default_max_cores = instance["maxCores"] if instance["maxCores"]
|
2272
|
+
default_cores_per_socket = instance["coresPerSocket"] if instance["coresPerSocket"]
|
2273
|
+
default_max_memory = instance["maxMemory"] if instance["maxMemory"]
|
2274
|
+
end
|
2275
|
+
# Core Count
|
2276
|
+
if plan_info["customCores"]
|
2277
|
+
if locked_fields.include?('servicePlanOptions.maxCores')
|
2278
|
+
if options[:options]['servicePlanOptions'] && options[:options]['servicePlanOptions']['maxCores']
|
2279
|
+
plan_opts['maxCores'] = options[:options]['servicePlanOptions']['maxCores'].to_i
|
2280
|
+
end
|
2281
|
+
else
|
2282
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'servicePlanOptions', 'fieldName' => 'maxCores', 'type' => 'number', 'fieldLabel' => "Core Count", 'required' => true, 'defaultValue' => default_max_cores, 'description' => "Customize service plan options Core Count"}], options[:options])
|
2283
|
+
if v_prompt['servicePlanOptions'] && v_prompt['servicePlanOptions']['maxCores']
|
2284
|
+
plan_opts['maxCores'] = v_prompt['servicePlanOptions']['maxCores'].to_i
|
2285
|
+
end
|
2286
|
+
end
|
2287
|
+
end
|
2288
|
+
# Cores Per Socket
|
2289
|
+
if plan_info["customCoresPerSocket"]
|
2290
|
+
if locked_fields.include?('servicePlanOptions.coresPerSocket')
|
2291
|
+
if options[:options]['servicePlanOptions'] && options[:options]['servicePlanOptions']['coresPerSocket']
|
2292
|
+
plan_opts['coresPerSocket'] = options[:options]['servicePlanOptions']['coresPerSocket'].to_i
|
2293
|
+
end
|
2294
|
+
else
|
2295
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'servicePlanOptions', 'fieldName' => 'coresPerSocket', 'type' => 'number', 'fieldLabel' => "Cores Per Socket", 'required' => true, 'defaultValue' => default_cores_per_socket, 'description' => "Customize service plan options Cores Per Socket"}], options[:options])
|
2296
|
+
if v_prompt['servicePlanOptions'] && v_prompt['servicePlanOptions']['coresPerSocket']
|
2297
|
+
plan_opts['coresPerSocket'] = v_prompt['servicePlanOptions']['coresPerSocket'].to_i
|
2298
|
+
end
|
2299
|
+
end
|
2300
|
+
end
|
2301
|
+
# Memory
|
2302
|
+
if plan_info["customMaxMemory"]
|
2303
|
+
if locked_fields.include?('servicePlanOptions.maxMemory')
|
2304
|
+
if options[:options]['servicePlanOptions'] && options[:options]['servicePlanOptions']['maxMemory']
|
2305
|
+
plan_opts['maxMemory'] = options[:options]['servicePlanOptions']['maxMemory'].to_i
|
2306
|
+
end
|
2307
|
+
else
|
2308
|
+
if options[:options]['servicePlanOptions'] && options[:options]['servicePlanOptions']['maxMemory']
|
2309
|
+
plan_opts['maxMemory'] = options[:options]['servicePlanOptions']['maxMemory'].to_i
|
2310
|
+
else
|
2311
|
+
# prompt for "memoryMB" field as MB or "memoryGB" in GB
|
2312
|
+
# always convert maxMemory to bytes
|
2313
|
+
if plan_info["memorySizeType"] == "MB" || options[:options]["memoryMB"]
|
2314
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'memoryMB', 'type' => 'text', 'fieldLabel' => "Memory (MB)", 'required' => true, 'defaultValue' => default_max_memory ? (default_max_memory / (1024 * 1024)) : nil, 'description' => "Customize service plan options Memory (MB). Value is in megabytes."}], options[:options])
|
2315
|
+
if v_prompt['memoryMB'].to_s != ""
|
2316
|
+
plan_opts['maxMemory'] = v_prompt['memoryMB'].to_i * 1024 * 1024
|
2317
|
+
end
|
2318
|
+
else
|
2319
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'memoryGB', 'type' => 'text', 'fieldLabel' => "Memory (GB)", 'required' => true, 'defaultValue' => default_max_memory ? (default_max_memory / (1024 * 1024 * 1024)) : nil, 'description' => "Customize service plan options Memory (GB). Value is in gigabytes."}], options[:options])
|
2320
|
+
if v_prompt['memoryGB'].to_s != ""
|
2321
|
+
plan_opts['maxMemory'] = v_prompt['memoryGB'].to_i * 1024 * 1024 * 1024
|
2322
|
+
end
|
2323
|
+
end
|
2324
|
+
# remove transient memory field just used for prompting for MB or GB
|
2325
|
+
plan_opts.delete("memoryMB")
|
2326
|
+
plan_opts.delete("memoryGB")
|
2327
|
+
end
|
2328
|
+
end
|
2329
|
+
end
|
2330
|
+
return plan_opts
|
2331
|
+
end
|
2332
|
+
|
2243
2333
|
def format_instance_status(instance, return_color=cyan)
|
2244
2334
|
out = ""
|
2245
2335
|
status_string = instance['status'].to_s
|
@@ -336,11 +336,19 @@ module Morpheus::Cli::RestCommand
|
|
336
336
|
end
|
337
337
|
|
338
338
|
def rest_object_key
|
339
|
-
|
339
|
+
if respond_to?("#{rest_key}_object_key", true)
|
340
|
+
send("#{rest_key}_object_key")
|
341
|
+
else
|
342
|
+
rest_name.camelcase.singularize
|
343
|
+
end
|
340
344
|
end
|
341
345
|
|
342
346
|
def rest_list_key
|
343
|
-
|
347
|
+
if respond_to?("#{rest_key}_list_key", true)
|
348
|
+
send("#{rest_key}_list_key")
|
349
|
+
else
|
350
|
+
rest_name.camelcase
|
351
|
+
end
|
344
352
|
end
|
345
353
|
|
346
354
|
def rest_column_definitions(options)
|
@@ -408,11 +416,19 @@ module Morpheus::Cli::RestCommand
|
|
408
416
|
end
|
409
417
|
|
410
418
|
def rest_type_object_key
|
411
|
-
|
419
|
+
if respond_to?("#{rest_type_key}_object_key", true)
|
420
|
+
send("#{rest_type_key}_object_key")
|
421
|
+
else
|
422
|
+
rest_type_name.camelcase.singularize
|
423
|
+
end
|
412
424
|
end
|
413
425
|
|
414
426
|
def rest_type_list_key
|
415
|
-
|
427
|
+
if respond_to?("#{rest_type_key}_list_key", true)
|
428
|
+
send("#{rest_type_key}_list_key")
|
429
|
+
else
|
430
|
+
rest_type_name.camelcase
|
431
|
+
end
|
416
432
|
end
|
417
433
|
|
418
434
|
def rest_type_column_definitions(options)
|
@@ -90,67 +90,4 @@ module Morpheus::Cli::StorageServersHelper
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
-
def get_available_storage_server_types(refresh=false)
|
94
|
-
if !@available_storage_server_types || refresh
|
95
|
-
@available_storage_server_types = storage_server_types_interface.list({max:1000})[storage_server_type_list_key]
|
96
|
-
end
|
97
|
-
return @available_storage_server_types
|
98
|
-
end
|
99
|
-
|
100
|
-
def storage_server_type_for_name_or_id(val)
|
101
|
-
if val.to_s =~ /\A\d{1,}\Z/
|
102
|
-
return storage_server_type_for_id(val)
|
103
|
-
else
|
104
|
-
return storage_server_type_for_name(val)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def storage_server_type_for_id(id)
|
109
|
-
return get_available_storage_server_types().find { |z| z['id'].to_i == id.to_i}
|
110
|
-
end
|
111
|
-
|
112
|
-
def storage_server_type_for_name(name)
|
113
|
-
return get_available_storage_server_types().find { |z| z['name'].downcase == name.downcase || z['code'].downcase == name.downcase}
|
114
|
-
end
|
115
|
-
|
116
|
-
def find_storage_server_type_by_name_or_id(val)
|
117
|
-
if val.to_s =~ /\A\d{1,}\Z/
|
118
|
-
return find_storage_server_type_by_id(val)
|
119
|
-
else
|
120
|
-
return find_storage_server_type_by_name(val)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def find_storage_server_type_by_id(id)
|
125
|
-
begin
|
126
|
-
json_response = storage_server_types_interface.get(id.to_i)
|
127
|
-
return json_response[storage_server_type_object_key]
|
128
|
-
rescue RestClient::Exception => e
|
129
|
-
if e.response && e.response.code == 404
|
130
|
-
print_red_alert "Storage Server Type not found by id #{id}"
|
131
|
-
return nil
|
132
|
-
else
|
133
|
-
raise e
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def find_storage_server_type_by_name(name)
|
139
|
-
json_response = storage_server_types_interface.list({name: name.to_s})
|
140
|
-
storage_server_types = json_response[storage_server_type_list_key]
|
141
|
-
if storage_server_types.empty?
|
142
|
-
print_red_alert "Storage Server Type not found by name #{name}"
|
143
|
-
return storage_server_types
|
144
|
-
elsif storage_server_types.size > 1
|
145
|
-
print_red_alert "#{storage_server_types.size} storage server types found by name #{name}"
|
146
|
-
rows = storage_server_types.collect do |it|
|
147
|
-
{id: it['id'], name: it['name']}
|
148
|
-
end
|
149
|
-
puts as_pretty_table(rows, [:id, :name], {color:red})
|
150
|
-
return nil
|
151
|
-
else
|
152
|
-
return storage_server_types[0]
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
93
|
end
|
@@ -54,49 +54,6 @@ module Morpheus::Cli::StorageVolumesHelper
|
|
54
54
|
'Storage Volume Types'
|
55
55
|
end
|
56
56
|
|
57
|
-
def get_available_storage_volume_types(refresh=false)
|
58
|
-
if !@available_storage_volume_types || refresh
|
59
|
-
@available_storage_volume_types = storage_volume_types_interface.list({max:1000})[storage_volume_type_list_key]
|
60
|
-
end
|
61
|
-
return @available_storage_volume_types
|
62
|
-
end
|
63
|
-
|
64
|
-
def storage_volume_type_for_name_or_id(val)
|
65
|
-
if val.to_s =~ /\A\d{1,}\Z/
|
66
|
-
return storage_volume_type_for_id(val)
|
67
|
-
else
|
68
|
-
return storage_volume_type_for_name(val)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def storage_volume_type_for_id(val)
|
73
|
-
record = get_available_storage_volume_types().find { |z| z['id'].to_i == val.to_i}
|
74
|
-
label = "Storage Volume Type"
|
75
|
-
if record.nil?
|
76
|
-
print_red_alert "#{label} not found by id #{val}"
|
77
|
-
return nil
|
78
|
-
end
|
79
|
-
return record
|
80
|
-
end
|
81
|
-
|
82
|
-
def storage_volume_type_for_name(val)
|
83
|
-
records = get_available_storage_volume_types().select { |z| z['name'].downcase == val.downcase || z['code'].downcase == val.downcase}
|
84
|
-
label = "Storage Volume Type"
|
85
|
-
if records.empty?
|
86
|
-
print_red_alert "#{label} not found by name '#{val}'"
|
87
|
-
return nil
|
88
|
-
elsif records.size > 1
|
89
|
-
print_red_alert "More than one #{label.downcase} found by name '#{val}'"
|
90
|
-
print_error "\n"
|
91
|
-
puts_error as_pretty_table(records, [:id, :name], {color:red})
|
92
|
-
print_red_alert "Try using ID instead"
|
93
|
-
print_error reset,"\n"
|
94
|
-
return nil
|
95
|
-
else
|
96
|
-
return records[0]
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
57
|
def format_storage_volume_status(record, return_color=cyan)
|
101
58
|
out = ""
|
102
59
|
status_string = record['status']
|
@@ -42,7 +42,7 @@ module Morpheus
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
def self.prompt(option_types, options={}, api_client=nil, api_params={}, no_prompt=false, paging_enabled=false)
|
45
|
+
def self.prompt(option_types, options={}, api_client=nil, api_params={}, no_prompt=false, paging_enabled=false, ignore_empty=false)
|
46
46
|
paging_enabled = false if Morpheus::Cli.windows?
|
47
47
|
no_prompt = no_prompt || options[:no_prompt]
|
48
48
|
results = {}
|
@@ -57,6 +57,10 @@ module Morpheus
|
|
57
57
|
if option_type['fieldGroup'].to_s.downcase == 'options'
|
58
58
|
option_type['fieldGroup'] = 'default'
|
59
59
|
end
|
60
|
+
# apply custom templates
|
61
|
+
if option_type['fieldName'] == 'sshHosts'
|
62
|
+
option_type['type'] = 'multiText'
|
63
|
+
end
|
60
64
|
end
|
61
65
|
# puts "Options Prompt #{options}"
|
62
66
|
# Sort options by default, group, advanced
|
@@ -156,7 +160,7 @@ module Morpheus
|
|
156
160
|
end
|
157
161
|
|
158
162
|
# build parameters for option source api request
|
159
|
-
option_params = (option_type['noParams'] ? {} : (api_params || {}).
|
163
|
+
option_params = (option_type['noParams'] ? {} : (api_params || {}).deep_merge(results))
|
160
164
|
option_params.merge!(option_type['optionParams']) if option_type['optionParams']
|
161
165
|
|
162
166
|
# use the value passed in the options map
|
@@ -169,14 +173,14 @@ module Morpheus
|
|
169
173
|
end
|
170
174
|
# these select prompts should just fall down through below, with the extra params no_prompt, use_value
|
171
175
|
elsif option_type['type'] == 'select'
|
172
|
-
value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, option_params, true)
|
176
|
+
value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, option_params, true, nil, false, ignore_empty)
|
173
177
|
elsif option_type['type'] == 'multiSelect'
|
174
178
|
# support value as csv like "thing1, thing2"
|
175
179
|
value_list = value.is_a?(String) ? value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [value].flatten
|
176
180
|
input_value_list = input_value.is_a?(String) ? input_value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [input_value].flatten
|
177
181
|
select_value_list = []
|
178
182
|
value_list.each_with_index do |v, i|
|
179
|
-
select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true)
|
183
|
+
select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true, nil, false, ignore_empty)
|
180
184
|
end
|
181
185
|
value = select_value_list
|
182
186
|
elsif option_type['type'] == 'typeahead'
|
@@ -213,20 +217,21 @@ module Morpheus
|
|
213
217
|
# select type is special because it supports skipSingleOption
|
214
218
|
# and prints the available options on error
|
215
219
|
if ['select', 'multiSelect'].include?(option_type['type'])
|
216
|
-
value = select_prompt(option_type, api_client, option_params, true)
|
220
|
+
value = select_prompt(option_type, api_client, option_params, true, nil, false, ignore_empty)
|
217
221
|
value_found = !!value
|
218
222
|
end
|
219
223
|
if ['typeahead', 'multiTypeahead'].include?(option_type['type'])
|
220
224
|
value = typeahead_prompt(option_type, api_client, option_params, true)
|
221
225
|
value_found = !!value
|
222
226
|
end
|
223
|
-
if !value_found
|
227
|
+
if !value_found && !ignore_empty
|
224
228
|
if option_type['required']
|
225
229
|
print Term::ANSIColor.red, "\nMissing Required Option\n\n", Term::ANSIColor.reset
|
226
230
|
print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{help_field_key}=] - #{option_type['description']}\n", Term::ANSIColor.reset
|
227
231
|
print "\n"
|
228
232
|
exit 1
|
229
233
|
else
|
234
|
+
parent_context_map.reject! {|k,v| k == parent_ns && (v.nil? || (v.is_a?(Hash) && v.empty?))}
|
230
235
|
next
|
231
236
|
end
|
232
237
|
end
|
@@ -254,11 +259,11 @@ module Morpheus
|
|
254
259
|
# I suppose the entered value should take precedence
|
255
260
|
# api_params = api_params.merge(options) # this might be good enough
|
256
261
|
# dup it
|
257
|
-
value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled)
|
262
|
+
value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
|
258
263
|
if value && option_type['type'] == 'multiSelect'
|
259
264
|
value = [value]
|
260
265
|
while self.confirm("Add another #{option_type['fieldLabel']}?", {:default => false}) do
|
261
|
-
if addn_value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled)
|
266
|
+
if addn_value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
|
262
267
|
value << addn_value
|
263
268
|
else
|
264
269
|
break
|
@@ -370,7 +375,7 @@ module Morpheus
|
|
370
375
|
Thread.current[:_last_select]
|
371
376
|
end
|
372
377
|
|
373
|
-
def self.select_prompt(option_type, api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false)
|
378
|
+
def self.select_prompt(option_type, api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false, ignore_empty=false)
|
374
379
|
paging_enabled = false if Morpheus::Cli.windows?
|
375
380
|
field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
|
376
381
|
help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
|
@@ -406,9 +411,11 @@ module Morpheus
|
|
406
411
|
select_options = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {})
|
407
412
|
end
|
408
413
|
else
|
409
|
-
raise "option '#{
|
414
|
+
raise "option '#{help_field_key}' is type: 'select' and missing selectOptions or optionSource!"
|
410
415
|
end
|
411
416
|
|
417
|
+
return nil if (select_options.nil? || select_options.count == 0) && ignore_empty
|
418
|
+
|
412
419
|
# ensure the preselected value (passed as an option) is in the dropdown
|
413
420
|
if !use_value.nil?
|
414
421
|
matched_option = select_options.find {|opt| opt[value_field].to_s == use_value.to_s || opt['name'].to_s == use_value.to_s }
|
@@ -672,6 +679,10 @@ module Morpheus
|
|
672
679
|
if select_options.empty?
|
673
680
|
print "The value '#{input}' matched 0 options.\n"
|
674
681
|
# print "Please try again.\n"
|
682
|
+
elsif select_options.size() == 1
|
683
|
+
print "The value '#{input}' matched 1 option.\n"
|
684
|
+
print "Perhaps you meant '#{select_options[0]['name']}' instead?"
|
685
|
+
# print "Please try again.\n"
|
675
686
|
else
|
676
687
|
print "The value '#{input}' matched #{select_options.size()} options.\n"
|
677
688
|
print "Perhaps you meant one of these? #{ored_list(select_options.collect {|i|i['name']}, 3)}\n"
|
@@ -686,6 +697,9 @@ module Morpheus
|
|
686
697
|
if select_options.empty?
|
687
698
|
print "The value '#{input}' matched 0 options.\n"
|
688
699
|
print "Please try again.\n"
|
700
|
+
elsif select_options.size() == 1
|
701
|
+
print "The value '#{input}' matched 1 option.\n"
|
702
|
+
print "Perhaps you meant '#{select_options[0]['name']}' instead?"
|
689
703
|
else
|
690
704
|
print "The value '#{input}' matched #{select_options.size()} options.\n"
|
691
705
|
print "Perhaps you meant one of these? #{ored_list(select_options.collect {|i|i['name']}, 3)}\n"
|
@@ -958,6 +972,8 @@ module Morpheus
|
|
958
972
|
end
|
959
973
|
|
960
974
|
def self.load_options(option_type, api_client, api_params, query_value=nil)
|
975
|
+
field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
|
976
|
+
help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
|
961
977
|
select_options = []
|
962
978
|
# local array of options
|
963
979
|
if option_type['selectOptions']
|
@@ -989,7 +1005,7 @@ module Morpheus
|
|
989
1005
|
select_options = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {})
|
990
1006
|
end
|
991
1007
|
else
|
992
|
-
raise "option '#{
|
1008
|
+
raise "option '#{help_field_key}' is type: 'typeahead' and missing selectOptions or optionSource!"
|
993
1009
|
end
|
994
1010
|
|
995
1011
|
return select_options
|
data/lib/morpheus/cli/version.rb
CHANGED
data/lib/morpheus/routes.rb
CHANGED
@@ -87,9 +87,19 @@ module Morpheus::Routes
|
|
87
87
|
:'data-stores' => {}, # ugh, should be datastores
|
88
88
|
servers: {}, # Storage Servers
|
89
89
|
},
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
trust: [
|
91
|
+
"#!credentials",
|
92
|
+
"#!certificates",
|
93
|
+
"#!keypairs",
|
94
|
+
"#!services",
|
95
|
+
],
|
96
|
+
boot: [
|
97
|
+
"#!mappings",
|
98
|
+
"#!boot-menus",
|
99
|
+
"#!answerfiles",
|
100
|
+
"#!boot-images",
|
101
|
+
"#!macs",
|
102
|
+
],
|
93
103
|
},
|
94
104
|
backups: {
|
95
105
|
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.4.
|
4
|
+
version: 5.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Estes
|
8
8
|
- Bob Whiton
|
9
9
|
- Jeremy Michael Crosbie
|
10
10
|
- James Dickson
|
11
|
-
autorequire:
|
11
|
+
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2022-
|
14
|
+
date: 2022-03-10 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -200,6 +200,8 @@ files:
|
|
200
200
|
- lib/morpheus/api/clouds_interface.rb
|
201
201
|
- lib/morpheus/api/clusters_interface.rb
|
202
202
|
- lib/morpheus/api/containers_interface.rb
|
203
|
+
- lib/morpheus/api/credential_types_interface.rb
|
204
|
+
- lib/morpheus/api/credentials_interface.rb
|
203
205
|
- lib/morpheus/api/custom_instance_types_interface.rb
|
204
206
|
- lib/morpheus/api/cypher_interface.rb
|
205
207
|
- lib/morpheus/api/dashboard_interface.rb
|
@@ -300,6 +302,7 @@ files:
|
|
300
302
|
- lib/morpheus/api/service_catalog_interface.rb
|
301
303
|
- lib/morpheus/api/service_plans_interface.rb
|
302
304
|
- lib/morpheus/api/setup_interface.rb
|
305
|
+
- lib/morpheus/api/snapshots_interface.rb
|
303
306
|
- lib/morpheus/api/storage_providers_interface.rb
|
304
307
|
- lib/morpheus/api/storage_server_types_interface.rb
|
305
308
|
- lib/morpheus/api/storage_servers_interface.rb
|
@@ -355,6 +358,8 @@ files:
|
|
355
358
|
- lib/morpheus/cli/commands/clusters.rb
|
356
359
|
- lib/morpheus/cli/commands/coloring_command.rb
|
357
360
|
- lib/morpheus/cli/commands/containers_command.rb
|
361
|
+
- lib/morpheus/cli/commands/credential_types_command.rb
|
362
|
+
- lib/morpheus/cli/commands/credentials_command.rb
|
358
363
|
- lib/morpheus/cli/commands/curl_command.rb
|
359
364
|
- lib/morpheus/cli/commands/cypher_command.rb
|
360
365
|
- lib/morpheus/cli/commands/dashboard_command.rb
|
@@ -455,6 +460,7 @@ files:
|
|
455
460
|
- lib/morpheus/cli/commands/setup.rb
|
456
461
|
- lib/morpheus/cli/commands/shell.rb
|
457
462
|
- lib/morpheus/cli/commands/sleep_command.rb
|
463
|
+
- lib/morpheus/cli/commands/snapshots.rb
|
458
464
|
- lib/morpheus/cli/commands/source_command.rb
|
459
465
|
- lib/morpheus/cli/commands/ssl_verification_command.rb
|
460
466
|
- lib/morpheus/cli/commands/storage_providers_command.rb
|
@@ -524,11 +530,11 @@ files:
|
|
524
530
|
- lib/morpheus/terminal.rb
|
525
531
|
- lib/morpheus/util.rb
|
526
532
|
- morpheus-cli.gemspec
|
527
|
-
homepage:
|
533
|
+
homepage:
|
528
534
|
licenses:
|
529
535
|
- MIT
|
530
536
|
metadata: {}
|
531
|
-
post_install_message:
|
537
|
+
post_install_message:
|
532
538
|
rdoc_options: []
|
533
539
|
require_paths:
|
534
540
|
- lib
|
@@ -543,9 +549,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
543
549
|
- !ruby/object:Gem::Version
|
544
550
|
version: '0'
|
545
551
|
requirements: []
|
546
|
-
rubyforge_project:
|
552
|
+
rubyforge_project:
|
547
553
|
rubygems_version: 2.7.6
|
548
|
-
signing_key:
|
554
|
+
signing_key:
|
549
555
|
specification_version: 4
|
550
556
|
summary: Provides CLI Interface to the Morpheus Public/Private Cloud Appliance
|
551
557
|
test_files: []
|