morpheus-cli 5.5.3.1 → 6.0.0

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +8 -0
  4. data/lib/morpheus/api/cloud_resource_pools_interface.rb +28 -3
  5. data/lib/morpheus/api/containers_interface.rb +10 -0
  6. data/lib/morpheus/api/doc_interface.rb +1 -10
  7. data/lib/morpheus/api/key_pairs_interface.rb +9 -0
  8. data/lib/morpheus/api/network_floating_ips_interface.rb +37 -0
  9. data/lib/morpheus/api/resource_pool_groups_interface.rb +51 -0
  10. data/lib/morpheus/cli/cli_command.rb +17 -11
  11. data/lib/morpheus/cli/commands/appliance_settings_command.rb +5 -0
  12. data/lib/morpheus/cli/commands/apps.rb +11 -5
  13. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +42 -12
  14. data/lib/morpheus/cli/commands/clusters.rb +23 -2
  15. data/lib/morpheus/cli/commands/containers_command.rb +129 -4
  16. data/lib/morpheus/cli/commands/doc.rb +14 -13
  17. data/lib/morpheus/cli/commands/hosts.rb +2 -0
  18. data/lib/morpheus/cli/commands/instances.rb +8 -2
  19. data/lib/morpheus/cli/commands/key_pairs.rb +94 -33
  20. data/lib/morpheus/cli/commands/network_floating_ips.rb +109 -0
  21. data/lib/morpheus/cli/commands/reports_command.rb +8 -1
  22. data/lib/morpheus/cli/commands/resource_pool_groups_command.rb +586 -0
  23. data/lib/morpheus/cli/commands/roles.rb +10 -10
  24. data/lib/morpheus/cli/commands/service_catalog_command.rb +44 -2
  25. data/lib/morpheus/cli/commands/tasks.rb +1 -1
  26. data/lib/morpheus/cli/commands/workflows.rb +1 -1
  27. data/lib/morpheus/cli/credentials.rb +2 -1
  28. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +148 -0
  29. data/lib/morpheus/cli/option_types.rb +15 -8
  30. data/lib/morpheus/cli/version.rb +1 -1
  31. data/lib/morpheus/cli.rb +13 -0
  32. data/test/cli/doc_test.rb +1 -1
  33. data/test/test_case.rb +3 -0
  34. metadata +6 -2
@@ -661,7 +661,8 @@ EOT
661
661
  it
662
662
  }
663
663
  if catalog_option_types && !catalog_option_types.empty?
664
- config_prompt = Morpheus::Cli::OptionTypes.prompt(catalog_option_types, options[:options], @api_client, {})['config']
664
+ api_params = construct_catalog_api_params(catalog_item_type)
665
+ config_prompt = Morpheus::Cli::OptionTypes.prompt(catalog_option_types, options[:options], @api_client, api_params, options[:no_prompt], false, false, true)['config']
665
666
  payload[add_item_object_key].deep_merge!({'config' => config_prompt})
666
667
  end
667
668
  if workflow_context
@@ -999,11 +1000,13 @@ EOT
999
1000
  catalog_option_types = catalog_item_type['optionTypes']
1000
1001
  # instead of config.customOptions just use config...
1001
1002
  catalog_option_types = catalog_option_types.collect {|it|
1003
+ it['fieldContext'] = nil
1002
1004
  it['fieldContext'] = 'config'
1003
1005
  it
1004
1006
  }
1005
1007
  if catalog_option_types && !catalog_option_types.empty?
1006
- config_prompt = Morpheus::Cli::OptionTypes.prompt(catalog_option_types, options[:options], @api_client, {})['config']
1008
+ api_params = construct_catalog_api_params(catalog_item_type)
1009
+ config_prompt = Morpheus::Cli::OptionTypes.prompt(catalog_option_types, options[:options], @api_client, api_params, options[:no_prompt], false, false, true)['config']
1007
1010
  item_payload.deep_merge!({'config' => config_prompt})
1008
1011
  end
1009
1012
 
@@ -1123,6 +1126,14 @@ EOT
1123
1126
  opts.on('--releaseEIPs [true|false]', String, "Release EIPs. Default is on. Applies to Amazon only.") do |val|
1124
1127
  params[:releaseEIPs] = ['true','on','1',''].include?(val.to_s.downcase)
1125
1128
  end
1129
+ opts.on('--release-ips [on|off]', ['on','off'], "Release Floating IPs. Default is on. Applies to certain types only.") do |val|
1130
+ params[:releaseFloatingIps] = ['true','on','1',''].include?(val.to_s.downcase)
1131
+ params[:releaseEIPs] = params[:releaseFloatingIps] # old parameter before 6.0
1132
+ end
1133
+ opts.on('--releaseEIPs [on|off]', ['on','off'], "Alias for Release Floating IPs") do |val|
1134
+ params[:releaseFloatingIps] = ['true','on','1',''].include?(val.to_s.downcase)
1135
+ params[:releaseEIPs] = params[:releaseFloatingIps] # old parameter before 6.0
1136
+ end
1126
1137
  opts.on( '-f', '--force', "Force Delete" ) do
1127
1138
  params[:force] = true
1128
1139
  end
@@ -1471,4 +1482,35 @@ EOT
1471
1482
  out + return_color
1472
1483
  end
1473
1484
 
1485
+
1486
+ def construct_catalog_api_params(record)
1487
+ catalog_item_type_id = record['id'].to_i
1488
+ api_params = {}
1489
+ api_params['catalogItemType'] ||= {}
1490
+ api_params['catalogItemType']['id'] = catalog_item_type_id
1491
+ # Determine instance.type value
1492
+ # the UI is injecting this parameter into the option source requests
1493
+ # it is needed to populate api option lists eg. optionTypeClouds
1494
+ # this should be fixed on the api side, so it automatically extracts this input from the config
1495
+ begin
1496
+ instance_type_code = nil
1497
+ catalog_item_type = find_by_id(:catalog_item_type, catalog_item_type_id.to_i)
1498
+ if catalog_item_type
1499
+ if catalog_item_type['type'] == 'instance'
1500
+ if catalog_item_type['config'] && catalog_item_type['config']['type']
1501
+ instance_type_code = catalog_item_type['config']['type']
1502
+ end
1503
+ end
1504
+ end
1505
+ if instance_type_code
1506
+ api_params['instance'] ||= {}
1507
+ api_params['instance']['type'] = instance_type_code
1508
+ end
1509
+ rescue ::RestClient::Exception => e
1510
+ # users may not have permission to this endpoint
1511
+ # puts "Failed to load catalog item type"
1512
+ end
1513
+ return api_params
1514
+ end
1515
+
1474
1516
  end
@@ -902,7 +902,7 @@ class Morpheus::Cli::Tasks
902
902
  opts.on(nil, '--no-refresh', "Do not refresh" ) do
903
903
  options[:no_refresh] = true
904
904
  end
905
- build_common_options(opts, options, [:options, :json, :dry_run, :remote])
905
+ build_standard_post_options(opts, options)
906
906
  end
907
907
  optparse.parse!(args)
908
908
  if args.count != 1
@@ -593,7 +593,7 @@ class Morpheus::Cli::Workflows
593
593
  opts.on(nil, '--no-refresh', "Do not refresh" ) do
594
594
  options[:no_refresh] = true
595
595
  end
596
- build_common_options(opts, options, [:payload, :options, :json, :dry_run, :remote])
596
+ build_standard_post_options(opts, options)
597
597
  end
598
598
  optparse.parse!(args)
599
599
  if args.count != 1
@@ -123,7 +123,8 @@ module Morpheus
123
123
  end
124
124
  if password.empty?
125
125
  # readline is still echoing secret with 'NUL:'' so just use $stdin on windows for now
126
- if Morpheus::Cli.windows?
126
+ # and some other environments? just use noecho unless running unit tests
127
+ if Morpheus::Cli.windows? || !Morpheus::Cli.testing?
127
128
  print "Password: #{required_blue_prompt} "
128
129
  # this should be my_terminal.stdin instead of STDIN and $stdin
129
130
  password = $stdin.noecho(&:gets).chomp!
@@ -39,6 +39,18 @@ module Morpheus::Cli::InfrastructureHelper
39
39
  @network_groups_interface
40
40
  end
41
41
 
42
+ def resource_pool_groups_interface
43
+ # @api_client.resource_pool_groups
44
+ raise "#{self.class} has not defined @resource_pool_groups_interface" if @resource_pool_groups_interface.nil?
45
+ @resource_pool_groups_interface
46
+ end
47
+
48
+ def resource_pools_interface
49
+ # @api_client.resource_pool_groups
50
+ raise "#{self.class} has not defined @cloud_resource_pools_interface" if @cloud_resource_pools_interface.nil?
51
+ @cloud_resource_pools_interface
52
+ end
53
+
42
54
  def network_types_interface
43
55
  # @api_client.network_types
44
56
  raise "#{self.class} has not defined @network_types_interface" if @network_types_interface.nil?
@@ -343,6 +355,86 @@ module Morpheus::Cli::InfrastructureHelper
343
355
  end
344
356
  end
345
357
 
358
+ def find_resource_pool_by_name_or_id(val)
359
+ if val.to_s =~ /\A\d{1,}\Z/
360
+ return find_resource_pool_by_id(val)
361
+ else
362
+ return find_resource_pool_by_name(val)
363
+ end
364
+ end
365
+
366
+ def find_resource_pool_by_id(id)
367
+ begin
368
+ json_response = resource_pools_interface.get_without_cloud(id.to_i)
369
+ return json_response['resourcePool']
370
+ rescue RestClient::Exception => e
371
+ if e.response && e.response.code == 404
372
+ print_red_alert "Resource Pool not found by id #{id}"
373
+ return nil
374
+ else
375
+ raise e
376
+ end
377
+ end
378
+ end
379
+
380
+ def find_resource_pool_by_name(name)
381
+ json_response = resource_pools_interface.list_without_cloud({name: name.to_s})
382
+ resource_pools = json_response['resourcePools']
383
+ if resource_pools.empty?
384
+ print_red_alert "Resource Pool not found by name #{name}"
385
+ return nil
386
+ elsif resource_pools.size > 1
387
+ print_red_alert "#{resource_pools.size} resource pools found by name #{name}"
388
+ rows = resource_pools.collect do |it|
389
+ {id: it['id'], name: it['name']}
390
+ end
391
+ puts as_pretty_table(rows, [:id, :name], {color:red})
392
+ return nil
393
+ else
394
+ return resource_pools[0]
395
+ end
396
+ end
397
+
398
+ def find_resource_pool_group_by_name_or_id(val)
399
+ if val.to_s =~ /\A\d{1,}\Z/
400
+ return find_resource_pool_group_by_id(val)
401
+ else
402
+ return find_resource_pool_group_by_name(val)
403
+ end
404
+ end
405
+
406
+ def find_resource_pool_group_by_id(id)
407
+ begin
408
+ json_response = resource_pool_groups_interface.get(id.to_i)
409
+ return json_response['resourcePoolGroup']
410
+ rescue RestClient::Exception => e
411
+ if e.response && e.response.code == 404
412
+ print_red_alert "Resource Pool Group not found by id #{id}"
413
+ return nil
414
+ else
415
+ raise e
416
+ end
417
+ end
418
+ end
419
+
420
+ def find_resource_pool_group_by_name(name)
421
+ json_response = resource_pool_groups_interface.list({name: name.to_s})
422
+ resource_pool_groups = json_response['resourcePoolGroups']
423
+ if resource_pool_groups.empty?
424
+ print_red_alert "Resource Pool Group not found by name #{name}"
425
+ return nil
426
+ elsif resource_pool_groups.size > 1
427
+ print_red_alert "#{resource_pool_groups.size} resource pool groups found by name #{name}"
428
+ rows = resource_pool_groups.collect do |it|
429
+ {id: it['id'], name: it['name']}
430
+ end
431
+ puts as_pretty_table(rows, [:id, :name], {color:red})
432
+ return nil
433
+ else
434
+ return resource_pool_groups[0]
435
+ end
436
+ end
437
+
346
438
  def prompt_for_network(network_id, options={}, required=true, field_name='network', field_label='Network')
347
439
  # Prompt for a Network, text input that searches by name or id
348
440
  network = nil
@@ -479,6 +571,62 @@ module Morpheus::Cli::InfrastructureHelper
479
571
  return {success:true, data: record_ids}
480
572
  end
481
573
 
574
+ def prompt_for_pools(params, options={}, api_client=nil, api_params={})
575
+ # Pools
576
+ pool_list = nil
577
+ pool_ids = nil
578
+ still_prompting = true
579
+ if params['pools'].nil?
580
+ still_prompting = true
581
+ while still_prompting do
582
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'pools', 'type' => 'text', 'fieldLabel' => 'Pools', 'required' => false, 'description' => 'Pools to include, comma separated list of names or IDs.'}], options[:options])
583
+ unless v_prompt['pools'].to_s.empty?
584
+ pool_list = v_prompt['pools'].split(",").collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
585
+ end
586
+ pool_ids = []
587
+ bad_ids = []
588
+ if pool_list && pool_list.size > 0
589
+ pool_list.each do |it|
590
+ found_pool = nil
591
+ begin
592
+ found_pool = find_resource_pool_by_name_or_id(it)
593
+ rescue SystemExit => cmdexit
594
+ end
595
+ if found_pool
596
+ pool_ids << found_pool['id']
597
+ else
598
+ bad_ids << it
599
+ end
600
+ end
601
+ end
602
+ still_prompting = bad_ids.empty? ? false : true
603
+ end
604
+ else
605
+ pool_list = params['pools']
606
+ still_prompting = false
607
+ pool_ids = []
608
+ bad_ids = []
609
+ if pool_list && pool_list.size > 0
610
+ pool_list.each do |it|
611
+ found_pool = nil
612
+ begin
613
+ found_pool = find_resource_pool_by_name_or_id(it)
614
+ rescue SystemExit => cmdexit
615
+ end
616
+ if found_pool
617
+ pool_ids << found_pool['id']
618
+ else
619
+ bad_ids << it
620
+ end
621
+ end
622
+ end
623
+ if !bad_ids.empty?
624
+ return {success:false, msg:"Pools not found: #{bad_ids}"}
625
+ end
626
+ end
627
+ return {success:true, data: pool_ids}
628
+ end
629
+
482
630
  def network_pool_server_list_column_definitions(options)
483
631
  {
484
632
  "ID" => 'id',
@@ -55,7 +55,7 @@ module Morpheus
55
55
  end
56
56
  end
57
57
 
58
- def self.prompt(option_types, options={}, api_client=nil, api_params={}, no_prompt=false, paging_enabled=false, ignore_empty=false)
58
+ def self.prompt(option_types, options={}, api_client=nil, api_params={}, no_prompt=false, paging_enabled=false, ignore_empty=false, skip_sort = false)
59
59
  paging_enabled = false if Morpheus::Cli.windows?
60
60
  no_prompt = no_prompt || options[:no_prompt]
61
61
  results = {}
@@ -89,12 +89,18 @@ module Morpheus
89
89
  # puts "Options Prompt #{options}"
90
90
  # Sort options by default, group, advanced
91
91
  # add displayOrder if it's missing, so it doesn't end up using a random order
92
- if !option_types.find {|it| it['displayOrder'] }
93
- option_types.each_with_index {|it, i| it['displayOrder'] = i+1 }
94
- end
92
+ # if !option_types.find {|it| it['displayOrder'] && it['displayOrder'] != 0 }
93
+ # option_types.each_with_index {|it, i| it['displayOrder'] = i+1 }
94
+ # end
95
95
  cur_field_group = 'default'
96
96
  prompt_local_credentials = true
97
- self.sort_option_types(option_types.reject {|it| it[:for_help_only]}).each do |option_type|
97
+ # reject help only options..
98
+ option_types.reject! {|it| it[:for_help_only]}
99
+ # sort options
100
+ if !skip_sort
101
+ option_types = self.sort_option_types(option_types)
102
+ end
103
+ option_types.each do |option_type|
98
104
  next if option_type['localCredential'] && !prompt_local_credentials
99
105
  context_map = results
100
106
  value = nil
@@ -672,7 +678,7 @@ module Morpheus
672
678
  # print "Perhaps you meant one of these? #{ored_list(matched_options.collect {|i|i[value_field]}, 3)}\n"
673
679
  print "Try using value instead of name.\n"
674
680
  print "\n"
675
- exit 1
681
+ #exit 1
676
682
  elsif matched_options.size == 1
677
683
  matched_option = matched_options[0]
678
684
  end
@@ -998,8 +1004,9 @@ module Morpheus
998
1004
  def self.password_prompt(option_type)
999
1005
  value_found = false
1000
1006
  while !value_found do
1001
- # readline is still echoing secret with 'NUL:'' so just use $stdin on windows for now
1002
- if Morpheus::Cli.windows?
1007
+ # readline is still echoing secret with 'NUL:'' so just use $stdin on windows
1008
+ # and some other environments? just use noecho unless running unit tests
1009
+ if Morpheus::Cli.windows? || !Morpheus::Cli.testing?
1003
1010
  print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+'************'+']' : ''}: "
1004
1011
  input = $stdin.noecho(&:gets).chomp!
1005
1012
  else
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "5.5.3.1"
4
+ VERSION = "6.0.0"
5
5
  end
6
6
  end
data/lib/morpheus/cli.rb CHANGED
@@ -77,6 +77,19 @@ module Morpheus
77
77
  Dir[File.dirname(__FILE__) + "/cli/commands/**/*.rb"].each {|file| load file }
78
78
  end
79
79
 
80
+ # hack needed for unit tests right now
81
+ @@testing = false unless defined?(@@testing)
82
+
83
+ # hack needed for unit tests right now
84
+ def self.enable_test_mode
85
+ @@testing = true
86
+ end
87
+
88
+ # hack needed for unit tests right now
89
+ def self.testing?
90
+ defined?(@@testing) && @@testing == true
91
+ end
92
+
80
93
  # require all CLI modules now (on require)
81
94
  load!
82
95
 
data/test/cli/doc_test.rb CHANGED
@@ -28,7 +28,7 @@ class MorpheusTest::DocTest < MorpheusTest::TestCase
28
28
  def test_doc_get_unauthorized
29
29
  # authentication is NOT required for this api
30
30
  without_authentication do
31
- assert_success("doc get -q")
31
+ assert_error("doc get -q")
32
32
  end
33
33
  end
34
34
 
data/test/test_case.rb CHANGED
@@ -5,6 +5,9 @@ require 'morpheus'
5
5
  require 'test_config'
6
6
  #require 'securerandom'
7
7
 
8
+ # hack needed for unit tests right now
9
+ Morpheus::Cli.enable_test_mode()
10
+
8
11
  module MorpheusTest
9
12
 
10
13
  # TestCase is the base class for all unit tests to provide standard behavior
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.5.3.1
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-01-19 00:00:00.000000000 Z
14
+ date: 2023-03-02 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -280,6 +280,7 @@ files:
280
280
  - lib/morpheus/api/network_domain_records_interface.rb
281
281
  - lib/morpheus/api/network_domains_interface.rb
282
282
  - lib/morpheus/api/network_edge_clusters_interface.rb
283
+ - lib/morpheus/api/network_floating_ips_interface.rb
283
284
  - lib/morpheus/api/network_groups_interface.rb
284
285
  - lib/morpheus/api/network_pool_ips_interface.rb
285
286
  - lib/morpheus/api/network_pool_server_types_interface.rb
@@ -313,6 +314,7 @@ files:
313
314
  - lib/morpheus/api/provisioning_settings_interface.rb
314
315
  - lib/morpheus/api/read_interface.rb
315
316
  - lib/morpheus/api/reports_interface.rb
317
+ - lib/morpheus/api/resource_pool_groups_interface.rb
316
318
  - lib/morpheus/api/rest_interface.rb
317
319
  - lib/morpheus/api/roles_interface.rb
318
320
  - lib/morpheus/api/scale_thresholds_interface.rb
@@ -455,6 +457,7 @@ files:
455
457
  - lib/morpheus/cli/commands/network_domains_command.rb
456
458
  - lib/morpheus/cli/commands/network_edge_clusters_command.rb
457
459
  - lib/morpheus/cli/commands/network_firewalls_command.rb
460
+ - lib/morpheus/cli/commands/network_floating_ips.rb
458
461
  - lib/morpheus/cli/commands/network_groups_command.rb
459
462
  - lib/morpheus/cli/commands/network_pool_server_types.rb
460
463
  - lib/morpheus/cli/commands/network_pool_servers_command.rb
@@ -483,6 +486,7 @@ files:
483
486
  - lib/morpheus/cli/commands/recent_activity_command.rb
484
487
  - lib/morpheus/cli/commands/remote.rb
485
488
  - lib/morpheus/cli/commands/reports_command.rb
489
+ - lib/morpheus/cli/commands/resource_pool_groups_command.rb
486
490
  - lib/morpheus/cli/commands/rm_command.rb
487
491
  - lib/morpheus/cli/commands/roles.rb
488
492
  - lib/morpheus/cli/commands/scale_thresholds.rb