morpheus-cli 8.0.1 → 8.0.3
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/cli/cli_command.rb +18 -3
- data/lib/morpheus/cli/commands/clusters.rb +50 -44
- data/lib/morpheus/cli/commands/hosts.rb +9 -3
- data/lib/morpheus/cli/commands/instances.rb +37 -66
- data/lib/morpheus/cli/commands/library_cluster_layouts_command.rb +1 -1
- data/lib/morpheus/cli/commands/processes_command.rb +2 -2
- data/lib/morpheus/cli/commands/shell.rb +18 -39
- data/lib/morpheus/cli/commands/snapshots.rb +24 -8
- data/lib/morpheus/cli/commands/virtual_images.rb +71 -17
- data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/processes_helper.rb +34 -4
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -324
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.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
@@ -797,7 +797,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
797
797
|
resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{}, no_prompt, true)
|
798
798
|
resource_pool_prompt.deep_compact!
|
799
799
|
payload.deep_merge!(resource_pool_prompt)
|
800
|
-
|
800
|
+
# this results in the layout, not the resourcePool for some reason...
|
801
|
+
#resource_pool = Morpheus::Cli::OptionTypes.get_last_select()
|
801
802
|
if resource_pool_option_type['fieldContext'] && resource_pool_prompt[resource_pool_option_type['fieldContext']]
|
802
803
|
pool_id = resource_pool_prompt[resource_pool_option_type['fieldContext']][resource_pool_option_type['fieldName']]
|
803
804
|
elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
|
@@ -834,38 +835,13 @@ module Morpheus::Cli::ProvisioningHelper
|
|
834
835
|
option_type_list = option_type_list.reject {|opt| ['provisionServerId'].include?(opt['fieldName'])}
|
835
836
|
end
|
836
837
|
|
837
|
-
# 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'
|
838
841
|
if options[:select_datastore]
|
839
|
-
|
840
|
-
|
841
|
-
service_plan
|
842
|
-
['clusters', 'datastores'].each do |type|
|
843
|
-
service_plan['datastores'][type] ||= []
|
844
|
-
selectable_datastores[type].reject { |ds| service_plan['datastores'][type].find {|it| it['id'] == ds['id']} }.each { |ds|
|
845
|
-
service_plan['datastores'][type] << ds
|
846
|
-
}
|
847
|
-
end
|
848
|
-
rescue => error
|
849
|
-
Morpheus::Logging::DarkPrinter.puts "Unable to load available data-stores, using datastores option source instead." if Morpheus::Logging.debug?
|
850
|
-
end
|
851
|
-
|
852
|
-
if provision_type && provision_type['supportsAutoDatastore']
|
853
|
-
service_plan['supportsAutoDatastore'] = true
|
854
|
-
service_plan['autoOptions'] ||= []
|
855
|
-
if service_plan['datastores'] && service_plan['datastores']['clusters']
|
856
|
-
if service_plan['datastores']['clusters'].count > 0 && !service_plan['autoOptions'].find {|it| it['id'] == 'autoCluster'}
|
857
|
-
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
858
|
-
end
|
859
|
-
else
|
860
|
-
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
861
|
-
end
|
862
|
-
if service_plan['datastores'] && service_plan['datastores']['datastores']
|
863
|
-
if service_plan['datastores']['datastores'].count > 0 && !service_plan['autoOptions'].find {|it| it['id'] == 'auto'}
|
864
|
-
service_plan['autoOptions'] << {'id' => 'auto', 'name' => 'Auto - Datastore'}
|
865
|
-
end
|
866
|
-
else
|
867
|
-
service_plan['autoOptions'] << {'id' => 'auto', 'name' => 'Auto - Datastore'}
|
868
|
-
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)
|
869
845
|
end
|
870
846
|
end
|
871
847
|
end
|
@@ -1090,7 +1066,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1090
1066
|
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
1091
1067
|
volumes = []
|
1092
1068
|
plan_size = nil
|
1093
|
-
if plan_info['maxStorage']
|
1069
|
+
if plan_info['maxStorage'].to_i > 0
|
1094
1070
|
plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
|
1095
1071
|
end
|
1096
1072
|
root_storage_types = []
|
@@ -1163,7 +1139,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1163
1139
|
storage_type_id = nil
|
1164
1140
|
storage_type = nil
|
1165
1141
|
else
|
1166
|
-
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}
|
1167
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])
|
1168
1144
|
storage_type_id = v_prompt[field_context]['storageType']
|
1169
1145
|
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
@@ -1199,6 +1175,11 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1199
1175
|
volume['size'] = nil #volume.delete('size')
|
1200
1176
|
end
|
1201
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
|
1202
1183
|
else
|
1203
1184
|
# might need different logic here ? =o
|
1204
1185
|
#volume['size'] = plan_size
|
@@ -1218,29 +1199,254 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1218
1199
|
has_another_volume = (options[:options] && options[:options]["dataVolume#{volume_index}"]) || (options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index])
|
1219
1200
|
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?", {:default => (options[:defaultAddFirstDataVolume] == true && volume_index == 1)}))
|
1220
1201
|
while add_another_volume do
|
1221
|
-
|
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
|
1222
1348
|
|
1223
|
-
|
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
|
1224
1364
|
|
1225
|
-
|
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
|
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'
|
1226
1432
|
volume = {
|
1227
|
-
|
1433
|
+
'id' => current_volume['id'].to_i,
|
1228
1434
|
'rootVolume' => false,
|
1229
|
-
'name' =>
|
1230
|
-
'size' => plan_size,
|
1435
|
+
'name' => current_volume['name'],
|
1436
|
+
'size' => get_volume_size(current_volume) || plan_size,
|
1231
1437
|
'sizeId' => nil,
|
1232
|
-
'storageType' => nil,
|
1233
|
-
'datastoreId' =>
|
1438
|
+
'storageType' => (current_volume['typeId'] || current_volume['storageType'] || (current_volume['type']['id'] rescue nil)),
|
1439
|
+
'datastoreId' => current_volume['datastoreId']
|
1234
1440
|
}
|
1235
|
-
if
|
1236
|
-
volume =
|
1441
|
+
if !current_volume['controllerMountPoint'].to_s.empty?
|
1442
|
+
volume['controllerMountPoint'] = current_volume['controllerMountPoint']
|
1237
1443
|
end
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
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))
|
1242
1449
|
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
1243
|
-
|
1244
1450
|
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
1245
1451
|
custom_size_options = []
|
1246
1452
|
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
@@ -1251,6 +1457,19 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1251
1457
|
end
|
1252
1458
|
end
|
1253
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
|
+
|
1254
1473
|
if plan_info['customizeVolume'] && storage_type['customLabel']
|
1255
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])
|
1256
1475
|
volume['name'] = v_prompt[field_context]['name']
|
@@ -1261,331 +1480,323 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1261
1480
|
volume['size'] = v_prompt[field_context]['size']
|
1262
1481
|
volume['sizeId'] = nil #volume.delete('sizeId')
|
1263
1482
|
else
|
1264
|
-
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])
|
1265
1484
|
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1266
1485
|
volume['size'] = nil #volume.delete('size')
|
1267
1486
|
end
|
1268
1487
|
else
|
1269
1488
|
# might need different logic here ? =o
|
1270
|
-
volume['size'] = plan_size
|
1271
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1272
|
-
end
|
1273
|
-
if !datastore_options.empty?
|
1274
|
-
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])
|
1275
|
-
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1489
|
+
# volume['size'] = plan_size
|
1490
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1276
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
|
1277
1500
|
|
1278
1501
|
volumes << volume
|
1279
1502
|
|
1280
|
-
volume_index += 1
|
1281
|
-
if options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index]
|
1282
|
-
add_another_volume = true
|
1283
|
-
elsif plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
1284
|
-
# todo: should maxDisk check consider the root volume too?
|
1285
|
-
add_another_volume = false
|
1286
|
-
else
|
1287
|
-
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
1288
|
-
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?", {:default => false}))
|
1289
|
-
end
|
1290
|
-
|
1291
1503
|
end
|
1292
1504
|
|
1293
1505
|
end
|
1294
|
-
|
1295
|
-
return volumes
|
1296
1506
|
end
|
1297
1507
|
|
1298
1508
|
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
root_storage_types = []
|
1315
|
-
if plan_info['rootStorageTypes']
|
1316
|
-
plan_info['rootStorageTypes'].each do |opt|
|
1317
|
-
if !opt.nil?
|
1318
|
-
root_storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
1319
|
-
end
|
1320
|
-
end
|
1321
|
-
end
|
1322
|
-
|
1323
|
-
storage_types = []
|
1324
|
-
if plan_info['storageTypes']
|
1325
|
-
plan_info['storageTypes'].each do |opt|
|
1326
|
-
if !opt.nil?
|
1327
|
-
storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
1328
|
-
end
|
1329
|
-
end
|
1330
|
-
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 }
|
1331
1523
|
|
1332
|
-
|
1333
|
-
|
1334
|
-
if plan_info['
|
1335
|
-
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|
|
1336
1528
|
if !opt.nil?
|
1337
|
-
|
1529
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
1338
1530
|
end
|
1339
1531
|
end
|
1340
1532
|
end
|
1341
|
-
end
|
1342
|
-
if plan_info['datastores']
|
1343
|
-
plan_info['datastores'].each do |k, v|
|
1344
|
-
v.each do |opt|
|
1345
|
-
if !opt.nil?
|
1346
|
-
datastore_options << {'name' => "#{k}: #{opt['name']}", 'value' => opt['id']}
|
1347
|
-
end
|
1348
|
-
end
|
1349
|
-
end
|
1350
|
-
end
|
1351
|
-
|
1352
|
-
#puts "Configure Root Volume"
|
1353
1533
|
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
end
|
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
|
+
}
|
1366
1545
|
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
plan_info['rootCustomSizeOptions'][storage_type_id.to_s].each do |opt|
|
1371
|
-
if !opt.nil?
|
1372
|
-
root_custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
1373
|
-
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']
|
1374
1549
|
end
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
'id' => current_root_volume['id'],
|
1379
|
-
'rootVolume' => true,
|
1380
|
-
'name' => current_root_volume['name'],
|
1381
|
-
'size' => current_root_volume['size'] > 0 ? current_root_volume['size'] : plan_size,
|
1382
|
-
'sizeId' => nil,
|
1383
|
-
'storageType' => storage_type_id,
|
1384
|
-
'datastoreId' => current_root_volume['datastoreId']
|
1385
|
-
}
|
1386
|
-
|
1387
|
-
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customLabel']
|
1388
|
-
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])
|
1389
|
-
volume['name'] = v_prompt[field_context]['name']
|
1390
|
-
end
|
1391
|
-
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
|
1392
|
-
# provision_type['rootDiskSizeKnown'] == false means size cannot be changed
|
1393
|
-
if provision_type['rootDiskSizeKnown'] == false
|
1394
|
-
# volume['size'] = plan_size if plan_size.to_i != 0
|
1395
|
-
else
|
1396
|
-
if root_custom_size_options.empty?
|
1397
|
-
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])
|
1398
1553
|
volume['size'] = v_prompt[field_context]['size']
|
1399
1554
|
volume['sizeId'] = nil #volume.delete('sizeId')
|
1400
1555
|
else
|
1401
|
-
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])
|
1402
1557
|
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1403
1558
|
volume['size'] = nil #volume.delete('size')
|
1404
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?
|
1405
1572
|
end
|
1406
|
-
else
|
1407
|
-
# might need different logic here ? =o
|
1408
|
-
# volume['size'] = plan_size
|
1409
|
-
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1410
|
-
end
|
1411
|
-
# if !datastore_options.empty?
|
1412
|
-
# 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])
|
1413
|
-
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1414
|
-
# end
|
1415
1573
|
|
1416
|
-
|
1417
|
-
|
1418
|
-
# modify or delete existing data volumes
|
1419
|
-
(1..(current_volumes.size-1)).each do |volume_index|
|
1420
|
-
current_volume = current_volumes[volume_index]
|
1421
|
-
if current_volume
|
1422
|
-
|
1423
|
-
field_context = "dataVolume#{volume_index}"
|
1424
|
-
|
1425
|
-
action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
|
1426
|
-
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])
|
1427
|
-
volume_action = v_prompt[field_context]['action']
|
1428
|
-
|
1429
|
-
if volume_action == 'delete'
|
1430
|
-
# deleted volume is just excluded from post params
|
1431
|
-
next
|
1432
|
-
elsif volume_action == 'keep'
|
1433
|
-
volume = {
|
1434
|
-
'id' => current_volume['id'].to_i,
|
1435
|
-
'rootVolume' => false,
|
1436
|
-
'name' => current_volume['name'],
|
1437
|
-
'size' => current_volume['size'] > (plan_size || 0) ? current_volume['size'] : plan_size,
|
1438
|
-
'sizeId' => nil,
|
1439
|
-
'storageType' => (current_volume['type'] || current_volume['storageType']),
|
1440
|
-
'datastoreId' => current_volume['datastoreId']
|
1441
|
-
}
|
1442
|
-
volumes << volume
|
1443
|
-
else
|
1444
|
-
# 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])
|
1445
|
-
# storage_type_id = v_prompt[field_context]['storageType']
|
1446
|
-
storage_type_id = current_volume['type'] || current_volume['storageType']
|
1447
|
-
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
1448
|
-
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
1449
|
-
custom_size_options = []
|
1450
|
-
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
1451
|
-
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
1452
|
-
if !opt.nil?
|
1453
|
-
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
1454
|
-
end
|
1455
|
-
end
|
1456
|
-
end
|
1574
|
+
volumes << volume
|
1457
1575
|
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
if plan_info['customizeVolume'] && storage_type['customLabel']
|
1469
|
-
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])
|
1470
|
-
volume['name'] = v_prompt[field_context]['name']
|
1471
|
-
end
|
1472
|
-
if plan_info['customizeVolume'] && storage_type['customSize']
|
1473
|
-
if custom_size_options.empty?
|
1474
|
-
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])
|
1475
|
-
volume['size'] = v_prompt[field_context]['size']
|
1476
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
1477
|
-
else
|
1478
|
-
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])
|
1479
|
-
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1480
|
-
volume['size'] = nil #volume.delete('size')
|
1481
|
-
end
|
1482
|
-
else
|
1483
|
-
# might need different logic here ? =o
|
1484
|
-
# volume['size'] = plan_size
|
1485
|
-
# volume['sizeId'] = nil #volume.delete('sizeId')
|
1486
|
-
end
|
1487
|
-
# if !datastore_options.empty?
|
1488
|
-
# 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])
|
1489
|
-
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
1490
|
-
# 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
|
1584
|
+
|
1585
|
+
end
|
1491
1586
|
|
1492
|
-
|
1587
|
+
end
|
1493
1588
|
|
1494
|
-
|
1589
|
+
return volumes
|
1590
|
+
end
|
1495
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'}
|
1496
1614
|
end
|
1615
|
+
else
|
1616
|
+
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
1497
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
|
1498
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
|
1499
1638
|
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
end
|
1522
|
-
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]
|
1523
1660
|
end
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
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
|
1539
1710
|
end
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
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])
|
1547
|
-
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
1548
|
-
volume['size'] = nil #volume.delete('size')
|
1549
|
-
end
|
1550
|
-
else
|
1551
|
-
# might need different logic here ? =o
|
1552
|
-
# volume['size'] = plan_size
|
1553
|
-
# 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}")
|
1554
1717
|
end
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
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
|
1561
1730
|
end
|
1562
|
-
|
1563
|
-
datastore_options = []
|
1731
|
+
bus_number = next_bus_number
|
1564
1732
|
end
|
1565
1733
|
end
|
1566
|
-
|
1567
|
-
|
1568
|
-
|
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}")
|
1569
1746
|
end
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
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
|
1580
1782
|
end
|
1581
|
-
|
1582
1783
|
end
|
1583
|
-
|
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
|
1584
1790
|
end
|
1585
|
-
|
1586
|
-
|
1791
|
+
else
|
1792
|
+
# storage controllers not supported, carry on then
|
1587
1793
|
end
|
1588
|
-
|
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
|
1589
1800
|
|
1590
1801
|
# This recreates the behavior of multi_networks.js
|
1591
1802
|
# This is used by both `instances add` and `hosts add`
|