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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +12 -1
  4. data/lib/morpheus/api/catalog_item_types_interface.rb +17 -0
  5. data/lib/morpheus/api/clusters_interface.rb +12 -0
  6. data/lib/morpheus/api/credential_types_interface.rb +9 -0
  7. data/lib/morpheus/api/credentials_interface.rb +9 -0
  8. data/lib/morpheus/api/instances_interface.rb +28 -0
  9. data/lib/morpheus/api/monitoring_apps_interface.rb +12 -4
  10. data/lib/morpheus/api/monitoring_checks_interface.rb +12 -4
  11. data/lib/morpheus/api/monitoring_groups_interface.rb +13 -5
  12. data/lib/morpheus/api/monitoring_incidents_interface.rb +12 -4
  13. data/lib/morpheus/api/options_interface.rb +8 -1
  14. data/lib/morpheus/api/ping_interface.rb +2 -0
  15. data/lib/morpheus/api/power_schedules_interface.rb +2 -2
  16. data/lib/morpheus/api/service_plans_interface.rb +6 -0
  17. data/lib/morpheus/api/setup_interface.rb +4 -0
  18. data/lib/morpheus/api/snapshots_interface.rb +19 -0
  19. data/lib/morpheus/cli/cli_command.rb +10 -17
  20. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +156 -1
  21. data/lib/morpheus/cli/commands/clusters.rb +177 -50
  22. data/lib/morpheus/cli/commands/credential_types_command.rb +36 -0
  23. data/lib/morpheus/cli/commands/credentials_command.rb +124 -0
  24. data/lib/morpheus/cli/commands/hosts.rb +32 -2
  25. data/lib/morpheus/cli/commands/instances.rb +255 -2
  26. data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
  27. data/lib/morpheus/cli/commands/monitoring_apps_command.rb +8 -8
  28. data/lib/morpheus/cli/commands/monitoring_checks_command.rb +8 -8
  29. data/lib/morpheus/cli/commands/monitoring_groups_command.rb +8 -8
  30. data/lib/morpheus/cli/commands/monitoring_incidents_command.rb +8 -8
  31. data/lib/morpheus/cli/commands/network_static_routes_command.rb +5 -0
  32. data/lib/morpheus/cli/commands/networks_command.rb +2 -2
  33. data/lib/morpheus/cli/commands/ping.rb +3 -5
  34. data/lib/morpheus/cli/commands/policies_command.rb +1 -1
  35. data/lib/morpheus/cli/commands/power_schedules_command.rb +189 -258
  36. data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
  37. data/lib/morpheus/cli/commands/remote.rb +16 -10
  38. data/lib/morpheus/cli/commands/security_groups.rb +2 -2
  39. data/lib/morpheus/cli/commands/service_plans_command.rb +52 -5
  40. data/lib/morpheus/cli/commands/setup.rb +1 -1
  41. data/lib/morpheus/cli/commands/snapshots.rb +139 -0
  42. data/lib/morpheus/cli/commands/storage_server_types.rb +0 -5
  43. data/lib/morpheus/cli/commands/storage_servers.rb +0 -6
  44. data/lib/morpheus/cli/commands/storage_volume_types.rb +0 -5
  45. data/lib/morpheus/cli/commands/storage_volumes.rb +0 -6
  46. data/lib/morpheus/cli/commands/tasks.rb +5 -5
  47. data/lib/morpheus/cli/commands/user_settings_command.rb +1 -1
  48. data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
  49. data/lib/morpheus/cli/mixins/provisioning_helper.rb +117 -27
  50. data/lib/morpheus/cli/mixins/rest_command.rb +20 -4
  51. data/lib/morpheus/cli/mixins/storage_servers_helper.rb +0 -63
  52. data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +0 -43
  53. data/lib/morpheus/cli/option_types.rb +27 -11
  54. data/lib/morpheus/cli/version.rb +1 -1
  55. data/lib/morpheus/routes.rb +13 -3
  56. 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
- if available_layouts.count > 1 && !options[:no_prompt]
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({max:1, computeTypeId: cluster_type['controllerTypes'].first['id'], zoneTypeId: cloud['zoneType']['id'], useZoneProvisionTypes: true})['serverTypes']
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
- controller_provision_type = controller_type['provisionType'] ? (@provision_types_interface.get(controller_type['provisionType']['id'])['provisionType'] rescue nil) : nil
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
- volumes = options[:volumes] || prompt_volumes(service_plan, options.merge({'defaultAddFirstDataVolume': true}), @api_client, api_params)
594
-
595
- if !volumes.empty?
596
- server_payload['volumes'] = volumes
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 []) + layout['optionTypes'] +
602
- (cluster_type['optionTypes'].reject { |type| !type['enabled'] || !type['creatable'] || type['fieldComponent'] } rescue [])).sort { |type| type['displayOrder'] }
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
- default_node_count = layout['computeServers'] ? (layout['computeServers'].find {|it| it['nodeType'] == 'worker'} || {'nodeCount' => 3})['nodeCount'] : 3
632
- server_payload['config']['nodeCount'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => "config.nodeCount", 'type' => 'number', 'fieldLabel' => "#{['docker', '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']
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
- 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']
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
- if !task_set_id.nil?
663
- server_payload['taskSet'] = {'id' => task_set_id}
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
- # custom max memory
3720
- if service_plan['customMaxMemory']
3721
- if !options[:maxMemory]
3722
- 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])
3723
- plan_options['maxMemory'] = v_prompt['maxMemory'] * 1024 * 1024 if v_prompt['maxMemory']
3724
- else
3725
- plan_options['maxMemory'] = options[:maxMemory]
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
- # custom cores: max cpu, max cores, cores per socket
3730
- if service_plan['customCores']
3731
- if options[:cpuCount].empty?
3732
- 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])
3733
- plan_options['cpuCount'] = v_prompt['cpuCount'] if v_prompt['cpuCount']
3734
- else
3735
- plan_options['cpuCount']
3736
- end
3737
- if options[:coreCount].empty?
3738
- 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])
3739
- plan_options['coreCount'] = v_prompt['coreCount'] if v_prompt['coreCount']
3740
- end
3741
- if options[:coresPerSocket].empty? && service_plan['coresPerSocket']
3742
- 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])
3743
- plan_options['coresPerSocket'] = v_prompt['coresPerSocket'] if v_prompt['coresPerSocket']
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)