morpheus-cli 5.4.2 → 5.4.4
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 +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: []
|