morpheus-cli 8.0.0 → 8.0.2
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/appliance_settings_interface.rb +7 -0
- data/lib/morpheus/api/virtual_images_interface.rb +6 -0
- data/lib/morpheus/cli/cli_command.rb +18 -3
- data/lib/morpheus/cli/commands/appliance_settings_command.rb +21 -2
- data/lib/morpheus/cli/commands/apps.rb +1 -1
- data/lib/morpheus/cli/commands/clouds.rb +1 -1
- data/lib/morpheus/cli/commands/clusters.rb +48 -11
- data/lib/morpheus/cli/commands/hosts.rb +9 -3
- data/lib/morpheus/cli/commands/instances.rb +17 -3
- data/lib/morpheus/cli/commands/library_cluster_layouts_command.rb +1 -1
- data/lib/morpheus/cli/commands/shell.rb +18 -39
- data/lib/morpheus/cli/commands/virtual_images.rb +117 -13
- data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +4 -2
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +542 -330
- data/lib/morpheus/cli/version.rb +1 -1
- data/test/cli/auth_test.rb +6 -0
- data/test/cli/roles_test.rb +15 -2
- data/test/test_case.rb +1 -0
- metadata +2 -2
@@ -508,16 +508,17 @@ module Morpheus::Cli::ProvisioningHelper
|
|
508
508
|
|
509
509
|
while instance_name.nil? do
|
510
510
|
name_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Instance Name', 'type' => 'text', 'required' => options[:name_required], 'defaultValue' => options[:default_name]}], options[:options])
|
511
|
-
|
512
|
-
if
|
511
|
+
name = name_prompt['name']
|
512
|
+
if name.nil? && !options[:name_required]
|
513
513
|
break
|
514
514
|
else
|
515
|
-
if instances_interface.list({name:
|
516
|
-
instance_name =
|
515
|
+
if instances_interface.list({name: name})['instances'].empty?
|
516
|
+
instance_name = name
|
517
517
|
else
|
518
|
-
print_red_alert "Name must be unique"
|
518
|
+
print_red_alert "Name must be unique, #{name} already exists"
|
519
|
+
options[:options].delete('name')
|
519
520
|
exit 1 if no_prompt
|
520
|
-
if options[:default_name] ==
|
521
|
+
if options[:default_name] == name
|
521
522
|
options[:default_name] += '-2'
|
522
523
|
end
|
523
524
|
end
|
@@ -796,7 +797,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
796
797
|
resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{}, no_prompt, true)
|
797
798
|
resource_pool_prompt.deep_compact!
|
798
799
|
payload.deep_merge!(resource_pool_prompt)
|
799
|
-
|
800
|
+
# this results in the layout, not the resourcePool for some reason...
|
801
|
+
#resource_pool = Morpheus::Cli::OptionTypes.get_last_select()
|
800
802
|
if resource_pool_option_type['fieldContext'] && resource_pool_prompt[resource_pool_option_type['fieldContext']]
|
801
803
|
pool_id = resource_pool_prompt[resource_pool_option_type['fieldContext']][resource_pool_option_type['fieldName']]
|
802
804
|
elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
|
@@ -833,38 +835,13 @@ module Morpheus::Cli::ProvisioningHelper
|
|
833
835
|
option_type_list = option_type_list.reject {|opt| ['provisionServerId'].include?(opt['fieldName'])}
|
834
836
|
end
|
835
837
|
|
836
|
-
# add selectable datastores
|
838
|
+
# add selectable datastores
|
839
|
+
# no longer use the plan datastores info, always load from data-stores api instead
|
840
|
+
# note: this modifies service_plan in place with 'datastores' and 'autoOptions'
|
837
841
|
if options[:select_datastore]
|
838
|
-
|
839
|
-
|
840
|
-
service_plan
|
841
|
-
['clusters', 'datastores'].each do |type|
|
842
|
-
service_plan['datastores'][type] ||= []
|
843
|
-
selectable_datastores[type].reject { |ds| service_plan['datastores'][type].find {|it| it['id'] == ds['id']} }.each { |ds|
|
844
|
-
service_plan['datastores'][type] << ds
|
845
|
-
}
|
846
|
-
end
|
847
|
-
rescue => error
|
848
|
-
Morpheus::Logging::DarkPrinter.puts "Unable to load available data-stores, using datastores option source instead." if Morpheus::Logging.debug?
|
849
|
-
end
|
850
|
-
|
851
|
-
if provision_type && provision_type['supportsAutoDatastore']
|
852
|
-
service_plan['supportsAutoDatastore'] = true
|
853
|
-
service_plan['autoOptions'] ||= []
|
854
|
-
if service_plan['datastores'] && service_plan['datastores']['clusters']
|
855
|
-
if service_plan['datastores']['clusters'].count > 0 && !service_plan['autoOptions'].find {|it| it['id'] == 'autoCluster'}
|
856
|
-
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
857
|
-
end
|
858
|
-
else
|
859
|
-
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
860
|
-
end
|
861
|
-
if service_plan['datastores'] && service_plan['datastores']['datastores']
|
862
|
-
if service_plan['datastores']['datastores'].count > 0 && !service_plan['autoOptions'].find {|it| it['id'] == 'auto'}
|
863
|
-
service_plan['autoOptions'] << {'id' => 'auto', 'name' => 'Auto - Datastore'}
|
864
|
-
end
|
865
|
-
else
|
866
|
-
service_plan['autoOptions'] << {'id' => 'auto', 'name' => 'Auto - Datastore'}
|
867
|
-
end
|
842
|
+
if provision_type['hasDatastore']
|
843
|
+
datastore_params = {'zoneId' => cloud_id, 'siteId' => group_id, 'resourcePoolId' => resource_pool['id']}
|
844
|
+
load_service_plan_datastores(service_plan, provision_type, datastore_params)
|
868
845
|
end
|
869
846
|
end
|
870
847
|
end
|
@@ -1089,7 +1066,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1089
1066
|
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
1090
1067
|
volumes = []
|
1091
1068
|
plan_size = nil
|
1092
|
-
if plan_info['maxStorage']
|
1069
|
+
if plan_info['maxStorage'].to_i > 0
|
1093
1070
|
plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
|
1094
1071
|
end
|
1095
1072
|
root_storage_types = []
|
@@ -1162,7 +1139,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1162
1139
|
storage_type_id = nil
|
1163
1140
|
storage_type = nil
|
1164
1141
|
else
|
1165
|
-
default_storage_type = root_storage_types.find {|t| t['value'].to_s == volume['storageType'].to_s}
|
1142
|
+
default_storage_type = root_storage_types.find {|t| t['value'].to_s == (volume['typeId'] || volume['storageType']).to_s}
|
1166
1143
|
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => 'Root Storage Type', 'selectOptions' => root_storage_types, 'required' => true, 'defaultFirstOption' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.', 'defaultValue' => default_storage_type ? default_storage_type['name'] : volume['storageType']}], options[:options])
|
1167
1144
|
storage_type_id = v_prompt[field_context]['storageType']
|
1168
1145
|
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
@@ -1198,6 +1175,11 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1198
1175
|
volume['size'] = nil #volume.delete('size')
|
1199
1176
|
end
|
1200
1177
|
end
|
1178
|
+
# root volume storage controller mount input is disabled in the UI.
|
1179
|
+
# if plan_info['customizeVolume'] # && storage_type['customStorageController']
|
1180
|
+
# cmp = prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options, server)
|
1181
|
+
# volume['controllerMountPoint'] = cmp if !cmp.to_s.empty?
|
1182
|
+
# end
|
1201
1183
|
else
|
1202
1184
|
# might need different logic here ? =o
|
1203
1185
|
#volume['size'] = plan_size
|
@@ -1217,29 +1199,254 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1217
1199
|
has_another_volume = (options[:options] && options[:options]["dataVolume#{volume_index}"]) || (options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index])
|
1218
1200
|
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?", {:default => (options[:defaultAddFirstDataVolume] == true && volume_index == 1)}))
|
1219
1201
|
while add_another_volume do
|
1220
|
-
|
1202
|
+
#puts "Configure Data #{volume_index} Volume"
|
1203
|
+
|
1204
|
+
field_context = "dataVolume#{volume_index}"
|
1205
|
+
|
1206
|
+
#volume_label = (volume_index == 1 ? 'data' : "data #{volume_index}")
|
1207
|
+
volume_label = "data-#{volume_index}"
|
1208
|
+
volume = {
|
1209
|
+
#'id' => -1,
|
1210
|
+
'rootVolume' => false,
|
1211
|
+
'name' => volume_label,
|
1212
|
+
'size' => plan_size,
|
1213
|
+
'sizeId' => nil,
|
1214
|
+
'storageType' => nil,
|
1215
|
+
'datastoreId' => nil
|
1216
|
+
}
|
1217
|
+
if options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index]
|
1218
|
+
volume = options[:options]['volumes'][volume_index]
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
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.', 'defaultValue' => volume['storageType']}], options[:options])
|
1222
|
+
storage_type_id = v_prompt[field_context]['storageType']
|
1223
|
+
volume['storageType'] = storage_type_id
|
1224
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
1225
|
+
|
1226
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
1227
|
+
custom_size_options = []
|
1228
|
+
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
1229
|
+
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
1230
|
+
if !opt.nil?
|
1231
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
1232
|
+
end
|
1233
|
+
end
|
1234
|
+
end
|
1235
|
+
|
1236
|
+
if plan_info['customizeVolume'] && storage_type['customLabel']
|
1237
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
1238
|
+
volume['name'] = v_prompt[field_context]['name']
|
1239
|
+
end
|
1240
|
+
if plan_info['customizeVolume'] && storage_type['customSize']
|
1241
|
+
if custom_size_options.empty?
|
1242
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
1243
|
+
volume['size'] = v_prompt[field_context]['size']
|
1244
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
1245
|
+
else
|
1246
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.', 'defaultValue' => volume['sizeId']}], options[:options])
|
1247
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1248
|
+
volume['size'] = nil #volume.delete('size')
|
1249
|
+
end
|
1250
|
+
else
|
1251
|
+
# might need different logic here ? =o
|
1252
|
+
volume['size'] = plan_size
|
1253
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
1254
|
+
end
|
1255
|
+
#todo: Pass in virtual_image to prompt based on its storage_controllers (and volume configuration)
|
1256
|
+
if plan_info['customizeVolume'] # && storage_type['customStorageController']
|
1257
|
+
cmp = prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options, nil)
|
1258
|
+
volume['controllerMountPoint'] = cmp if !cmp.to_s.empty?
|
1259
|
+
end
|
1260
|
+
if !datastore_options.empty?
|
1261
|
+
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.', 'defaultValue' => volume['datastoreId']}], options[:options])
|
1262
|
+
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
volumes << volume
|
1266
|
+
|
1267
|
+
volume_index += 1
|
1268
|
+
if options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index]
|
1269
|
+
add_another_volume = true
|
1270
|
+
elsif plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
1271
|
+
# todo: should maxDisk check consider the root volume too?
|
1272
|
+
add_another_volume = false
|
1273
|
+
else
|
1274
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
1275
|
+
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?", {:default => false}))
|
1276
|
+
end
|
1277
|
+
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
return volumes
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
|
1286
|
+
# This recreates the behavior of multi_disk.js
|
1287
|
+
# returns array of volumes based on service plan options (plan_info)
|
1288
|
+
def prompt_resize_volumes(current_volumes, plan_info, provision_type, options={}, server=nil)
|
1289
|
+
#puts "Configure Volumes:"
|
1290
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
1291
|
+
|
1292
|
+
current_root_volume = current_volumes[0]
|
1293
|
+
|
1294
|
+
volumes = []
|
1295
|
+
|
1296
|
+
plan_size = nil
|
1297
|
+
if plan_info['maxStorage'].to_i > 0
|
1298
|
+
plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
root_storage_types = []
|
1302
|
+
if plan_info['rootStorageTypes']
|
1303
|
+
plan_info['rootStorageTypes'].each do |opt|
|
1304
|
+
if !opt.nil?
|
1305
|
+
root_storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
1306
|
+
end
|
1307
|
+
end
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
storage_types = []
|
1311
|
+
if plan_info['storageTypes']
|
1312
|
+
plan_info['storageTypes'].each do |opt|
|
1313
|
+
if !opt.nil?
|
1314
|
+
storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
end
|
1318
|
+
|
1319
|
+
# no longer use the plan datastores info, always load from data-stores api instead
|
1320
|
+
# note: this modifies service_plan in place with 'datastores' and 'autoOptions'
|
1321
|
+
group_id = cloud_id = options['siteId']
|
1322
|
+
cloud_id = options['zoneId']
|
1323
|
+
server_resource_pool_id = server ? (server['resourcePoolId'] || (server['resourcePool'] ? server['resourcePool']['id'] : nil)) : nil
|
1324
|
+
resource_pool_id = options['resourcePoolId'] || server_resource_pool_id
|
1325
|
+
if provision_type['hasDatastore']
|
1326
|
+
datastore_params = {'zoneId' => cloud_id, 'siteId' => group_id, 'resourcePoolId' => resource_pool_id}
|
1327
|
+
load_service_plan_datastores(plan_info, provision_type, datastore_params)
|
1328
|
+
end
|
1329
|
+
datastore_options = []
|
1330
|
+
if plan_info['supportsAutoDatastore']
|
1331
|
+
if plan_info['autoOptions']
|
1332
|
+
plan_info['autoOptions'].each do |opt|
|
1333
|
+
if !opt.nil?
|
1334
|
+
datastore_options << {'name' => opt['name'], 'value' => opt['id']}
|
1335
|
+
end
|
1336
|
+
end
|
1337
|
+
end
|
1338
|
+
end
|
1339
|
+
if plan_info['datastores']
|
1340
|
+
plan_info['datastores'].each do |k, v|
|
1341
|
+
v.each do |opt|
|
1342
|
+
if !opt.nil?
|
1343
|
+
datastore_options << {'name' => "#{k}: #{opt['name']}", 'value' => opt['id']}
|
1344
|
+
end
|
1345
|
+
end
|
1346
|
+
end
|
1347
|
+
end
|
1348
|
+
|
1349
|
+
#puts "Configure Root Volume"
|
1350
|
+
|
1351
|
+
field_context = "rootVolume"
|
1352
|
+
storage_type = nil
|
1353
|
+
storage_type_id = nil
|
1354
|
+
if root_storage_types.empty?
|
1355
|
+
# this means there's no configuration, just send a single root volume to the server
|
1356
|
+
storage_type_id = nil
|
1357
|
+
storage_type = nil
|
1358
|
+
else
|
1359
|
+
#v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => 'Root Storage Type', 'selectOptions' => root_storage_types, 'required' => true, 'defaultFirstOption' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
|
1360
|
+
#storage_type_id = v_prompt[field_context]['storageType']
|
1361
|
+
storage_type_id = (current_root_volume['typeId'] || current_root_volume['storageType'] || (current_root_volume['type']['id'] rescue nil))
|
1362
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
1366
|
+
root_custom_size_options = []
|
1367
|
+
if plan_info['rootCustomSizeOptions'] && plan_info['rootCustomSizeOptions'][storage_type_id.to_s]
|
1368
|
+
plan_info['rootCustomSizeOptions'][storage_type_id.to_s].each do |opt|
|
1369
|
+
if !opt.nil?
|
1370
|
+
root_custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
1371
|
+
end
|
1372
|
+
end
|
1373
|
+
end
|
1374
|
+
volume = {
|
1375
|
+
'id' => current_root_volume['id'],
|
1376
|
+
'rootVolume' => true,
|
1377
|
+
'name' => current_root_volume['name'],
|
1378
|
+
'size' => get_volume_size(current_root_volume) || plan_size,
|
1379
|
+
'sizeId' => nil,
|
1380
|
+
'storageType' => storage_type_id,
|
1381
|
+
'datastoreId' => current_root_volume['datastoreId']
|
1382
|
+
}
|
1383
|
+
if !current_root_volume['controllerMountPoint'].to_s.empty?
|
1384
|
+
volume['controllerMountPoint'] = current_root_volume['controllerMountPoint']
|
1385
|
+
end
|
1386
|
+
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customLabel']
|
1387
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Root Volume Label', 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
1388
|
+
volume['name'] = v_prompt[field_context]['name']
|
1389
|
+
end
|
1390
|
+
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
|
1391
|
+
# provision_type['rootDiskSizeKnown'] == false means size cannot be changed
|
1392
|
+
if provision_type['rootDiskSizeKnown'] == false
|
1393
|
+
# volume['size'] = plan_size if plan_size.to_i != 0
|
1394
|
+
else
|
1395
|
+
if root_custom_size_options.empty?
|
1396
|
+
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])
|
1397
|
+
volume['size'] = v_prompt[field_context]['size']
|
1398
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
1399
|
+
else
|
1400
|
+
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])
|
1401
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1402
|
+
volume['size'] = nil #volume.delete('size')
|
1403
|
+
end
|
1404
|
+
end
|
1405
|
+
else
|
1406
|
+
# might need different logic here ? =o
|
1407
|
+
# volume['size'] = plan_size
|
1408
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1409
|
+
end
|
1410
|
+
# if !datastore_options.empty?
|
1411
|
+
# 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])
|
1412
|
+
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1413
|
+
# end
|
1414
|
+
|
1415
|
+
volumes << volume
|
1416
|
+
|
1417
|
+
# modify or delete existing data volumes
|
1418
|
+
(1..(current_volumes.size-1)).each do |volume_index|
|
1419
|
+
current_volume = current_volumes[volume_index]
|
1420
|
+
if current_volume
|
1221
1421
|
|
1222
|
-
|
1422
|
+
field_context = "dataVolume#{volume_index}"
|
1223
1423
|
|
1224
|
-
|
1424
|
+
action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
|
1425
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'action', 'type' => 'select', 'fieldLabel' => "Modify/Keep/Delete volume '#{current_volume['name']}'", 'selectOptions' => action_options, 'required' => true, 'defaultValue' => 'keep', 'description' => 'Modify, Keep or Delete existing data volume?'}], options[:options])
|
1426
|
+
volume_action = v_prompt[field_context]['action']
|
1427
|
+
|
1428
|
+
if volume_action == 'delete'
|
1429
|
+
# deleted volume is just excluded from post params
|
1430
|
+
next
|
1431
|
+
elsif volume_action == 'keep'
|
1225
1432
|
volume = {
|
1226
|
-
|
1433
|
+
'id' => current_volume['id'].to_i,
|
1227
1434
|
'rootVolume' => false,
|
1228
|
-
'name' =>
|
1229
|
-
'size' => plan_size,
|
1435
|
+
'name' => current_volume['name'],
|
1436
|
+
'size' => get_volume_size(current_volume) || plan_size,
|
1230
1437
|
'sizeId' => nil,
|
1231
|
-
'storageType' => nil,
|
1232
|
-
'datastoreId' =>
|
1438
|
+
'storageType' => (current_volume['typeId'] || current_volume['storageType'] || (current_volume['type']['id'] rescue nil)),
|
1439
|
+
'datastoreId' => current_volume['datastoreId']
|
1233
1440
|
}
|
1234
|
-
if
|
1235
|
-
volume =
|
1441
|
+
if !current_volume['controllerMountPoint'].to_s.empty?
|
1442
|
+
volume['controllerMountPoint'] = current_volume['controllerMountPoint']
|
1236
1443
|
end
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1444
|
+
volumes << volume
|
1445
|
+
else
|
1446
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
|
1447
|
+
# storage_type_id = v_prompt[field_context]['storageType']
|
1448
|
+
storage_type_id = (current_volume['typeId'] || current_volume['storageType'] || (current_volume['type']['id'] rescue nil))
|
1241
1449
|
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
1242
|
-
|
1243
1450
|
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
1244
1451
|
custom_size_options = []
|
1245
1452
|
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
@@ -1250,6 +1457,19 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1250
1457
|
end
|
1251
1458
|
end
|
1252
1459
|
|
1460
|
+
volume = {
|
1461
|
+
'id' => current_volume['id'].to_i,
|
1462
|
+
'rootVolume' => false,
|
1463
|
+
'name' => current_volume['name'],
|
1464
|
+
'size' => get_volume_size(current_volume) || plan_size,
|
1465
|
+
'sizeId' => nil,
|
1466
|
+
'storageType' => (current_volume['typeId'] || current_volume['storageType'] || (current_volume['type']['id'] rescue current_volume['type'])),
|
1467
|
+
'datastoreId' => current_volume['datastoreId']
|
1468
|
+
}
|
1469
|
+
if !current_volume['controllerMountPoint'].to_s.empty?
|
1470
|
+
volume['controllerMountPoint'] = current_volume['controllerMountPoint']
|
1471
|
+
end
|
1472
|
+
|
1253
1473
|
if plan_info['customizeVolume'] && storage_type['customLabel']
|
1254
1474
|
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
1255
1475
|
volume['name'] = v_prompt[field_context]['name']
|
@@ -1260,331 +1480,323 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1260
1480
|
volume['size'] = v_prompt[field_context]['size']
|
1261
1481
|
volume['sizeId'] = nil #volume.delete('sizeId')
|
1262
1482
|
else
|
1263
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'
|
1483
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
|
1264
1484
|
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1265
1485
|
volume['size'] = nil #volume.delete('size')
|
1266
1486
|
end
|
1267
1487
|
else
|
1268
1488
|
# might need different logic here ? =o
|
1269
|
-
volume['size'] = plan_size
|
1270
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1271
|
-
end
|
1272
|
-
if !datastore_options.empty?
|
1273
|
-
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.', 'defaultValue' => volume['datastoreId']}], options[:options])
|
1274
|
-
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1489
|
+
# volume['size'] = plan_size
|
1490
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1275
1491
|
end
|
1492
|
+
# if plan_info['customizeVolume'] # && storage_type['customStorageController']
|
1493
|
+
# cmp = prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options, server)
|
1494
|
+
# volume['controllerMountPoint'] = cmp if !cmp.to_s.empty?
|
1495
|
+
# end
|
1496
|
+
# if !datastore_options.empty?
|
1497
|
+
# 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])
|
1498
|
+
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1499
|
+
# end
|
1276
1500
|
|
1277
1501
|
volumes << volume
|
1278
1502
|
|
1279
|
-
volume_index += 1
|
1280
|
-
if options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index]
|
1281
|
-
add_another_volume = true
|
1282
|
-
elsif plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
1283
|
-
# todo: should maxDisk check consider the root volume too?
|
1284
|
-
add_another_volume = false
|
1285
|
-
else
|
1286
|
-
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
1287
|
-
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?", {:default => false}))
|
1288
|
-
end
|
1289
|
-
|
1290
1503
|
end
|
1291
1504
|
|
1292
1505
|
end
|
1293
|
-
|
1294
|
-
return volumes
|
1295
1506
|
end
|
1296
1507
|
|
1297
1508
|
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
root_storage_types = []
|
1314
|
-
if plan_info['rootStorageTypes']
|
1315
|
-
plan_info['rootStorageTypes'].each do |opt|
|
1316
|
-
if !opt.nil?
|
1317
|
-
root_storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
1318
|
-
end
|
1319
|
-
end
|
1320
|
-
end
|
1321
|
-
|
1322
|
-
storage_types = []
|
1323
|
-
if plan_info['storageTypes']
|
1324
|
-
plan_info['storageTypes'].each do |opt|
|
1325
|
-
if !opt.nil?
|
1326
|
-
storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
1327
|
-
end
|
1328
|
-
end
|
1329
|
-
end
|
1509
|
+
if plan_info['addVolumes']
|
1510
|
+
volume_index = current_volumes.size
|
1511
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
1512
|
+
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?", {:default => false}))
|
1513
|
+
while add_another_volume do
|
1514
|
+
#puts "Configure Data #{volume_index} Volume"
|
1515
|
+
previous_volume = volumes.last
|
1516
|
+
default_storage_type_id = (previous_volume['typeId'] || previous_volume['storageType'] || (previous_volume['type']['id'] rescue previous_volume['type']))
|
1517
|
+
storage_type_match = storage_types.find {|type| type['value'] == default_storage_type_id}
|
1518
|
+
default_storage_type = storage_type_match ? (storage_type_match['name'] || storage_type_match['value']) : nil
|
1519
|
+
field_context = "dataVolume#{volume_index}"
|
1520
|
+
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])
|
1521
|
+
storage_type_id = v_prompt[field_context]['storageType']
|
1522
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
1330
1523
|
|
1331
|
-
|
1332
|
-
|
1333
|
-
if plan_info['
|
1334
|
-
plan_info['
|
1524
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
1525
|
+
custom_size_options = []
|
1526
|
+
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
1527
|
+
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
1335
1528
|
if !opt.nil?
|
1336
|
-
|
1529
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
1337
1530
|
end
|
1338
1531
|
end
|
1339
1532
|
end
|
1340
|
-
end
|
1341
|
-
if plan_info['datastores']
|
1342
|
-
plan_info['datastores'].each do |k, v|
|
1343
|
-
v.each do |opt|
|
1344
|
-
if !opt.nil?
|
1345
|
-
datastore_options << {'name' => "#{k}: #{opt['name']}", 'value' => opt['id']}
|
1346
|
-
end
|
1347
|
-
end
|
1348
|
-
end
|
1349
|
-
end
|
1350
|
-
|
1351
|
-
#puts "Configure Root Volume"
|
1352
|
-
|
1353
|
-
field_context = "rootVolume"
|
1354
1533
|
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1534
|
+
#volume_label = (volume_index == 1 ? 'data' : "data #{volume_index}")
|
1535
|
+
volume_label = "data-#{volume_index}"
|
1536
|
+
volume = {
|
1537
|
+
'id' => -1,
|
1538
|
+
'rootVolume' => false,
|
1539
|
+
'name' => volume_label,
|
1540
|
+
'size' => plan_size,
|
1541
|
+
'sizeId' => nil,
|
1542
|
+
'storageType' => storage_type_id,
|
1543
|
+
'datastoreId' => nil
|
1544
|
+
}
|
1365
1545
|
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
plan_info['rootCustomSizeOptions'][storage_type_id.to_s].each do |opt|
|
1370
|
-
if !opt.nil?
|
1371
|
-
root_custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
1372
|
-
end
|
1546
|
+
if plan_info['customizeVolume'] && storage_type['customLabel']
|
1547
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume_label}], options[:options])
|
1548
|
+
volume['name'] = v_prompt[field_context]['name']
|
1373
1549
|
end
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
'id' => current_root_volume['id'],
|
1378
|
-
'rootVolume' => true,
|
1379
|
-
'name' => current_root_volume['name'],
|
1380
|
-
'size' => current_root_volume['size'] > 0 ? current_root_volume['size'] : plan_size,
|
1381
|
-
'sizeId' => nil,
|
1382
|
-
'storageType' => storage_type_id,
|
1383
|
-
'datastoreId' => current_root_volume['datastoreId']
|
1384
|
-
}
|
1385
|
-
|
1386
|
-
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customLabel']
|
1387
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Root Volume Label', 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
1388
|
-
volume['name'] = v_prompt[field_context]['name']
|
1389
|
-
end
|
1390
|
-
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
|
1391
|
-
# provision_type['rootDiskSizeKnown'] == false means size cannot be changed
|
1392
|
-
if provision_type['rootDiskSizeKnown'] == false
|
1393
|
-
# volume['size'] = plan_size if plan_size.to_i != 0
|
1394
|
-
else
|
1395
|
-
if root_custom_size_options.empty?
|
1396
|
-
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])
|
1550
|
+
if plan_info['customizeVolume'] && storage_type['customSize']
|
1551
|
+
if custom_size_options.empty?
|
1552
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
1397
1553
|
volume['size'] = v_prompt[field_context]['size']
|
1398
1554
|
volume['sizeId'] = nil #volume.delete('sizeId')
|
1399
1555
|
else
|
1400
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' =>
|
1556
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
|
1401
1557
|
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1402
1558
|
volume['size'] = nil #volume.delete('size')
|
1403
1559
|
end
|
1560
|
+
else
|
1561
|
+
# might need different logic here ? =o
|
1562
|
+
# volume['size'] = plan_size
|
1563
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1564
|
+
end
|
1565
|
+
if plan_info['customizeVolume'] # && storage_type['customStorageController']
|
1566
|
+
cmp = prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options, server)
|
1567
|
+
volume['controllerMountPoint'] = cmp if !cmp.to_s.empty?
|
1568
|
+
end
|
1569
|
+
if !datastore_options.empty?
|
1570
|
+
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.', 'defaultValue' => current_root_volume['datastoreId']}], options[:options])
|
1571
|
+
volume['datastoreId'] = v_prompt[field_context]['datastoreId'] unless v_prompt[field_context]['datastoreId'].to_s.empty?
|
1404
1572
|
end
|
1405
|
-
else
|
1406
|
-
# might need different logic here ? =o
|
1407
|
-
# volume['size'] = plan_size
|
1408
|
-
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1409
|
-
end
|
1410
|
-
# if !datastore_options.empty?
|
1411
|
-
# 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])
|
1412
|
-
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1413
|
-
# end
|
1414
1573
|
|
1415
|
-
|
1416
|
-
|
1417
|
-
# modify or delete existing data volumes
|
1418
|
-
(1..(current_volumes.size-1)).each do |volume_index|
|
1419
|
-
current_volume = current_volumes[volume_index]
|
1420
|
-
if current_volume
|
1421
|
-
|
1422
|
-
field_context = "dataVolume#{volume_index}"
|
1423
|
-
|
1424
|
-
action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
|
1425
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'action', 'type' => 'select', 'fieldLabel' => "Modify/Keep/Delete volume '#{current_volume['name']}'", 'selectOptions' => action_options, 'required' => true, 'defaultValue' => 'keep', 'description' => 'Modify, Keep or Delete existing data volume?'}], options[:options])
|
1426
|
-
volume_action = v_prompt[field_context]['action']
|
1427
|
-
|
1428
|
-
if volume_action == 'delete'
|
1429
|
-
# deleted volume is just excluded from post params
|
1430
|
-
next
|
1431
|
-
elsif volume_action == 'keep'
|
1432
|
-
volume = {
|
1433
|
-
'id' => current_volume['id'].to_i,
|
1434
|
-
'rootVolume' => false,
|
1435
|
-
'name' => current_volume['name'],
|
1436
|
-
'size' => current_volume['size'] > (plan_size || 0) ? current_volume['size'] : plan_size,
|
1437
|
-
'sizeId' => nil,
|
1438
|
-
'storageType' => (current_volume['type'] || current_volume['storageType']),
|
1439
|
-
'datastoreId' => current_volume['datastoreId']
|
1440
|
-
}
|
1441
|
-
volumes << volume
|
1442
|
-
else
|
1443
|
-
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
|
1444
|
-
# storage_type_id = v_prompt[field_context]['storageType']
|
1445
|
-
storage_type_id = current_volume['type'] || current_volume['storageType']
|
1446
|
-
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
1447
|
-
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
1448
|
-
custom_size_options = []
|
1449
|
-
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
1450
|
-
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
1451
|
-
if !opt.nil?
|
1452
|
-
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
1453
|
-
end
|
1454
|
-
end
|
1455
|
-
end
|
1574
|
+
volumes << volume
|
1456
1575
|
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
}
|
1466
|
-
|
1467
|
-
if plan_info['customizeVolume'] && storage_type['customLabel']
|
1468
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
1469
|
-
volume['name'] = v_prompt[field_context]['name']
|
1470
|
-
end
|
1471
|
-
if plan_info['customizeVolume'] && storage_type['customSize']
|
1472
|
-
if custom_size_options.empty?
|
1473
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
1474
|
-
volume['size'] = v_prompt[field_context]['size']
|
1475
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1476
|
-
else
|
1477
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
|
1478
|
-
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1479
|
-
volume['size'] = nil #volume.delete('size')
|
1480
|
-
end
|
1481
|
-
else
|
1482
|
-
# might need different logic here ? =o
|
1483
|
-
# volume['size'] = plan_size
|
1484
|
-
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1485
|
-
end
|
1486
|
-
# if !datastore_options.empty?
|
1487
|
-
# 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])
|
1488
|
-
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1489
|
-
# end
|
1576
|
+
# todo: should maxDisk check consider the root volume too?
|
1577
|
+
if plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
1578
|
+
add_another_volume = false
|
1579
|
+
else
|
1580
|
+
volume_index += 1
|
1581
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
1582
|
+
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?", {default:false}))
|
1583
|
+
end
|
1490
1584
|
|
1491
|
-
|
1585
|
+
end
|
1492
1586
|
|
1493
|
-
|
1587
|
+
end
|
1588
|
+
|
1589
|
+
return volumes
|
1590
|
+
end
|
1494
1591
|
|
1592
|
+
# loads datastores and modifies service_plan in place
|
1593
|
+
# populating datastores: {datastores: [],clusters: []}, supportsAutoDatastore: true, autoOptions: []
|
1594
|
+
def load_service_plan_datastores(service_plan, provision_type, params)
|
1595
|
+
begin
|
1596
|
+
selectable_datastores = datastores_interface.list(params)
|
1597
|
+
service_plan['datastores'] = {'clusters' => [], 'datastores' => []}
|
1598
|
+
['clusters', 'datastores'].each do |type|
|
1599
|
+
service_plan['datastores'][type] ||= []
|
1600
|
+
selectable_datastores[type].reject { |ds| service_plan['datastores'][type].find {|it| it['id'] == ds['id']} }.each { |ds|
|
1601
|
+
service_plan['datastores'][type] << ds
|
1602
|
+
}
|
1603
|
+
end
|
1604
|
+
rescue => error
|
1605
|
+
Morpheus::Logging::DarkPrinter.puts "Unable to load available data-stores, using datastores option source instead." if Morpheus::Logging.debug?
|
1606
|
+
end
|
1607
|
+
|
1608
|
+
if provision_type && provision_type['supportsAutoDatastore']
|
1609
|
+
service_plan['supportsAutoDatastore'] = true
|
1610
|
+
service_plan['autoOptions'] ||= []
|
1611
|
+
if service_plan['datastores'] && service_plan['datastores']['clusters']
|
1612
|
+
if service_plan['datastores']['clusters'].count > 0 && !service_plan['autoOptions'].find {|it| it['id'] == 'autoCluster'}
|
1613
|
+
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
1495
1614
|
end
|
1615
|
+
else
|
1616
|
+
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
1496
1617
|
end
|
1618
|
+
if service_plan['datastores'] && service_plan['datastores']['datastores']
|
1619
|
+
if service_plan['datastores']['datastores'].count > 0 && !service_plan['autoOptions'].find {|it| it['id'] == 'auto'}
|
1620
|
+
service_plan['autoOptions'] << {'id' => 'auto', 'name' => 'Auto - Datastore'}
|
1621
|
+
end
|
1622
|
+
else
|
1623
|
+
service_plan['autoOptions'] << {'id' => 'auto', 'name' => 'Auto - Datastore'}
|
1624
|
+
end
|
1625
|
+
end
|
1626
|
+
return service_plan
|
1627
|
+
end
|
1497
1628
|
|
1629
|
+
def get_volume_size(volume)
|
1630
|
+
if volume['size'].to_i > 0
|
1631
|
+
volume['size']
|
1632
|
+
elsif volume['maxStorage'].to_i > 0
|
1633
|
+
volume['maxStorage'].to_i / (1024**3)
|
1634
|
+
else
|
1635
|
+
nil
|
1636
|
+
end
|
1637
|
+
end
|
1498
1638
|
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
end
|
1521
|
-
end
|
1639
|
+
def prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options={}, server=nil)
|
1640
|
+
begin
|
1641
|
+
# The /api/provision-types has always returned all the controllerTypes, yay
|
1642
|
+
# It did not return hasStorageControllers: true|false though, so fallback to checking if controllerTypes.size > 0.
|
1643
|
+
# has_storage_controllers = provision_type['hasStorageControllers'] || ['vmware'].include?(provision_type['code'])
|
1644
|
+
# storage_controller_types = has_storage_controllers ? options_interface.options_for_source('storageControllerTypes',{provisionTypeId:provision_type['id']})['data'] : []
|
1645
|
+
storage_controller_types = provision_type['controllerTypes']
|
1646
|
+
has_storage_controllers = provision_type['hasStorageControllers'] || (storage_controller_types && !storage_controller_types.empty?)
|
1647
|
+
storage_controllers = server ? server['controllers'] : []
|
1648
|
+
if has_storage_controllers
|
1649
|
+
# existing storage controllers from server
|
1650
|
+
storage_controller_options = []
|
1651
|
+
storage_controller_options.push({'name' => 'Auto', 'value' => 'auto'})
|
1652
|
+
storage_controller_options.push({'name' => 'New', 'value' => -1})
|
1653
|
+
storage_controllers.each_with_index do |sc, index|
|
1654
|
+
# storage_controller_options.push({'name' => sc['name'], 'value' => sc['id']})
|
1655
|
+
# API did not always return controller busNumber so extract from the volume mountPoint if needed
|
1656
|
+
if sc['busNumber'].nil?
|
1657
|
+
matching_volume = volumes.find {|v| v['controllerMountPoint'] && v['controllerMountPoint'].split(':')[0] == sc['id'].to_s }
|
1658
|
+
if matching_volume
|
1659
|
+
sc['busNumber'] = matching_volume['controllerMountPoint'].split(":")[1]
|
1522
1660
|
end
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1661
|
+
end
|
1662
|
+
sct = storage_controller_types.find { |t| t['id'] == sc['type']['id'] }
|
1663
|
+
storage_controller_options.push({'name' => "#{sct['category'].to_s.upcase rescue ''} #{sc['busNumber'] || index}", 'value' => sc['id']})
|
1664
|
+
end if storage_controllers
|
1665
|
+
# The controller mount point specification for this volume in the format: `id:busNumber:typeId:unitNumber"`
|
1666
|
+
# For new storage controllers the id is passed as -1, so an example value would be: `"-1:1:6:0"` which translates to id: -1 (new), busNumber: 1, storage controller type id: 6 (SCSI VMware Paravirtual), unit number: 0.
|
1667
|
+
# Split -O dataVolume1.controllerMountPoint="-1:1:6:0" into its components.
|
1668
|
+
controller_mount_point = ""
|
1669
|
+
controller_id, bus_number, controller_type_id, unit_number = nil, nil, nil, nil
|
1670
|
+
if options[:options][field_context] && options[:options][field_context]['controllerMountPoint']
|
1671
|
+
parts = options[:options][field_context]['controllerMountPoint'].split(":").collect {|it| it.to_s.strip }
|
1672
|
+
controller_id, bus_number, controller_type_id, unit_number = parts[0],parts[1],parts[2],parts[3]
|
1673
|
+
# if we dont have every part then clear the options value so it prompt down below
|
1674
|
+
if controller_id.to_s.empty? || bus_number.to_s.empty? || controller_type_id.to_s.empty? || unit_number.to_s.empty?
|
1675
|
+
options[:options][field_context].delete('controllerMountPoint')
|
1676
|
+
end
|
1677
|
+
end
|
1678
|
+
# Select Storage Controller, auto, new or existing
|
1679
|
+
# Choose Existing or Add a new controller which requires selecting type selecting type.
|
1680
|
+
if !controller_id.to_s.empty?
|
1681
|
+
controller_id = controller_id
|
1682
|
+
else
|
1683
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'controllerId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Controller #{volume_index}", 'selectOptions' => storage_controller_options, 'required' => true, 'description' => 'Choose a storage controller.', 'defaultValue' => (volume['controllerId'] || 'auto') }], options[:options])
|
1684
|
+
controller_id = v_prompt[field_context]['controllerId']
|
1685
|
+
end
|
1686
|
+
skip_controller_mount_point = false
|
1687
|
+
if controller_id.to_s == 'auto'
|
1688
|
+
# auto just means omit controllerMountPoint
|
1689
|
+
skip_controller_mount_point = true
|
1690
|
+
elsif controller_id.to_i < 1
|
1691
|
+
# -1 (or anything but a positive integer) means new controller
|
1692
|
+
controller_id = -1
|
1693
|
+
elsif controller_id
|
1694
|
+
controller_id = controller_id.to_i
|
1695
|
+
end
|
1696
|
+
if skip_controller_mount_point
|
1697
|
+
# skip mount point parameter
|
1698
|
+
# volume.delete('controllerMountPoint')
|
1699
|
+
# volume.delete('controllerId')
|
1700
|
+
return nil
|
1701
|
+
else
|
1702
|
+
storage_controller_type = nil
|
1703
|
+
storage_controller = nil
|
1704
|
+
# New Controller?
|
1705
|
+
if controller_id == -1
|
1706
|
+
#[field_context]['controllerTypeId'] controller_type_id = unless controller_type_id.to_s.empty?
|
1707
|
+
storage_controller_type_options = storage_controller_types.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}.collect {|it| {"name" => it["name"], "value" => it["id"]}}
|
1708
|
+
if !controller_type_id.to_s.empty?
|
1709
|
+
options[:options][field_context]['controllerTypeId'] = controller_type_id
|
1538
1710
|
end
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
|
1546
|
-
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1547
|
-
volume['size'] = nil #volume.delete('size')
|
1548
|
-
end
|
1549
|
-
else
|
1550
|
-
# might need different logic here ? =o
|
1551
|
-
# volume['size'] = plan_size
|
1552
|
-
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1711
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'controllerTypeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Controller Type", 'selectOptions' => storage_controller_type_options, 'required' => true, 'description' => 'Choose a storage controller type.'}], options[:options])
|
1712
|
+
controller_type_id = v_prompt[field_context]['controllerTypeId']
|
1713
|
+
# find the selected controller type
|
1714
|
+
storage_controller_type = storage_controller_types.find {|it| it['id'] == controller_type_id }
|
1715
|
+
if storage_controller_type.nil?
|
1716
|
+
raise_command_error("Storage controller type not found for id #{controller_type_id}")
|
1553
1717
|
end
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1718
|
+
storage_controller = {'id' => -1, 'type' => {'id' => storage_controller_type['id']}}
|
1719
|
+
max_devices = storage_controller_type['maxDevices'] || 1
|
1720
|
+
reserved_bus_numbers = storage_controllers.select {|it| it['category'] == storage_controller_type['category'] }.collect {|it| it['busNumber'].to_s}.uniq
|
1721
|
+
bus_number = bus_number.to_i || 0
|
1722
|
+
while true
|
1723
|
+
if !reserved_bus_numbers.include?(bus_number.to_s)
|
1724
|
+
break
|
1725
|
+
else
|
1726
|
+
next_bus_number = bus_number + 1
|
1727
|
+
if next_bus_number >= max_devices
|
1728
|
+
Morpheus::Logging::DarkPrinter.puts "Failed to find an available bus number!"
|
1729
|
+
break
|
1560
1730
|
end
|
1561
|
-
|
1562
|
-
datastore_options = []
|
1731
|
+
bus_number = next_bus_number
|
1563
1732
|
end
|
1564
1733
|
end
|
1565
|
-
|
1566
|
-
|
1567
|
-
|
1734
|
+
storage_controller['busNumber'] = bus_number.to_s
|
1735
|
+
storage_controller['name'] = "#{storage_controller_type['category'].to_s.upcase} #{bus_number}"
|
1736
|
+
# storage_controller['unitNumber'] = "null"
|
1737
|
+
# add new controller to the list
|
1738
|
+
storage_controllers.push(storage_controller)
|
1739
|
+
else
|
1740
|
+
# existing controller
|
1741
|
+
# controller_type_id = controller_type_id
|
1742
|
+
# find the selected controller type
|
1743
|
+
storage_controller = storage_controllers.find {|it| it['id'] == controller_id.to_i }
|
1744
|
+
if storage_controller.nil?
|
1745
|
+
raise_command_error("Storage controller type not found for id #{controller_type_id}")
|
1568
1746
|
end
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1747
|
+
end
|
1748
|
+
# Choose Controller Mount Point
|
1749
|
+
mount_point_options = []
|
1750
|
+
controller_list = storage_controllers
|
1751
|
+
# only show the selected controller
|
1752
|
+
controller_list = [storage_controller]
|
1753
|
+
controller_list.each do |sc|
|
1754
|
+
sct = storage_controller_types.find { |t| t['id'] == sc['type']['id'] }
|
1755
|
+
category = sct['category']
|
1756
|
+
max_devices = sct['maxDevices'] || 1
|
1757
|
+
matching_type_ids = storage_controller_types.select { |t| t['category'] == category }.collect {|t| t['id'] }
|
1758
|
+
# find available unit numbers by reversing the controllerMountPoint to find matching types, blarghhh
|
1759
|
+
reserved_unit_numbers = (volumes || []).collect {|v|
|
1760
|
+
if !v['controllerMountPoint'].to_s.empty?
|
1761
|
+
parts = v['controllerMountPoint'].split(":")
|
1762
|
+
vol_controller_id = parts[0]
|
1763
|
+
vol_bus_number = parts[1]
|
1764
|
+
vol_sct_id = parts[2]
|
1765
|
+
vol_unit_number = parts[3]
|
1766
|
+
if matching_type_ids.include?(vol_sct_id.to_i)
|
1767
|
+
vol_unit_number.to_i
|
1768
|
+
else
|
1769
|
+
nil
|
1770
|
+
end
|
1771
|
+
else
|
1772
|
+
nil
|
1773
|
+
end
|
1774
|
+
}.compact.uniq
|
1775
|
+
(0..(max_devices - 1)).each do |index|
|
1776
|
+
cmp_value = [sc['id'],sc['busNumber'],sct['id'],index].join(":")
|
1777
|
+
if reserved_unit_numbers.include?(index)
|
1778
|
+
#mount_point_options << {'name' => "#{category.to_s.upcase} #{sc['busNumber']}:#{index}", 'value' => cmp_value}
|
1779
|
+
else
|
1780
|
+
mount_point_options << {'name' => "#{category.to_s.upcase} #{sc['busNumber']}:#{index}", 'value' => cmp_value}
|
1781
|
+
end
|
1579
1782
|
end
|
1580
|
-
|
1581
1783
|
end
|
1582
|
-
|
1784
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'controllerMountPoint', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Controller Mount Point", 'selectOptions' => mount_point_options, 'required' => true, 'description' => 'Choose a storage controller mount point.'}], options[:options])
|
1785
|
+
controller_mount_point = v_prompt[field_context]['controllerMountPoint']
|
1786
|
+
# build controllerMountPoint parameter as "id:busNumber:typeId:unitNumber"
|
1787
|
+
#controller_mount_point = [controller_id, bus_number, controller_type_id, unit_number].collect {|it| it.to_s.strip}.join(":")
|
1788
|
+
# volume['controllerMountPoint'] = controller_mount_point
|
1789
|
+
return controller_mount_point
|
1583
1790
|
end
|
1584
|
-
|
1585
|
-
|
1791
|
+
else
|
1792
|
+
# storage controllers not supported, carry on then
|
1586
1793
|
end
|
1587
|
-
|
1794
|
+
rescue => e
|
1795
|
+
raise e
|
1796
|
+
Morpheus::Cli::ErrorHandler.new(my_terminal.stderr).handle_error(e) if Morpheus::Logging.debug?
|
1797
|
+
Morpheus::Logging::DarkPrinter.puts "Failed to prompt for storage controller. Proceeding..."
|
1798
|
+
end
|
1799
|
+
end
|
1588
1800
|
|
1589
1801
|
# This recreates the behavior of multi_networks.js
|
1590
1802
|
# This is used by both `instances add` and `hosts add`
|