morpheus-cli 5.4.2 → 5.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +12 -1
- data/lib/morpheus/api/catalog_item_types_interface.rb +17 -0
- data/lib/morpheus/api/clusters_interface.rb +12 -0
- data/lib/morpheus/api/credential_types_interface.rb +9 -0
- data/lib/morpheus/api/credentials_interface.rb +9 -0
- data/lib/morpheus/api/instances_interface.rb +28 -0
- data/lib/morpheus/api/monitoring_apps_interface.rb +12 -4
- data/lib/morpheus/api/monitoring_checks_interface.rb +12 -4
- data/lib/morpheus/api/monitoring_groups_interface.rb +13 -5
- data/lib/morpheus/api/monitoring_incidents_interface.rb +12 -4
- data/lib/morpheus/api/options_interface.rb +8 -1
- data/lib/morpheus/api/ping_interface.rb +2 -0
- data/lib/morpheus/api/power_schedules_interface.rb +2 -2
- data/lib/morpheus/api/service_plans_interface.rb +6 -0
- data/lib/morpheus/api/setup_interface.rb +4 -0
- data/lib/morpheus/api/snapshots_interface.rb +19 -0
- data/lib/morpheus/cli/cli_command.rb +10 -17
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +156 -1
- data/lib/morpheus/cli/commands/clusters.rb +177 -50
- data/lib/morpheus/cli/commands/credential_types_command.rb +36 -0
- data/lib/morpheus/cli/commands/credentials_command.rb +124 -0
- data/lib/morpheus/cli/commands/hosts.rb +32 -2
- data/lib/morpheus/cli/commands/instances.rb +255 -2
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
- data/lib/morpheus/cli/commands/monitoring_apps_command.rb +8 -8
- data/lib/morpheus/cli/commands/monitoring_checks_command.rb +8 -8
- data/lib/morpheus/cli/commands/monitoring_groups_command.rb +8 -8
- data/lib/morpheus/cli/commands/monitoring_incidents_command.rb +8 -8
- data/lib/morpheus/cli/commands/network_static_routes_command.rb +5 -0
- data/lib/morpheus/cli/commands/networks_command.rb +2 -2
- data/lib/morpheus/cli/commands/ping.rb +3 -5
- data/lib/morpheus/cli/commands/policies_command.rb +1 -1
- data/lib/morpheus/cli/commands/power_schedules_command.rb +189 -258
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
- data/lib/morpheus/cli/commands/remote.rb +16 -10
- data/lib/morpheus/cli/commands/security_groups.rb +2 -2
- data/lib/morpheus/cli/commands/service_plans_command.rb +52 -5
- data/lib/morpheus/cli/commands/setup.rb +1 -1
- data/lib/morpheus/cli/commands/snapshots.rb +139 -0
- data/lib/morpheus/cli/commands/storage_server_types.rb +0 -5
- data/lib/morpheus/cli/commands/storage_servers.rb +0 -6
- data/lib/morpheus/cli/commands/storage_volume_types.rb +0 -5
- data/lib/morpheus/cli/commands/storage_volumes.rb +0 -6
- data/lib/morpheus/cli/commands/tasks.rb +5 -5
- data/lib/morpheus/cli/commands/user_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +117 -27
- data/lib/morpheus/cli/mixins/rest_command.rb +20 -4
- data/lib/morpheus/cli/mixins/storage_servers_helper.rb +0 -63
- data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +0 -43
- data/lib/morpheus/cli/option_types.rb +27 -11
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/routes.rb +13 -3
- metadata +13 -7
@@ -8,7 +8,7 @@ class Morpheus::Cli::Clusters
|
|
8
8
|
include Morpheus::Cli::AccountsHelper
|
9
9
|
|
10
10
|
register_subcommands :list, :count, :get, :view, :add, :update, :remove, :logs, :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details}
|
11
|
-
register_subcommands :list_workers, :add_worker
|
11
|
+
register_subcommands :list_workers, :add_worker, :remove_worker, :update_worker_count
|
12
12
|
register_subcommands :list_masters
|
13
13
|
register_subcommands :list_volumes, :remove_volume
|
14
14
|
register_subcommands :list_namespaces, :get_namespace, :add_namespace, :update_namespace, :remove_namespace
|
@@ -547,11 +547,7 @@ class Morpheus::Cli::Clusters
|
|
547
547
|
available_layouts = layouts_for_dropdown(cloud['id'], cluster_type['id'])
|
548
548
|
|
549
549
|
if !available_layouts.empty?
|
550
|
-
|
551
|
-
layout_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'selectOptions' => available_layouts, 'required' => true, 'description' => 'Select Layout.'}],options[:options],@api_client,{})['layout']
|
552
|
-
else
|
553
|
-
layout_id = available_layouts.first['id']
|
554
|
-
end
|
550
|
+
layout_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'selectOptions' => available_layouts, 'required' => true, 'description' => 'Select Layout.'}],options[:options],@api_client,{})['layout']
|
555
551
|
layout = find_layout_by_name_or_id(layout_id)
|
556
552
|
end
|
557
553
|
end
|
@@ -560,17 +556,25 @@ class Morpheus::Cli::Clusters
|
|
560
556
|
|
561
557
|
# Provision Type
|
562
558
|
provision_type = (layout && layout['provisionType'] ? layout['provisionType'] : nil) || get_provision_type_for_zone_type(cloud['zoneType']['id'])
|
559
|
+
provision_type = @provision_types_interface.get(provision_type['id'])['provisionType'] if !provision_type.nil?
|
563
560
|
|
564
561
|
api_params = {zoneId: cloud['id'], siteId: group['id'], layoutId: layout['id'], groupTypeId: cluster_type['id'], provisionType: provision_type['code'], provisionTypeId: provision_type['id']}
|
565
562
|
|
566
563
|
# Controller type
|
567
|
-
server_types = @server_types_interface.list({
|
564
|
+
server_types = @server_types_interface.list({computeTypeId: cluster_type['controllerTypes'].first['id'], zoneTypeId: cloud['zoneType']['id'], useZoneProvisionTypes: true})['serverTypes'].reject {|it| it['provisionType']['code'] == 'manual'}
|
568
565
|
controller_provision_type = nil
|
569
566
|
resource_pool = nil
|
570
567
|
|
571
568
|
if !server_types.empty?
|
572
569
|
controller_type = server_types.first
|
573
|
-
|
570
|
+
|
571
|
+
if controller_type['provisionType']
|
572
|
+
if provision_type && provision_type['id'] == controller_type['provisionType']['id']
|
573
|
+
controller_provision_type = provision_type
|
574
|
+
else
|
575
|
+
controller_provision_type = @provision_types_interface.get(controller_type['provisionType']['id'])['provisionType'] rescue nil
|
576
|
+
end
|
577
|
+
end
|
574
578
|
|
575
579
|
if controller_provision_type && resource_pool = prompt_resource_pool(group, cloud, nil, controller_provision_type, options)
|
576
580
|
server_payload['config']['resourcePoolId'] = resource_pool['id']
|
@@ -585,21 +589,23 @@ class Morpheus::Cli::Clusters
|
|
585
589
|
service_plan = prompt_service_plan(api_params, options)
|
586
590
|
|
587
591
|
if service_plan
|
588
|
-
server_payload['plan'] = {'id' => service_plan['id'], 'code' => service_plan['code'], 'options' => prompt_service_plan_options(service_plan, options)}
|
592
|
+
server_payload['plan'] = {'id' => service_plan['id'], 'code' => service_plan['code'], 'options' => prompt_service_plan_options(service_plan, provision_type, options)}
|
589
593
|
api_params['planId'] = service_plan['id']
|
590
594
|
end
|
591
595
|
|
592
596
|
# Multi-disk / prompt for volumes
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
+
if provision_type['hasVolumes']
|
598
|
+
volumes = options[:volumes] || prompt_volumes(service_plan, provision_type, options.merge({'defaultAddFirstDataVolume': true}), @api_client, api_params)
|
599
|
+
if !volumes.empty?
|
600
|
+
server_payload['volumes'] = volumes
|
601
|
+
end
|
597
602
|
end
|
598
603
|
|
599
604
|
# Options / Custom Config
|
600
605
|
option_type_list =
|
601
|
-
((controller_type['optionTypes'].reject { |type| !type['enabled'] || type['fieldComponent'] } rescue []) +
|
602
|
-
|
606
|
+
((controller_type.nil? ? [] : controller_type['optionTypes'].reject { |type| !type['enabled'] || type['fieldComponent'] } rescue []) +
|
607
|
+
layout['optionTypes'] +
|
608
|
+
(cluster_type['optionTypes'].reject { |type| !type['enabled'] || !type['creatable'] || type['fieldComponent'] } rescue []))
|
603
609
|
|
604
610
|
# KLUDGE: google zone required for network selection
|
605
611
|
if option_type = option_type_list.find {|type| type['code'] == 'computeServerType.googleLinux.googleZoneId'}
|
@@ -625,11 +631,13 @@ class Morpheus::Cli::Clusters
|
|
625
631
|
cluster_payload.deep_merge!(Morpheus::Cli::OptionTypes.prompt(load_layout_options(cluster_payload), options[:options], @api_client, api_params, options[:no_prompt], true))
|
626
632
|
|
627
633
|
# Server options
|
628
|
-
server_payload.deep_merge!(Morpheus::Cli::OptionTypes.prompt(option_type_list, options[:options], @api_client, api_params, options[:no_prompt], true))
|
634
|
+
server_payload.deep_merge!(Morpheus::Cli::OptionTypes.prompt(option_type_list, options[:options].deep_merge({:context_map => {'domain' => ''}}), @api_client, api_params, options[:no_prompt], true))
|
629
635
|
|
630
636
|
# Worker count
|
631
|
-
|
632
|
-
|
637
|
+
if !['manual', 'external'].include?(provision_type['code'])
|
638
|
+
default_node_count = layout['computeServers'] ? (layout['computeServers'].find {|it| it['nodeType'] == 'worker'} || {'nodeCount' => 3})['nodeCount'] : 3
|
639
|
+
server_payload['config']['nodeCount'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => "config.nodeCount", 'type' => 'number', 'fieldLabel' => "#{['docker-cluster', 'kvm-cluster'].include?(cluster_type['code']) ? 'Host' : 'Worker'} Count", 'required' => true, 'defaultValue' => default_node_count > 0 ? default_node_count : 3}], options[:options], @api_client, api_params, options[:no_prompt])['config']['nodeCount']
|
640
|
+
end
|
633
641
|
|
634
642
|
# Create User
|
635
643
|
if !options[:createUser].nil?
|
@@ -657,10 +665,12 @@ class Morpheus::Cli::Clusters
|
|
657
665
|
server_payload['hostname'] = options[:hostname] || Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'hostname', 'fieldLabel' => 'Hostname', 'type' => 'text', 'required' => true, 'description' => 'Hostname', 'defaultValue' => resourceName}], options[:options], @api_client, api_params)['hostname']
|
658
666
|
|
659
667
|
# Workflow / Automation
|
660
|
-
|
668
|
+
if provision_type['code'] != 'manual' && controller_type && controller_type['hasAutomation']
|
669
|
+
task_set_id = options[:taskSetId] || Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'taskSet', 'fieldLabel' => 'Workflow', 'type' => 'select', 'required' => false, 'optionSource' => 'taskSets'}], options[:options], @api_client, api_params.merge({'phase' => 'postProvision'}))['taskSet']
|
661
670
|
|
662
|
-
|
663
|
-
|
671
|
+
if !task_set_id.nil?
|
672
|
+
server_payload['taskSet'] = {'id' => task_set_id}
|
673
|
+
end
|
664
674
|
end
|
665
675
|
|
666
676
|
cluster_payload['server'] = server_payload
|
@@ -1167,12 +1177,14 @@ class Morpheus::Cli::Clusters
|
|
1167
1177
|
cloud = @clouds_interface.get(cloud_id)['zone']
|
1168
1178
|
cloud['zoneType'] = get_cloud_type(cloud['zoneType']['id'])
|
1169
1179
|
group = @groups_interface.get(cluster['site']['id'])['group']
|
1170
|
-
|
1180
|
+
provision_type = server_type['provisionType'] || {}
|
1181
|
+
provision_type = @provision_types_interface.get(provision_type['id'])['provisionType'] if !provision_type.nil?
|
1182
|
+
|
1171
1183
|
server_payload['cloud'] = {'id' => cloud_id}
|
1172
1184
|
service_plan = prompt_service_plan({zoneId: cloud_id, siteId: cluster['site']['id'], provisionTypeId: server_type['provisionType']['id'], groupTypeId: cluster_type['id'], }, options)
|
1173
1185
|
|
1174
1186
|
if service_plan
|
1175
|
-
server_payload['plan'] = {'code' => service_plan['code'], 'options' => prompt_service_plan_options(service_plan, options)}
|
1187
|
+
server_payload['plan'] = {'code' => service_plan['code'], 'options' => prompt_service_plan_options(service_plan, nil, options)}
|
1176
1188
|
end
|
1177
1189
|
|
1178
1190
|
if resource_pool = prompt_resource_pool(cluster, cloud, service_plan, server_type['provisionType'], options)
|
@@ -1180,7 +1192,7 @@ class Morpheus::Cli::Clusters
|
|
1180
1192
|
end
|
1181
1193
|
|
1182
1194
|
# Multi-disk / prompt for volumes
|
1183
|
-
volumes = options[:volumes] || prompt_volumes(service_plan, options.merge({'defaultAddFirstDataVolume': true}), @api_client, {zoneId: cloud['id'], siteId: group['id']})
|
1195
|
+
volumes = options[:volumes] || prompt_volumes(service_plan, provision_type, options.merge({'defaultAddFirstDataVolume': true}), @api_client, {zoneId: cloud['id'], siteId: group['id']})
|
1184
1196
|
|
1185
1197
|
if !volumes.empty?
|
1186
1198
|
server_payload['volumes'] = volumes
|
@@ -1188,7 +1200,6 @@ class Morpheus::Cli::Clusters
|
|
1188
1200
|
|
1189
1201
|
# Networks
|
1190
1202
|
# NOTE: You must choose subnets in the same availability zone
|
1191
|
-
provision_type = server_type['provisionType'] || {}
|
1192
1203
|
if provision_type && cloud['zoneType']['code'] != 'esxi'
|
1193
1204
|
server_payload['networkInterfaces'] = options[:networkInterfaces] || prompt_network_interfaces(cloud['id'], server_type['provisionType']['id'], (resource_pool['id'] rescue nil), options)
|
1194
1205
|
end
|
@@ -1264,6 +1275,90 @@ class Morpheus::Cli::Clusters
|
|
1264
1275
|
end
|
1265
1276
|
end
|
1266
1277
|
|
1278
|
+
def remove_worker(args)
|
1279
|
+
params = {}
|
1280
|
+
options = {}
|
1281
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1282
|
+
opts.banner = subcommand_usage("[cluster] [worker]")
|
1283
|
+
opts.on( '-f', '--force', "Force Delete" ) do
|
1284
|
+
params[:force] = 'on'
|
1285
|
+
end
|
1286
|
+
build_standard_remove_options(opts, options)
|
1287
|
+
opts.footer = "Delete a worker from a cluster.\n" +
|
1288
|
+
"[cluster] is required. This is the name or id of an existing cluster.\n" +
|
1289
|
+
"[worker] is required. This is the name or (server) id of an existing worker."
|
1290
|
+
end
|
1291
|
+
optparse.parse!(args)
|
1292
|
+
verify_args!(args:args, optparse:optparse, count:2)
|
1293
|
+
connect(options)
|
1294
|
+
params.merge!(parse_query_options(options))
|
1295
|
+
|
1296
|
+
cluster = find_cluster_by_name_or_id(args[0])
|
1297
|
+
return 1 if cluster.nil?
|
1298
|
+
|
1299
|
+
worker_id = args[1]
|
1300
|
+
if worker_id.empty?
|
1301
|
+
raise_command_error "missing required worker parameter"
|
1302
|
+
end
|
1303
|
+
|
1304
|
+
worker = find_worker_by_name_or_id(cluster['id'], worker_id)
|
1305
|
+
if worker.nil?
|
1306
|
+
print_red_alert "Worker not found for '#{worker_id}'"
|
1307
|
+
return 1
|
1308
|
+
end
|
1309
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the cluster worker '#{worker['name'] || worker['id']}'?", options)
|
1310
|
+
return 9, "aborted command"
|
1311
|
+
end
|
1312
|
+
|
1313
|
+
@clusters_interface.setopts(options)
|
1314
|
+
if options[:dry_run]
|
1315
|
+
print_dry_run @clusters_interface.dry.destroy_worker(cluster['id'], worker['id'], params)
|
1316
|
+
return
|
1317
|
+
end
|
1318
|
+
json_response = @clusters_interface.destroy_worker(cluster['id'], worker['id'], params)
|
1319
|
+
render_response(json_response, options) do
|
1320
|
+
print_green_success "Worker #{worker['name']} is being removed from cluster #{cluster['name']}..."
|
1321
|
+
end
|
1322
|
+
return 0, nil
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
def update_worker_count(args)
|
1326
|
+
params = {}
|
1327
|
+
options = {}
|
1328
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1329
|
+
opts.banner = subcommand_usage("[cluster] [worker_count]")
|
1330
|
+
build_standard_update_options(opts, options)
|
1331
|
+
opts.footer = "Resizes a cluster to the specified number of worker nodes.\n" +
|
1332
|
+
"[cluster] is required. This is the name or id of an existing cluster.\n" +
|
1333
|
+
"[worker_count] is required. This is the desired number of workers."
|
1334
|
+
end
|
1335
|
+
optparse.parse!(args)
|
1336
|
+
verify_args!(args:args, optparse:optparse, count:2)
|
1337
|
+
connect(options)
|
1338
|
+
|
1339
|
+
cluster = find_cluster_by_name_or_id(args[0])
|
1340
|
+
return 1 if cluster.nil?
|
1341
|
+
|
1342
|
+
worker_count = args[1]
|
1343
|
+
payload = {}
|
1344
|
+
if options[:payload]
|
1345
|
+
payload = options[:payload]
|
1346
|
+
payload.deep_merge!({'workerCount' => worker_count.to_i})
|
1347
|
+
else
|
1348
|
+
payload.deep_merge!({'workerCount' => worker_count.to_i})
|
1349
|
+
end
|
1350
|
+
@clusters_interface.setopts(options)
|
1351
|
+
if options[:dry_run]
|
1352
|
+
print_dry_run @clusters_interface.dry.update_worker_count(cluster['id'], payload)
|
1353
|
+
return
|
1354
|
+
end
|
1355
|
+
json_response = @clusters_interface.update_worker_count(cluster['id'], payload)
|
1356
|
+
render_response(json_response, options) do
|
1357
|
+
print_green_success "Cluster #{cluster['name']} is being resized to #{worker_count} worker nodes..."
|
1358
|
+
end
|
1359
|
+
return 0, nil
|
1360
|
+
end
|
1361
|
+
|
1267
1362
|
def list_masters(args)
|
1268
1363
|
options = {}
|
1269
1364
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
@@ -3469,6 +3564,35 @@ class Morpheus::Cli::Clusters
|
|
3469
3564
|
out
|
3470
3565
|
end
|
3471
3566
|
|
3567
|
+
def find_worker_by_name_or_id(cluster_id, val)
|
3568
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
3569
|
+
find_worker_by_id(cluster_id, val.to_i)
|
3570
|
+
else
|
3571
|
+
find_worker_by_name(cluster_id, val)
|
3572
|
+
end
|
3573
|
+
|
3574
|
+
end
|
3575
|
+
|
3576
|
+
def find_worker_by_id(cluster_id, id)
|
3577
|
+
json_results = @clusters_interface.list_workers(cluster_id)
|
3578
|
+
filtered_results = json_results['workers'].select {|worker| worker['id'] == id}
|
3579
|
+
if filtered_results.empty? || filtered_results.count > 1
|
3580
|
+
print_red_alert "Worker not found by id #{id}"
|
3581
|
+
exit 1
|
3582
|
+
end
|
3583
|
+
filtered_results[0]
|
3584
|
+
end
|
3585
|
+
|
3586
|
+
def find_worker_by_name(cluster_id, name)
|
3587
|
+
params = {phrase: name}
|
3588
|
+
json_results = @clusters_interface.list_workers(cluster_id, params)
|
3589
|
+
if json_results['workers'].empty? || json_results['workers'].count > 1
|
3590
|
+
print_red_alert "Worker not found by name #{name}"
|
3591
|
+
exit 1
|
3592
|
+
end
|
3593
|
+
json_results['workers'][0]
|
3594
|
+
end
|
3595
|
+
|
3472
3596
|
def find_cluster_by_name_or_id(val)
|
3473
3597
|
if val.to_s =~ /\A\d{1,}\Z/
|
3474
3598
|
find_cluster_by_id(val)
|
@@ -3713,34 +3837,37 @@ class Morpheus::Cli::Clusters
|
|
3713
3837
|
service_plan
|
3714
3838
|
end
|
3715
3839
|
|
3716
|
-
def prompt_service_plan_options(service_plan, options)
|
3840
|
+
def prompt_service_plan_options(service_plan, provision_type, options)
|
3717
3841
|
plan_options = {}
|
3718
|
-
|
3719
|
-
|
3720
|
-
if
|
3721
|
-
|
3722
|
-
|
3723
|
-
|
3724
|
-
|
3725
|
-
|
3842
|
+
hide_custom_options = provision_type && provision_type['code'] == 'manual'
|
3843
|
+
|
3844
|
+
if !hide_custom_options
|
3845
|
+
# custom max memory
|
3846
|
+
if service_plan['customMaxMemory']
|
3847
|
+
if !options[:maxMemory]
|
3848
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'maxMemory', 'type' => 'number', 'fieldLabel' => 'Max Memory (MB)', 'required' => false, 'description' => 'This will override any memory requirement set on the virtual image', 'defaultValue' => service_plan['maxMemory'] ? service_plan['maxMemory'] / (1024 * 1024) : 10 }], options[:options])
|
3849
|
+
plan_options['maxMemory'] = v_prompt['maxMemory'] * 1024 * 1024 if v_prompt['maxMemory']
|
3850
|
+
else
|
3851
|
+
plan_options['maxMemory'] = options[:maxMemory]
|
3852
|
+
end
|
3726
3853
|
end
|
3727
|
-
end
|
3728
3854
|
|
3729
|
-
|
3730
|
-
|
3731
|
-
|
3732
|
-
|
3733
|
-
|
3734
|
-
|
3735
|
-
|
3736
|
-
|
3737
|
-
|
3738
|
-
|
3739
|
-
|
3740
|
-
|
3741
|
-
|
3742
|
-
|
3743
|
-
|
3855
|
+
# custom cores: max cpu, max cores, cores per socket
|
3856
|
+
if service_plan['customCores']
|
3857
|
+
if options[:cpuCount].empty?
|
3858
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cpuCount', 'type' => 'number', 'fieldLabel' => 'CPU Count', 'required' => false, 'description' => 'Set CPU Count', 'defaultValue' => service_plan['maxCpu'] ? service_plan['maxCpu'] : 1 }], options[:options])
|
3859
|
+
plan_options['cpuCount'] = v_prompt['cpuCount'] if v_prompt['cpuCount']
|
3860
|
+
else
|
3861
|
+
plan_options['cpuCount']
|
3862
|
+
end
|
3863
|
+
if options[:coreCount].empty?
|
3864
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'coreCount', 'type' => 'number', 'fieldLabel' => 'Core Count', 'required' => false, 'description' => 'Set Core Count', 'defaultValue' => service_plan['maxCores'] ? service_plan['maxCores'] : 1 }], options[:options])
|
3865
|
+
plan_options['coreCount'] = v_prompt['coreCount'] if v_prompt['coreCount']
|
3866
|
+
end
|
3867
|
+
if options[:coresPerSocket].empty? && service_plan['coresPerSocket']
|
3868
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'coresPerSocket', 'type' => 'number', 'fieldLabel' => 'Cores Per Socket', 'required' => false, 'description' => 'Set Core Per Socket', 'defaultValue' => service_plan['coresPerSocket']}], options[:options])
|
3869
|
+
plan_options['coresPerSocket'] = v_prompt['coresPerSocket'] if v_prompt['coresPerSocket']
|
3870
|
+
end
|
3744
3871
|
end
|
3745
3872
|
end
|
3746
3873
|
plan_options
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::CredentialTypesCommand
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
include Morpheus::Cli::RestCommand
|
6
|
+
|
7
|
+
set_command_description "View credential types"
|
8
|
+
set_command_name :'credential-types'
|
9
|
+
register_subcommands :list, :get
|
10
|
+
|
11
|
+
# register_interfaces :credential_types
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def credential_type_list_column_definitions(options)
|
16
|
+
{
|
17
|
+
"ID" => 'id',
|
18
|
+
"Name" => 'name',
|
19
|
+
"Code" => 'code',
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def credential_type_column_definitions(options)
|
24
|
+
{
|
25
|
+
"ID" => 'id',
|
26
|
+
"Name" => 'name',
|
27
|
+
"Code" => 'code',
|
28
|
+
# "Description" => 'description',
|
29
|
+
"Enabled" => lambda {|it| format_boolean(it['enabled']) },
|
30
|
+
"Creatable" => lambda {|it| format_boolean(it['creatable']) },
|
31
|
+
"Editable" => lambda {|it| format_boolean(it['editable']) },
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::CredentialsCommand
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
include Morpheus::Cli::RestCommand
|
6
|
+
|
7
|
+
set_command_name :'credentials'
|
8
|
+
set_command_description "View and manage credentials."
|
9
|
+
register_subcommands :list, :get, :add, :update, :remove
|
10
|
+
|
11
|
+
# RestCommand settings
|
12
|
+
register_interfaces :credentials, :credential_types
|
13
|
+
set_rest_has_type true
|
14
|
+
# set_rest_type :credential_types
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def render_response_for_get(json_response, options)
|
19
|
+
render_response(json_response, options, rest_object_key) do
|
20
|
+
record = json_response[rest_object_key]
|
21
|
+
print_h1 rest_label, [], options
|
22
|
+
print cyan
|
23
|
+
print_description_list(credential_column_definitions(options, record), record, options)
|
24
|
+
print reset,"\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def credential_list_column_definitions(options)
|
29
|
+
{
|
30
|
+
"ID" => 'id',
|
31
|
+
"Name" => 'name',
|
32
|
+
"Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def credential_column_definitions(options, credential)
|
37
|
+
columns = [
|
38
|
+
{"ID" => 'id' },
|
39
|
+
{"Credential Store" => lambda {|it| it['integration'] ? it['integration']['name'] : 'Internal'} },
|
40
|
+
{"Name" => 'name' },
|
41
|
+
{"Description" => 'description' },
|
42
|
+
{"Type" => lambda {|it| it['type'] ? it['type']['name'] : '' } },
|
43
|
+
{"Enabled" => lambda {|it| format_boolean(it['enabled']) } },
|
44
|
+
]
|
45
|
+
type_code = credential['type']['code']
|
46
|
+
if type_code == "access-key-secret"
|
47
|
+
columns += [
|
48
|
+
{"Access Key" => lambda {|it| it['username'] } },
|
49
|
+
{"Secret Key" => lambda {|it| it['password'] } },
|
50
|
+
]
|
51
|
+
elsif type_code == "client-id-secret"
|
52
|
+
columns += [
|
53
|
+
{"Client ID" => lambda {|it| it['username'] } },
|
54
|
+
{"Client Secret" => lambda {|it| it['password'] } },
|
55
|
+
]
|
56
|
+
elsif type_code == "email-private-key"
|
57
|
+
columns += [
|
58
|
+
{"Email" => lambda {|it| it['username'] } },
|
59
|
+
{"Private Key" => lambda {|it| it['authKey'] ? it['authKey']['name'] : '' } },
|
60
|
+
]
|
61
|
+
elsif type_code == "tenant-username-keypair" || type_code == "tenant-username-key"
|
62
|
+
columns += [
|
63
|
+
{"Tenant" => lambda {|it| it['authPath'] } },
|
64
|
+
{"Username" => lambda {|it| it['username'] } },
|
65
|
+
{"Private Key" => lambda {|it| it['authKey'] ? it['authKey']['name'] : '' } },
|
66
|
+
]
|
67
|
+
elsif type_code == "username-api-key"
|
68
|
+
columns += [
|
69
|
+
{"Username" => lambda {|it| it['username'] } },
|
70
|
+
{"API Key" => lambda {|it| it['password'] } },
|
71
|
+
]
|
72
|
+
elsif type_code == "username-keypair" || type_code == "username-key"
|
73
|
+
columns += [
|
74
|
+
{"Username" => lambda {|it| it['username'] } },
|
75
|
+
{"Private Key" => lambda {|it| it['authKey'] ? it['authKey']['name'] : '' } },
|
76
|
+
]
|
77
|
+
elsif type_code == "username-password"
|
78
|
+
columns += [
|
79
|
+
{"Username" => lambda {|it| it['username'] } },
|
80
|
+
{"Password" => lambda {|it| it['password'] } },
|
81
|
+
]
|
82
|
+
elsif type_code == "username-password-keypair" || type_code == "username-password-key"
|
83
|
+
columns += [
|
84
|
+
{"Username" => lambda {|it| it['username'] } },
|
85
|
+
{"Password" => lambda {|it| it['password'] } },
|
86
|
+
{"Private Key" => lambda {|it| it['authKey'] ? it['authKey']['name'] : '' } },
|
87
|
+
]
|
88
|
+
end
|
89
|
+
columns += [
|
90
|
+
{"Created" => lambda {|it| format_local_dt(it['dateCreated']) } },
|
91
|
+
{"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) } },
|
92
|
+
]
|
93
|
+
return columns
|
94
|
+
end
|
95
|
+
|
96
|
+
def add_credential_option_types()
|
97
|
+
[
|
98
|
+
{'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Credential Type', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
|
99
|
+
api_client.credential_types.list({max:10000})['credentialTypes'].collect { |it| {"name" => it["name"], "value" => it["code"]} }
|
100
|
+
}, 'required' => true},
|
101
|
+
{'fieldName' => 'integration.id', 'fieldLabel' => 'Credential Store', 'type' => 'select', 'optionSource' => 'credentialIntegrations'},
|
102
|
+
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
|
103
|
+
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false},
|
104
|
+
{'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'required' => false, 'defaultValue' => true},
|
105
|
+
]
|
106
|
+
end
|
107
|
+
|
108
|
+
def add_credential_advanced_option_types()
|
109
|
+
[]
|
110
|
+
end
|
111
|
+
|
112
|
+
def update_credential_option_types()
|
113
|
+
[
|
114
|
+
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text'},
|
115
|
+
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
|
116
|
+
{'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox'},
|
117
|
+
]
|
118
|
+
end
|
119
|
+
|
120
|
+
def update_credential_advanced_option_types()
|
121
|
+
add_credential_advanced_option_types()
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
@@ -29,6 +29,7 @@ class Morpheus::Cli::Hosts
|
|
29
29
|
@task_sets_interface = @api_client.task_sets
|
30
30
|
@servers_interface = @api_client.servers
|
31
31
|
@server_types_interface = @api_client.server_types
|
32
|
+
@provision_types_interface = @api_client.provision_types
|
32
33
|
@logs_interface = @api_client.logs
|
33
34
|
@accounts_interface = @api_client.accounts
|
34
35
|
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
@@ -854,6 +855,19 @@ class Morpheus::Cli::Hosts
|
|
854
855
|
# remove cpu and memory option types, which now come from the plan
|
855
856
|
option_type_list = reject_service_plan_option_types(option_type_list)
|
856
857
|
|
858
|
+
# need to GET provision type for optionTypes, and other settings...
|
859
|
+
provision_type_code = server_type["provisionType"] ? server_type["provisionType"]["code"] : nil
|
860
|
+
provision_type = nil
|
861
|
+
if provision_type_code
|
862
|
+
provision_type = provision_types_interface.list({code:provision_type_code})['provisionTypes'][0]
|
863
|
+
if provision_type.nil?
|
864
|
+
print_red_alert "Provision Type not found by code #{provision_type_code}"
|
865
|
+
exit 1
|
866
|
+
end
|
867
|
+
else
|
868
|
+
provision_type = get_provision_type_for_zone_type(cloud['zoneType']['id'])
|
869
|
+
end
|
870
|
+
|
857
871
|
# prompt for resource pool
|
858
872
|
pool_id = nil
|
859
873
|
has_zone_pools = server_type["provisionType"] && server_type["provisionType"]["hasZonePools"]
|
@@ -873,11 +887,17 @@ class Morpheus::Cli::Hosts
|
|
873
887
|
end
|
874
888
|
|
875
889
|
# prompt for volumes
|
876
|
-
volumes = prompt_volumes(service_plan, options, @api_client, {zoneId: cloud_id, serverTypeId: server_type['id'], siteId: group_id})
|
890
|
+
volumes = prompt_volumes(service_plan, provision_type, options, @api_client, {zoneId: cloud_id, serverTypeId: server_type['id'], siteId: group_id})
|
877
891
|
if !volumes.empty?
|
878
892
|
payload['volumes'] = volumes
|
879
893
|
end
|
880
894
|
|
895
|
+
# plan customizations
|
896
|
+
plan_opts = prompt_service_plan_options(service_plan, options, @api_client, {})
|
897
|
+
if plan_opts && !plan_opts.empty?
|
898
|
+
payload['servicePlanOptions'] = plan_opts
|
899
|
+
end
|
900
|
+
|
881
901
|
# prompt for network interfaces (if supported)
|
882
902
|
if server_type["provisionType"] && server_type["provisionType"]["id"] && server_type["provisionType"]["hasNetworks"]
|
883
903
|
begin
|
@@ -1220,6 +1240,10 @@ class Morpheus::Cli::Hosts
|
|
1220
1240
|
:server => {:id => server["id"]}
|
1221
1241
|
}
|
1222
1242
|
|
1243
|
+
# need to GET provision type for some settings...
|
1244
|
+
server_type = @server_types_interface.get(server_type_id)['serverType']
|
1245
|
+
provision_type = @provision_types_interface.get(server_type['provisionType']['id'])['provisionType']
|
1246
|
+
|
1223
1247
|
# avoid 500 error
|
1224
1248
|
# payload[:servicePlanOptions] = {}
|
1225
1249
|
unless options[:no_prompt]
|
@@ -1247,11 +1271,17 @@ class Morpheus::Cli::Hosts
|
|
1247
1271
|
current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
1248
1272
|
|
1249
1273
|
# prompt for volumes
|
1250
|
-
volumes = prompt_resize_volumes(current_volumes, service_plan, options)
|
1274
|
+
volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, options)
|
1251
1275
|
if !volumes.empty?
|
1252
1276
|
payload[:volumes] = volumes
|
1253
1277
|
end
|
1254
1278
|
|
1279
|
+
# plan customizations
|
1280
|
+
plan_opts = prompt_service_plan_options(service_plan, options, @api_client, {}, server)
|
1281
|
+
if plan_opts && !plan_opts.empty?
|
1282
|
+
payload['servicePlanOptions'] = plan_opts
|
1283
|
+
end
|
1284
|
+
|
1255
1285
|
# todo: reconfigure networks
|
1256
1286
|
# need to get provision_type_id for network info
|
1257
1287
|
# prompt for network interfaces (if supported)
|