morpheus-cli 5.4.5.1 → 5.5.1.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +12 -0
  4. data/lib/morpheus/api/backup_service_types_interface.rb +9 -0
  5. data/lib/morpheus/api/backup_services_interface.rb +9 -0
  6. data/lib/morpheus/api/clusters_interface.rb +12 -0
  7. data/lib/morpheus/api/network_pool_servers_interface.rb +7 -0
  8. data/lib/morpheus/api/prices_interface.rb +6 -0
  9. data/lib/morpheus/api/scale_thresholds_interface.rb +9 -0
  10. data/lib/morpheus/cli/cli_command.rb +55 -23
  11. data/lib/morpheus/cli/commands/apps.rb +1 -1
  12. data/lib/morpheus/cli/commands/backup_services_command.rb +44 -0
  13. data/lib/morpheus/cli/commands/cloud_resource_pools_command.rb +33 -2
  14. data/lib/morpheus/cli/commands/clouds.rb +67 -31
  15. data/lib/morpheus/cli/commands/clusters.rb +66 -5
  16. data/lib/morpheus/cli/commands/cypher_command.rb +22 -23
  17. data/lib/morpheus/cli/commands/hosts.rb +5 -1
  18. data/lib/morpheus/cli/commands/instances.rb +11 -11
  19. data/lib/morpheus/cli/commands/integrations_command.rb +1 -1
  20. data/lib/morpheus/cli/commands/invoices_command.rb +8 -1
  21. data/lib/morpheus/cli/commands/jobs_command.rb +45 -225
  22. data/lib/morpheus/cli/commands/library_container_types_command.rb +52 -3
  23. data/lib/morpheus/cli/commands/library_option_lists_command.rb +18 -8
  24. data/lib/morpheus/cli/commands/library_option_types_command.rb +56 -62
  25. data/lib/morpheus/cli/commands/load_balancers.rb +11 -19
  26. data/lib/morpheus/cli/commands/network_pool_servers_command.rb +5 -2
  27. data/lib/morpheus/cli/commands/prices_command.rb +25 -11
  28. data/lib/morpheus/cli/commands/roles.rb +475 -70
  29. data/lib/morpheus/cli/commands/scale_thresholds.rb +103 -0
  30. data/lib/morpheus/cli/commands/tasks.rb +64 -22
  31. data/lib/morpheus/cli/commands/user_sources_command.rb +107 -39
  32. data/lib/morpheus/cli/commands/users.rb +10 -10
  33. data/lib/morpheus/cli/commands/view.rb +1 -0
  34. data/lib/morpheus/cli/commands/workflows.rb +21 -14
  35. data/lib/morpheus/cli/error_handler.rb +13 -4
  36. data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
  37. data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
  38. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +3 -3
  39. data/lib/morpheus/cli/mixins/jobs_helper.rb +173 -0
  40. data/lib/morpheus/cli/mixins/print_helper.rb +120 -38
  41. data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -3
  42. data/lib/morpheus/cli/mixins/rest_command.rb +58 -15
  43. data/lib/morpheus/cli/option_types.rb +69 -13
  44. data/lib/morpheus/cli/version.rb +1 -1
  45. data/lib/morpheus/logging.rb +6 -8
  46. data/lib/morpheus/routes.rb +3 -5
  47. metadata +9 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84ddc5a04df52338a55327598f760d41e51d93d6a03fbebac557202c3a952116
4
- data.tar.gz: 3a586a705cd480573bd9da349c737a18761999096ec59bd77ce98a27a41f07d4
3
+ metadata.gz: a66201f045d6e88db90746058ce40000b064616975aae3d00c025069c51f20d7
4
+ data.tar.gz: de2b69e5a52ca31f7bde8d573428853a765668b2d08ba8eaca1cdbe6743ecf0a
5
5
  SHA512:
6
- metadata.gz: 43dab7d23d4e1889dfc611445dcd2da0c61dc8c7ec1245cddebea0469cede7ebfdeb453b718e0bbbc247b620be9ae4af5698f46bf1d0c689f38940894b112e7f
7
- data.tar.gz: fb08c98c2395a86b41df4fe8ce6aaa7b8d4306aa39461d849ee121a256cfcc733ab1aa58c171c6b181ca62c824a2b3e55c80a206194a5e4993d7495413472617
6
+ metadata.gz: ebc460c1903caf068710ac2512e73fb88329045a49ff603904e875ff2a02cb6a4ec02b34195d9ee19c98ab8eefb6388357d8c43cb69a8ad92891322a085f1dd1
7
+ data.tar.gz: 60a297a75a29a6bb53a3944b81fa14a9f46c846173bf98472886bb86a5a13491c55da9600fa691d861ba20812546b5d57e891a61a3b4dcef9c922ed3b43a3f9b
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.5.1
2
2
 
3
- RUN gem install morpheus-cli -v 5.4.5.1
3
+ RUN gem install morpheus-cli -v 5.5.1.1
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
@@ -590,6 +590,10 @@ class Morpheus::APIClient
590
590
  Morpheus::OptionTypeListsInterface.new(common_interface_options).setopts(@options)
591
591
  end
592
592
 
593
+ def scale_thresholds
594
+ Morpheus::ScaleThresholdsInterface.new(common_interface_options).setopts(@options)
595
+ end
596
+
593
597
  def power_schedules
594
598
  Morpheus::PowerSchedulesInterface.new(common_interface_options).setopts(@options)
595
599
  end
@@ -832,6 +836,14 @@ class Morpheus::APIClient
832
836
  Morpheus::BackupJobsInterface.new(common_interface_options).setopts(@options)
833
837
  end
834
838
 
839
+ def backup_services
840
+ Morpheus::BackupServicesInterface.new(common_interface_options).setopts(@options)
841
+ end
842
+
843
+ def backup_service_types
844
+ Morpheus::BackupServiceTypesInterface.new(common_interface_options).setopts(@options)
845
+ end
846
+
835
847
  def catalog_item_types
836
848
  Morpheus::CatalogItemTypesInterface.new(common_interface_options).setopts(@options)
837
849
  end
@@ -0,0 +1,9 @@
1
+ require 'morpheus/api/read_interface'
2
+
3
+ class Morpheus::BackupServiceTypesInterface < Morpheus::ReadInterface
4
+
5
+ def base_path
6
+ "/api/backup-service-types"
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'morpheus/api/rest_interface'
2
+
3
+ class Morpheus::BackupServicesInterface < Morpheus::RestInterface
4
+
5
+ def base_path
6
+ "/api/backup-services"
7
+ end
8
+
9
+ end
@@ -103,6 +103,18 @@ class Morpheus::ClustersInterface < Morpheus::APIClient
103
103
  execute(method: :put, url: url, headers: headers)
104
104
  end
105
105
 
106
+ def get_upgrade_versions(id, params={})
107
+ url = "#{base_path}/#{id}/upgrade-cluster"
108
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
109
+ execute(method: :get, url: url, headers: headers)
110
+ end
111
+
112
+ def do_cluster_upgrade(id, params={})
113
+ url = "#{base_path}/#{id}/upgrade-cluster"
114
+ headers = { params: params, authorization: "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
115
+ execute(method: :post, url: url, headers: headers)
116
+ end
117
+
106
118
  def list_services(id, params={})
107
119
  url = "#{base_path}/#{id}/services"
108
120
  headers = { params: params, authorization: "Bearer #{@access_token}" }
@@ -38,4 +38,11 @@ class Morpheus::NetworkPoolServersInterface < Morpheus::APIClient
38
38
  execute(opts)
39
39
  end
40
40
 
41
+ def get_type(id, params={})
42
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
43
+ url = "#{@base_url}/api/networks/pool-server-types/#{id}"
44
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
45
+ opts = {method: :get, url: url, headers: headers}
46
+ execute(opts)
47
+ end
41
48
  end
@@ -62,4 +62,10 @@ class Morpheus::PricesInterface < Morpheus::APIClient
62
62
  headers = { params: params, authorization: "Bearer #{@access_token}" }
63
63
  execute(method: :get, url: url, headers: headers)
64
64
  end
65
+
66
+ def list_currencies(params={})
67
+ url = "#{base_path}/currencies"
68
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
69
+ execute(method: :get, url: url, headers: headers)
70
+ end
65
71
  end
@@ -0,0 +1,9 @@
1
+ require 'morpheus/api/rest_interface'
2
+
3
+ class Morpheus::ScaleThresholdsInterface < Morpheus::RestInterface
4
+
5
+ def base_path
6
+ "/api/scale-thresholds"
7
+ end
8
+
9
+ end
@@ -253,7 +253,7 @@ module Morpheus
253
253
 
254
254
  # list is GET that supports phrase,max,offset,sort,direction
255
255
  def build_standard_list_options(opts, options, includes=[], excludes=[])
256
- build_standard_get_options(opts, options, [:list] + includes, excludes=[])
256
+ build_standard_get_options(opts, options, [:list] + includes, excludes)
257
257
  end
258
258
 
259
259
  def build_standard_add_options(opts, options, includes=[], excludes=[])
@@ -479,8 +479,10 @@ module Morpheus
479
479
  options[:offset] = offset
480
480
  end
481
481
 
482
- opts.on( '-s', '--search PHRASE', "Search Phrase" ) do |phrase|
483
- options[:phrase] = phrase
482
+ if excludes.include?("search") == false
483
+ opts.on( '-s', '--search PHRASE', "Search Phrase" ) do |phrase|
484
+ options[:phrase] = phrase
485
+ end
484
486
  end
485
487
 
486
488
  opts.on( '-S', '--sort ORDER', "Sort Order. DIRECTION may be included as \"ORDER [asc|desc]\"." ) do |v|
@@ -741,7 +743,15 @@ module Morpheus
741
743
  options[:include_fields] = val
742
744
  end
743
745
  end
744
- opts.add_hidden_option('-F,') if opts.is_a?(Morpheus::Cli::OptionParser)
746
+ opts.on('--raw-fields [x,y,z]', String, "Raw fields filters output like --fields except the properties [x,y,z] must be specified from the root of the response instead of relative to the the list or object context for this particular resource.") do |val|
747
+ if val.size == 1 && val[0].downcase == 'all'
748
+ options[:all_fields] = true
749
+ else
750
+ options[:include_fields] = val.split(',').collect {|r| r.strip}.compact
751
+ end
752
+ options[:raw_fields] = true
753
+ end
754
+ opts.add_hidden_option('--raw-fields') if opts.is_a?(Morpheus::Cli::OptionParser)
745
755
  opts.on(nil, '--all-fields', "Show all fields present in the data.") do
746
756
  options[:all_fields] = true
747
757
  end
@@ -753,6 +763,11 @@ module Morpheus
753
763
  opts.on('--select x,y,z', String, "Filter Output to just print the value(s) of specific fields.") do |val|
754
764
  options[:select_fields] = val.split(',').collect {|r| r.strip}
755
765
  end
766
+ opts.on('--raw-select x,y,z', String, "Raw select works like --select except the properties [x,y,z] must be specified from the root of the response instead of relative to the the list or object context for this particular resource.") do |val|
767
+ options[:select_fields] = val.split(',').collect {|r| r.strip}
768
+ options[:raw_fields] = true
769
+ end
770
+ opts.add_hidden_option('--raw-select') if opts.is_a?(Morpheus::Cli::OptionParser)
756
771
 
757
772
  when :delim
758
773
  opts.on('--delimiter [CHAR]', String, "Delimiter for output values. Default: ',', use with --select and --csv") do |val|
@@ -1397,29 +1412,33 @@ module Morpheus
1397
1412
  def render_response(json_response, options, object_key=nil, &block)
1398
1413
  output = nil
1399
1414
  if options[:select_fields]
1400
- row = object_key ? json_response[object_key] : json_response
1401
- row = [row].flatten()
1402
- if row.is_a?(Array)
1403
- output = [row].flatten.collect { |record|
1404
- options[:select_fields].collect { |field|
1405
- value = get_object_value(record, field)
1406
- value.is_a?(String) ? value : JSON.fast_generate(value)
1407
- }.join(options[:delim] || ",")
1408
- }.join(options[:newline] || "\n")
1409
- else
1410
- output = records_as_csv([row], options)
1415
+ # support foos get --raw-select foo.x,foo.y,foo.z
1416
+ # and foos list --raw-select foos.x,foos.y,foos.z
1417
+ row = (object_key && !options[:raw_fields]) ? json_response[object_key] : json_response
1418
+ records = [row].flatten()
1419
+ # look for an array in the first field only now...
1420
+ field_parts = options[:select_fields][0].to_s.split(".")
1421
+ field_context = field_parts[0]
1422
+ context_data = json_response[field_context]
1423
+ if field_parts.size > 1 && context_data.is_a?(Array)
1424
+ # inject all the root level properties to be selectable too..
1425
+ context_data = json_response.delete(field_context)
1426
+ # records = context_data
1427
+ records = context_data.collect {|it| it.is_a?(Hash) ? json_response.merge(it) : json_response }
1428
+ options[:select_fields] = options[:select_fields].collect {|it| it.sub(field_context+'.', '')}
1411
1429
  end
1430
+ output = records.collect { |record|
1431
+ options[:select_fields].collect { |field|
1432
+ value = get_object_value(record, field)
1433
+ value.is_a?(String) ? value : JSON.fast_generate(value)
1434
+ }.join(options[:delim] || ",")
1435
+ }.join(options[:newline] || "\n")
1412
1436
  elsif options[:json]
1413
1437
  output = as_json(json_response, options, object_key)
1414
1438
  elsif options[:yaml]
1415
1439
  output = as_yaml(json_response, options, object_key)
1416
1440
  elsif options[:csv]
1417
- row = object_key ? json_response[object_key] : json_response
1418
- if row.is_a?(Array)
1419
- output = records_as_csv(row, options)
1420
- else
1421
- output = records_as_csv([row], options)
1422
- end
1441
+ output = as_csv(json_response, nil, options, object_key)
1423
1442
  end
1424
1443
  if options[:outfile]
1425
1444
  full_outfile = File.expand_path(options[:outfile])
@@ -1569,7 +1588,7 @@ module Morpheus
1569
1588
  #Morpheus::Logging::DarkPrinter.puts "find_all(#{args.join(', ')})" if Morpheus::Logging.debug?
1570
1589
  type, *request_args = args
1571
1590
  type = type.to_s.singularize.underscore
1572
- list_key = respond_to?("#{type}_list_key", true) ? send("#{type}_list_key") : type.camelcase.pluralize
1591
+ list_key = respond_to?("#{type}_list_key", true) ? send("#{type}_list_key") : get_list_key(type)
1573
1592
  json_response = find_all_json(*args)
1574
1593
  if !json_response.key?(list_key)
1575
1594
  # maybe just use the first key like this:
@@ -1600,7 +1619,7 @@ module Morpheus
1600
1619
  #Morpheus::Logging::DarkPrinter.puts "find_record(#{args.join(', ')})" if Morpheus::Logging.debug?
1601
1620
  type, *request_args = args
1602
1621
  type = type.to_s.singularize.underscore
1603
- object_key = respond_to?("#{type}_object_key", true) ? send("#{type}_object_key") : type.camelcase.singularize
1622
+ object_key = respond_to?("#{type}_object_key", true) ? send("#{type}_object_key") : get_object_key(type)
1604
1623
  json_response = find_record_json(*args)
1605
1624
  if !json_response.key?(object_key)
1606
1625
  # maybe just use the first key like this:
@@ -1645,6 +1664,19 @@ module Morpheus
1645
1664
  return interface
1646
1665
  end
1647
1666
 
1667
+ def get_list_key(type)
1668
+ return get_object_key(type).pluralize
1669
+ end
1670
+
1671
+ def get_object_key(type)
1672
+ key = type.camelcase.singularize
1673
+ # add aliases here as needed
1674
+ if key == "cloud"
1675
+ key = "zone"
1676
+ end
1677
+ return key
1678
+ end
1679
+
1648
1680
  module ClassMethods
1649
1681
 
1650
1682
  def prog_name
@@ -996,7 +996,7 @@ EOT
996
996
  end
997
997
 
998
998
  def apply(args)
999
- default_refresh_interval = 15
999
+ default_refresh_interval = 10
1000
1000
  params, payload, options = {}, {}, {}
1001
1001
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1002
1002
  opts.banner = subcommand_usage("[app] [options]")
@@ -0,0 +1,44 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::BackupServices
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::RestCommand
6
+
7
+ set_command_description "View and manage backup services."
8
+ set_command_name :'backup-services'
9
+ register_subcommands :list, :get, :add, :update, :remove
10
+ register_interfaces :backup_services, :backup_service_types
11
+ set_rest_has_type true
12
+
13
+ protected
14
+
15
+ def load_option_types_for_backup_service(record_type, parent_record)
16
+ [
17
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
18
+ {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => 'on', 'displayOrder' => 2},
19
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Public', 'value' => 'public'}, {'name' => 'Private', 'value' => 'private'}], 'defaultValue' => 'public', 'displayOrder' => 1000}
20
+ ] + record_type['optionTypes']
21
+ end
22
+
23
+ def backup_service_list_column_definitions(options)
24
+ {
25
+ "ID" => 'id',
26
+ "Name" => 'name',
27
+ "Status" => 'status',
28
+ "Visibility" => 'visibility'
29
+ }
30
+ end
31
+
32
+ def backup_service_column_definitions(options)
33
+ {
34
+ "ID" => 'id',
35
+ "Name" => 'name',
36
+ "Enabled" => 'enabled',
37
+ "Api URL" => 'serviceUrl',
38
+ "Host" => 'host',
39
+ "Port" => 'port',
40
+ "Credential" => lambda {|it| it['credential']['type'] == 'local' ? 'local' : it['credential']['name']},
41
+ "Visibility" => 'visibility'
42
+ }
43
+ end
44
+ end
@@ -35,7 +35,10 @@ class Morpheus::Cli::CloudResourcePoolsCommand
35
35
  cloud_id = val
36
36
  end
37
37
  opts.add_hidden_option('-c') # prefer args[0] for [cloud]
38
- build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote])
38
+ opts.on( '-s', '--search PHRASE', "Search by Name and/or Display Name" ) do |phrase|
39
+ options[:phrase] = phrase
40
+ end
41
+ build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote], ['search'])
39
42
  opts.footer = "List resource pools for a cloud." + "\n" +
40
43
  "[cloud] is required. This is the name or id of the cloud."
41
44
  end
@@ -91,6 +94,7 @@ class Morpheus::Cli::CloudResourcePoolsCommand
91
94
  type: resource_pool['type'].to_s.capitalize,
92
95
  description: resource_pool['description'],
93
96
  active: format_boolean(resource_pool['active']),
97
+ inventory: format_boolean(resource_pool['inventory']),
94
98
  status: resource_pool['status'].to_s.upcase,
95
99
  visibility: resource_pool['visibility'].to_s.capitalize,
96
100
  default: format_boolean(resource_pool['defaultPool']),
@@ -99,7 +103,7 @@ class Morpheus::Cli::CloudResourcePoolsCommand
99
103
  }
100
104
  row
101
105
  }
102
- columns = [:id, :name, :description, :active, :default, :visibility, :tenants]
106
+ columns = [:id, :name, :description, :active,:inventory, :default, :visibility, :tenants]
103
107
  if options[:include_fields]
104
108
  columns = options[:include_fields]
105
109
  end
@@ -179,10 +183,12 @@ class Morpheus::Cli::CloudResourcePoolsCommand
179
183
  description_cols = {
180
184
  "ID" => 'id',
181
185
  "Name" => 'name',
186
+ "Display Name" => 'displayName',
182
187
  "Description" => 'description',
183
188
  #"Type" => lambda {|it| it['type'].to_s.capitalize },
184
189
  "Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
185
190
  "Active" => lambda {|it| format_boolean(it['active']) },
191
+ "Inventory" => lambda {|it| format_boolean(it['inventory']) },
186
192
  "Default" => lambda {|it| format_boolean(it['defaultPool']) },
187
193
  "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
188
194
  "Status" => lambda {|it| it['status'].to_s.capitalize },
@@ -329,6 +335,9 @@ class Morpheus::Cli::CloudResourcePoolsCommand
329
335
  opts.on('--active [on|off]', String, "Can be used to disable a resource pool") do |val|
330
336
  options['active'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
331
337
  end
338
+ opts.on('--inventory [on|off]', String, "Enable or disable inventory sync for resource pool during cloud refresh") do |val|
339
+ options['inventory'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
340
+ end
332
341
  opts.on('--default-pool [on|off]', String, "Set resource pool as the default") do |val|
333
342
  options['defaultPool'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
334
343
  end
@@ -447,6 +456,11 @@ class Morpheus::Cli::CloudResourcePoolsCommand
447
456
  else
448
457
  payload['resourcePool']['active'] = true
449
458
  end
459
+
460
+ #inventory
461
+ if options['inventory'] != nil
462
+ payload['resourcePool']['inventory'] = options['inventory']
463
+ end
450
464
 
451
465
  # Default
452
466
  if options['defaultPool'] != nil
@@ -574,12 +588,18 @@ class Morpheus::Cli::CloudResourcePoolsCommand
574
588
  opts.on('--active [on|off]', String, "Can be used to disable a resource pool") do |val|
575
589
  options['active'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
576
590
  end
591
+ opts.on('--inventory [on|off]', String, "Enable or disable inventory sync for resource pool during cloud refresh") do |val|
592
+ options['inventory'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
593
+ end
577
594
  opts.on('--default-pool [on|off]', String, "Set resource pool as the default") do |val|
578
595
  options['defaultPool'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
579
596
  end
580
597
  opts.on("--description [TEXT]", String, "Description") do |val|
581
598
  options['description'] = val.to_s
582
599
  end
600
+ opts.on("--display-name [TEXT]", String, "Display Name") do |val|
601
+ options['displayName'] = val.to_s
602
+ end
583
603
  opts.on( '--role ROLE', String, "Role Name or ID (applicable to select resource pools)" ) do |val|
584
604
  options['role'] = val
585
605
  end
@@ -599,6 +619,7 @@ class Morpheus::Cli::CloudResourcePoolsCommand
599
619
  end
600
620
 
601
621
  connect(options)
622
+ puts "options #{options}"
602
623
 
603
624
  begin
604
625
  # load cloud
@@ -672,6 +693,11 @@ class Morpheus::Cli::CloudResourcePoolsCommand
672
693
  if options['active'] != nil
673
694
  payload['resourcePool']['active'] = options['active']
674
695
  end
696
+
697
+ #inventory
698
+ if options['inventory'] != nil
699
+ payload['resourcePool']['inventory'] = options['inventory']
700
+ end
675
701
 
676
702
  # Default
677
703
  if options['defaultPool'] != nil
@@ -688,6 +714,11 @@ class Morpheus::Cli::CloudResourcePoolsCommand
688
714
  payload['resourcePool']['description'] = options['description']
689
715
  end
690
716
 
717
+ # Display Name
718
+ if options['displayName'] != nil
719
+ payload['resourcePool']['displayName'] = options['displayName']
720
+ end
721
+
691
722
  # Role
692
723
  if options['role'] != nil
693
724
  role_options = load_option_source_data('openstackRoles', {zoneId: cloud['id']})
@@ -80,8 +80,9 @@ class Morpheus::Cli::Clouds
80
80
  print_h1 title, subtitles
81
81
  if clouds.empty?
82
82
  print cyan,"No clouds found.",reset,"\n"
83
- else
84
- print_clouds_table(clouds, options)
83
+ else
84
+ columns = cloud_list_column_definitions(options).upcase_keys!
85
+ print as_pretty_table(clouds, columns, options)
85
86
  print_results_pagination(json_response)
86
87
  end
87
88
  print reset,"\n"
@@ -164,13 +165,14 @@ class Morpheus::Cli::Clouds
164
165
  else
165
166
  server_counts = json_response['serverCounts'] # legacy
166
167
  end
167
- cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
168
+ #cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
168
169
  print_h1 "Cloud Details"
169
170
  print cyan
170
171
  description_cols = {
171
172
  "ID" => 'id',
172
173
  "Name" => 'name',
173
- "Type" => lambda {|it| cloud_type ? cloud_type['name'] : '' },
174
+ # "Type" => lambda {|it| cloud_type ? cloud_type['name'] : '' },
175
+ "Type" => lambda {|it| it['zoneType'] ? it['zoneType']['name'] : '' },
174
176
  "Code" => 'code',
175
177
  "Location" => 'location',
176
178
  "Region Code" => 'regionCode',
@@ -215,6 +217,13 @@ class Morpheus::Cli::Clouds
215
217
  opts.on( '--certificate-provider CODE', String, "Certificate Provider. Default is 'internal'" ) do |val|
216
218
  params[:certificate_provider] = val
217
219
  end
220
+ opts.on('--costing-mode VALUE', String, "Costing Mode can be off,costing,full, Default is off." ) do |val|
221
+ options[:options]['costingMode'] = val
222
+ end
223
+ opts.on('--credential VALUE', String, "Credential ID or \"local\"" ) do |val|
224
+ options[:options]['credential'] = val
225
+ end
226
+
218
227
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
219
228
  end
220
229
  optparse.parse!(args)
@@ -251,7 +260,6 @@ class Morpheus::Cli::Clouds
251
260
  # todo: pass groups as an array instead
252
261
 
253
262
  # Cloud Name
254
-
255
263
  if args[0]
256
264
  cloud_payload[:name] = args[0]
257
265
  options[:options]['name'] = args[0] # to skip prompt
@@ -261,7 +269,6 @@ class Morpheus::Cli::Clouds
261
269
  end
262
270
 
263
271
  # Cloud Type
264
-
265
272
  cloud_type = nil
266
273
  if params[:zone_type]
267
274
  cloud_type = cloud_type_for_name(params[:zone_type])
@@ -329,6 +336,12 @@ class Morpheus::Cli::Clouds
329
336
  # opts.on( '-d', '--description DESCRIPTION', "Description (optional)" ) do |desc|
330
337
  # params[:description] = desc
331
338
  # end
339
+ opts.on('--costing-mode VALUE', String, "Costing Mode can be off, costing, or full. Default is off." ) do |val|
340
+ options[:options]['costingMode'] = val
341
+ end
342
+ opts.on('--credential VALUE', String, "Credential ID or \"local\"" ) do |val|
343
+ options[:options]['credential'] = val
344
+ end
332
345
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
333
346
  end
334
347
  optparse.parse!(args)
@@ -352,12 +365,26 @@ class Morpheus::Cli::Clouds
352
365
  cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
353
366
  cloud_payload = {}
354
367
  all_option_types = update_cloud_option_types(cloud_type)
355
- #params = Morpheus::Cli::OptionTypes.prompt(all_option_types, options[:options], @api_client, {zoneTypeId: cloud_type['id']})
368
+ #params = Morpheus::Cli::OptionTypes.no_prompt(all_option_types, options[:options], @api_client, {zoneId: cloud['id'], zoneTypeId: cloud_type['id']})
356
369
  params = options[:options] || {}
370
+
371
+ # Credentials (ideally only if value passed in and name can be parsed)
372
+ if options[:options]['credential']
373
+ credential_code = "credential"
374
+ credential_option_type = {'code' => credential_code, 'fieldName' => credential_code, 'fieldLabel' => 'Credentials', 'type' => 'select', 'optionSource' => 'credentials', 'description' => 'Enter an existing credential ID or choose "local"', 'defaultValue' => "local", 'required' => true}
375
+ # supported_credential_types = ['username-keypair', 'username-password', 'username-password-keypair'].compact.flatten.join(",").split(",").collect {|it| it.strip }
376
+ credential_params = {"new" => false, "zoneId" => cloud['id']}
377
+ credential_value = Morpheus::Cli::OptionTypes.select_prompt(credential_option_type, @api_client, credential_params, true, options[:options][credential_code])
378
+ if !credential_value.to_s.empty?
379
+ if credential_value == "local"
380
+ params[credential_code] = {"type" => credential_value}
381
+ elsif credential_value.to_s =~ /\A\d{1,}\Z/
382
+ params[credential_code] = {"id" => credential_value.to_i}
383
+ end
384
+ end
385
+ end
357
386
  if params.empty?
358
- puts_error optparse.banner
359
- puts_error format_available_options(all_option_types)
360
- exit 1
387
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
361
388
  end
362
389
  # some optionTypes have fieldContext='zone', so move those to the root level of the zone payload
363
390
  if params['zone'].is_a?(Hash)
@@ -430,7 +457,16 @@ class Morpheus::Cli::Clouds
430
457
  query_params = {}
431
458
  params = {}
432
459
  optparse = Morpheus::Cli::OptionParser.new do |opts|
433
- opts.banner = subcommand_usage("[name] [options]")
460
+ opts.banner = subcommand_usage("[cloud] [options]")
461
+ opts.on( '-m', '--mode [daily|costing]', "Refresh Mode. Use this to run the daily or costing jobs instead of the default hourly refresh." ) do |val|
462
+ query_params[:mode] = val
463
+ end
464
+ opts.on( '--rebuild [on|off]', "Rebuild invoices for period. Only applies to mode=costing." ) do |val|
465
+ query_params[:rebuild] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
466
+ end
467
+ opts.on( '--period PERIOD', "Period in the format YYYYMM to process invoices for. Default is the current period. Only applies to mode=costing." ) do |val|
468
+ query_params[:period] = val.to_s
469
+ end
434
470
  opts.on( '-f', '--force', "Force refresh. Useful if the cloud is disabled." ) do
435
471
  query_params[:force] = 'true'
436
472
  end
@@ -919,25 +955,17 @@ class Morpheus::Cli::Clouds
919
955
 
920
956
  private
921
957
 
922
- def print_clouds_table(clouds, opts={})
923
- table_color = opts[:color] || cyan
924
- rows = clouds.collect do |cloud|
925
- cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
926
- {
927
- id: cloud['id'],
928
- name: cloud['name'],
929
- type: cloud_type ? cloud_type['name'] : '',
930
- location: cloud['location'],
931
- "REGION CODE": cloud['regionCode'],
932
- groups: (cloud['groups'] || []).collect {|it| it.instance_of?(Hash) ? it['name'] : it.to_s }.join(', '),
933
- servers: cloud['serverCount'],
934
- status: format_cloud_status(cloud)
935
- }
936
- end
937
- columns = [
938
- :id, :name, :type, :location, "REGION CODE", :groups, :servers, :status
939
- ]
940
- print as_pretty_table(rows, columns, opts)
958
+ def cloud_list_column_definitions(options)
959
+ {
960
+ "ID" => 'id',
961
+ "Name" => 'name',
962
+ "Type" => lambda {|it| it['zoneType'] ? it['zoneType']['name'] : '' },
963
+ "Location" => 'location',
964
+ "Region Code" => lambda {|it| it['regionCode'] },
965
+ "Groups" => lambda {|it| (it['groups'] || []).collect {|g| g.instance_of?(Hash) ? g['name'] : g.to_s }.join(', ') },
966
+ "Servers" => lambda {|it| it['serverCount'] },
967
+ "Status" => lambda {|it| format_cloud_status(it) },
968
+ }
941
969
  end
942
970
 
943
971
  def add_cloud_option_types(cloud_type)
@@ -948,6 +976,8 @@ class Morpheus::Cli::Clouds
948
976
  {'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
949
977
  {'fieldName' => 'location', 'fieldLabel' => 'Location', 'type' => 'text', 'required' => false, 'displayOrder' => 3},
950
978
  {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'category' => 'permissions', 'defaultValue' => 'private', 'displayOrder' => 4},
979
+ {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'required' => false, 'defaultValue' => true, 'displayOrder' => 5},
980
+ {'fieldName' => 'autoRecoverPowerState', 'fieldLabel' => 'Automatically Power On VMs', 'type' => 'checkbox', 'required' => false, 'defaultValue' => false, 'displayOrder' => 6}
951
981
  ]
952
982
 
953
983
  # TODO: Account
@@ -955,9 +985,15 @@ class Morpheus::Cli::Clouds
955
985
  # Details (zoneType.optionTypes)
956
986
 
957
987
  if cloud_type && cloud_type['optionTypes']
988
+ if !cloud_type['optionTypes'].find {|opt| opt['type'] == 'credential'}
989
+ tmp_option_types << {'fieldName' => 'type', 'fieldLabel' => 'Credentials', 'type' => 'credential', 'optionSource' => 'credentials', 'required' => true, 'defaultValue' => 'local', 'config' => {'credentialTypes' => ['username-password']}, 'displayOrder' => 7}
990
+ cloud_type['optionTypes'].select {|opt| ['username', 'password'].include?(opt['fieldName'])}.each {|opt| opt['localCredential'] = true}
991
+ end
958
992
  # adjust displayOrder to put these at the end
959
993
  #tmp_option_types = tmp_option_types + cloud_type['optionTypes']
960
994
  cloud_type['optionTypes'].each do |opt|
995
+ # temp fix for typo
996
+ opt['optionSource'] = 'credentials' if opt['optionSource'] == 'credentials,'
961
997
  tmp_option_types << opt.merge({'displayOrder' => opt['displayOrder'].to_i + 100})
962
998
  end
963
999
  end
@@ -980,7 +1016,7 @@ class Morpheus::Cli::Clouds
980
1016
  end
981
1017
 
982
1018
  def cloud_types_for_dropdown
983
- get_available_cloud_types().select {|it| it['enabled'] }.collect {|it| {'name' => it['name'], 'value' => it['code']} }
1019
+ @clouds_interface.cloud_types({max:1000, shallow:true})['zoneTypes'].select {|it| it['enabled'] }.collect {|it| {'name' => it['name'], 'value' => it['code']} }
984
1020
  end
985
1021
 
986
1022
  def format_cloud_status(cloud, return_color=cyan)