morpheus-cli 5.5.0 → 5.5.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +4 -0
  4. data/lib/morpheus/api/clusters_interface.rb +12 -0
  5. data/lib/morpheus/api/network_pool_servers_interface.rb +7 -0
  6. data/lib/morpheus/api/scale_thresholds_interface.rb +9 -0
  7. data/lib/morpheus/cli/cli_command.rb +39 -20
  8. data/lib/morpheus/cli/commands/apps.rb +1 -1
  9. data/lib/morpheus/cli/commands/cloud_resource_pools_command.rb +33 -2
  10. data/lib/morpheus/cli/commands/clouds.rb +12 -6
  11. data/lib/morpheus/cli/commands/clusters.rb +66 -5
  12. data/lib/morpheus/cli/commands/hosts.rb +5 -1
  13. data/lib/morpheus/cli/commands/instances.rb +1 -1
  14. data/lib/morpheus/cli/commands/integrations_command.rb +1 -1
  15. data/lib/morpheus/cli/commands/invoices_command.rb +8 -1
  16. data/lib/morpheus/cli/commands/jobs_command.rb +45 -225
  17. data/lib/morpheus/cli/commands/library_container_types_command.rb +52 -3
  18. data/lib/morpheus/cli/commands/library_option_types_command.rb +56 -62
  19. data/lib/morpheus/cli/commands/load_balancers.rb +11 -19
  20. data/lib/morpheus/cli/commands/network_pool_servers_command.rb +5 -2
  21. data/lib/morpheus/cli/commands/roles.rb +475 -70
  22. data/lib/morpheus/cli/commands/scale_thresholds.rb +103 -0
  23. data/lib/morpheus/cli/commands/tasks.rb +19 -12
  24. data/lib/morpheus/cli/commands/user_sources_command.rb +107 -39
  25. data/lib/morpheus/cli/commands/users.rb +10 -10
  26. data/lib/morpheus/cli/commands/view.rb +1 -0
  27. data/lib/morpheus/cli/commands/workflows.rb +21 -14
  28. data/lib/morpheus/cli/error_handler.rb +13 -4
  29. data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
  30. data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
  31. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +3 -3
  32. data/lib/morpheus/cli/mixins/jobs_helper.rb +173 -0
  33. data/lib/morpheus/cli/mixins/print_helper.rb +120 -38
  34. data/lib/morpheus/cli/mixins/provisioning_helper.rb +1 -3
  35. data/lib/morpheus/cli/mixins/rest_command.rb +41 -14
  36. data/lib/morpheus/cli/option_types.rb +68 -37
  37. data/lib/morpheus/cli/version.rb +1 -1
  38. data/lib/morpheus/logging.rb +6 -8
  39. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca02ec5cffb310afe4458568f745332e8f81f1d03a525ad1a9d9d1a3ecd08313
4
- data.tar.gz: 323d4e3627c67fbd676bb34eb0b6f62b0eecff6180285af93599aba21f0a9781
3
+ metadata.gz: 0f9a8ef29c8d96c51593c8c762e94e34409426fb787ce3944396af9fc1e71279
4
+ data.tar.gz: 9a89c3ce4161499a9cf9df9ec30d48f0f8e9f4faf04746a19f966c1dc6cda7fd
5
5
  SHA512:
6
- metadata.gz: bc72cdba318abc74aef8dec7ab8602ad7ec7196101950dfc0b29b8fe8c4298c2de5b41265a386457c38fa0ac9e46082cb86d04d7cfbc75652a1824d5a036cec1
7
- data.tar.gz: f546fe9ed24fcc380d8aa1f2fc6d05a1cfb7186dcee48e66c340c51951b69e3b04408db5400ddcb23c9c596ccb14867571f1e21b6ceeb3e253c720d0525c21b0
6
+ metadata.gz: 2d4ef36713c80b4ce6c9037b5ac971f8abdcd65ad4ff732a7e1c9ab89e46ca7199fa4ce7f4bcb5cbe67e79236f9b90ee7b894d1d62ea5809c6da4c7b54e7ca7b
7
+ data.tar.gz: fc6fca36a81248ad7f44c8dd7aabb03fe60d7b9aaafd03311385a7b86a101a1cfb180dacf1a33d7306a5e5cf204d70ffb7e61ca02cef3c5180ff52df89d8fe65
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.5.1
2
2
 
3
- RUN gem install morpheus-cli -v 5.5.0
3
+ RUN gem install morpheus-cli -v 5.5.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
@@ -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
@@ -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
@@ -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])
@@ -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]")
@@ -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']})
@@ -260,7 +260,6 @@ class Morpheus::Cli::Clouds
260
260
  # todo: pass groups as an array instead
261
261
 
262
262
  # Cloud Name
263
-
264
263
  if args[0]
265
264
  cloud_payload[:name] = args[0]
266
265
  options[:options]['name'] = args[0] # to skip prompt
@@ -270,7 +269,6 @@ class Morpheus::Cli::Clouds
270
269
  end
271
270
 
272
271
  # Cloud Type
273
-
274
272
  cloud_type = nil
275
273
  if params[:zone_type]
276
274
  cloud_type = cloud_type_for_name(params[:zone_type])
@@ -459,7 +457,16 @@ class Morpheus::Cli::Clouds
459
457
  query_params = {}
460
458
  params = {}
461
459
  optparse = Morpheus::Cli::OptionParser.new do |opts|
462
- 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
463
470
  opts.on( '-f', '--force', "Force refresh. Useful if the cloud is disabled." ) do
464
471
  query_params[:force] = 'true'
465
472
  end
@@ -970,8 +977,7 @@ class Morpheus::Cli::Clouds
970
977
  {'fieldName' => 'location', 'fieldLabel' => 'Location', 'type' => 'text', 'required' => false, 'displayOrder' => 3},
971
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},
972
979
  {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'required' => false, 'defaultValue' => true, 'displayOrder' => 5},
973
- {'fieldName' => 'autoRecoverPowerState', 'fieldLabel' => 'Automatically Power On VMs', 'type' => 'checkbox', 'required' => false, 'defaultValue' => false, 'displayOrder' => 6},
974
- {'fieldName' => 'credential', 'fieldLabel' => 'Credentials', 'type' => 'select', 'optionSource' => 'credentials', 'description' => 'Credential ID or use "local" to specify username and password', 'displayOrder' => 9, 'defaultValue' => "local", 'required' => true, :for_help_only => true}, # hacky way to render this but not prompt for it
980
+ {'fieldName' => 'autoRecoverPowerState', 'fieldLabel' => 'Automatically Power On VMs', 'type' => 'checkbox', 'required' => false, 'defaultValue' => false, 'displayOrder' => 6}
975
981
  ]
976
982
 
977
983
  # TODO: Account
@@ -1004,7 +1010,7 @@ class Morpheus::Cli::Clouds
1004
1010
  end
1005
1011
 
1006
1012
  def cloud_types_for_dropdown
1007
- get_available_cloud_types().select {|it| it['enabled'] }.collect {|it| {'name' => it['name'], 'value' => it['code']} }
1013
+ @clouds_interface.cloud_types({max:1000, shallow:true})['zoneTypes'].select {|it| it['enabled'] }.collect {|it| {'name' => it['name'], 'value' => it['code']} }
1008
1014
  end
1009
1015
 
1010
1016
  def format_cloud_status(cloud, return_color=cyan)
@@ -10,6 +10,7 @@ class Morpheus::Cli::Clusters
10
10
  register_subcommands :list, :count, :get, :view, :add, :update, :remove, :logs, :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details}
11
11
  register_subcommands :list_workers, :add_worker, :remove_worker, :update_worker_count
12
12
  register_subcommands :list_masters
13
+ register_subcommands :upgrade_cluster
13
14
  register_subcommands :list_volumes, :remove_volume
14
15
  register_subcommands :list_namespaces, :get_namespace, :add_namespace, :update_namespace, :remove_namespace
15
16
  register_subcommands :list_containers, :remove_container, :restart_container
@@ -69,7 +70,6 @@ class Morpheus::Cli::Clusters
69
70
  return
70
71
  end
71
72
  json_response = @clusters_interface.list(params)
72
-
73
73
  render_result = render_with_format(json_response, options, 'clusters')
74
74
  return 0 if render_result
75
75
 
@@ -859,7 +859,11 @@ class Morpheus::Cli::Clusters
859
859
  print JSON.pretty_generate(json_response)
860
860
  print "\n"
861
861
  elsif !options[:quiet]
862
- print_green_success "Cluster #{cluster['name']} is being removed..."
862
+ msg = "Cluster #{cluster['name']} is being removed..."
863
+ if json_response['msg'] != nil && json_response['msg'] != ''
864
+ msg = json_response['msg']
865
+ end
866
+ print_green_success msg
863
867
  #list([])
864
868
  end
865
869
  rescue RestClient::Exception => e
@@ -1324,7 +1328,11 @@ class Morpheus::Cli::Clusters
1324
1328
  if options[:json]
1325
1329
  puts as_json(json_response)
1326
1330
  elsif json_response['success']
1327
- print_green_success "Added worker to cluster #{cluster['name']}"
1331
+ if json_response['msg'] == nil
1332
+ print_green_success "Added worker to cluster #{cluster['name']}"
1333
+ else
1334
+ print_green_success json_response['msg']
1335
+ end
1328
1336
  #get_args = [json_response["cluster"]["id"]] + (options[:remote] ? ["-r",options[:remote]] : [])
1329
1337
  #get(get_args)
1330
1338
  end
@@ -1377,7 +1385,11 @@ class Morpheus::Cli::Clusters
1377
1385
  end
1378
1386
  json_response = @clusters_interface.destroy_worker(cluster['id'], worker['id'], params)
1379
1387
  render_response(json_response, options) do
1380
- print_green_success "Worker #{worker['name']} is being removed from cluster #{cluster['name']}..."
1388
+ msg = "Worker #{worker['name']} is being removed from cluster #{cluster['name']}..."
1389
+ if json_response['msg']
1390
+ msg = json_response['msg']
1391
+ end
1392
+ print_green_success msg
1381
1393
  end
1382
1394
  return 0, nil
1383
1395
  end
@@ -1518,6 +1530,45 @@ class Morpheus::Cli::Clusters
1518
1530
  end
1519
1531
  end
1520
1532
 
1533
+ def upgrade_cluster(args)
1534
+ params = {}
1535
+ options = {}
1536
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
1537
+ opts.banner = subcommand_usage("[cluster]")
1538
+ build_standard_update_options(opts, options)
1539
+ opts.footer = "Updates kubernetes version (kubectl and kubeadm) of the specified cluster.\n" +
1540
+ "[cluster] is required. This is the name or id of an existing cluster.\n"
1541
+ end
1542
+ optparse.parse!(args)
1543
+ verify_args!(args:args, optparse:optparse, count:1)
1544
+ connect(options)
1545
+
1546
+ cluster = find_cluster_by_name_or_id(args[0])
1547
+ return 1 if cluster.nil?
1548
+
1549
+ version_options = get_valid_upgrade_versions(cluster['id'])
1550
+ version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'targetVersion', 'type' => 'select', 'fieldLabel' => 'To Version', 'selectOptions' => version_options, 'required' => true, 'description' => 'Select target version.' }],options[:options],api_client,{})
1551
+ target_version = version_options.detect{ |element| element['value'] == version_prompt['targetVersion'] }['name']
1552
+
1553
+ payload = {}
1554
+ if options[:payload]
1555
+ payload = options[:payload]
1556
+ payload.deep_merge!({'targetVersion' => target_version})
1557
+ else
1558
+ payload.deep_merge!({'targetVersion' => target_version})
1559
+ end
1560
+ @clusters_interface.setopts(options)
1561
+ if options[:dry_run]
1562
+ print_dry_run @clusters_interface.dry.do_cluster_upgrade(cluster['id'], payload)
1563
+ return
1564
+ end
1565
+ json_response = @clusters_interface.do_cluster_upgrade(cluster['id'], payload)
1566
+ render_response(json_response, options) do
1567
+ print_green_success "Cluster #{cluster['name']} is being upgraded to #{target_version}..."
1568
+ end
1569
+ return 0, nil
1570
+ end
1571
+
1521
1572
  def list_volumes(args)
1522
1573
  options = {}
1523
1574
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -3573,6 +3624,7 @@ class Morpheus::Cli::Clusters
3573
3624
  rows = clusters.collect do |cluster|
3574
3625
  {
3575
3626
  id: cluster['id'],
3627
+ display_name: cluster['displayName'],
3576
3628
  name: cluster['name'],
3577
3629
  type: (cluster['type']['name'] rescue ''),
3578
3630
  layout: (cluster['layout']['name'] rescue ''),
@@ -3582,7 +3634,7 @@ class Morpheus::Cli::Clusters
3582
3634
  }
3583
3635
  end
3584
3636
  columns = [
3585
- :id, :name, :type, :layout, :workers, :cloud, :status
3637
+ :id, :name, :display_name, :type, :layout, :workers, :cloud, :status
3586
3638
  ]
3587
3639
  print as_pretty_table(rows, columns, opts)
3588
3640
  end
@@ -4107,6 +4159,15 @@ class Morpheus::Cli::Clusters
4107
4159
  rtn
4108
4160
  end
4109
4161
 
4162
+ def get_valid_upgrade_versions(cluster_id)
4163
+ result = @clusters_interface.get_upgrade_versions(cluster_id, {})
4164
+ rtn = []
4165
+ if result['versions']
4166
+ rtn = result['versions'].map.with_index {|value, idx| {'name' => value,'value' => idx}}
4167
+ end
4168
+ rtn
4169
+ end
4170
+
4110
4171
  def update_wiki_page_option_types
4111
4172
  [
4112
4173
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'displayOrder' => 1, 'description' => 'The name of the wiki page for this instance. Default is the instance name.'},
@@ -1118,7 +1118,11 @@ class Morpheus::Cli::Hosts
1118
1118
  print JSON.pretty_generate(json_response)
1119
1119
  print "\n"
1120
1120
  elsif !options[:quiet]
1121
- print_green_success "Host #{server['name']} is being removed..."
1121
+ if json_response['deleteApprovalRequired'] == true
1122
+ print_green_success "Delete Request created for Host #{server['name']}"
1123
+ else
1124
+ print_green_success "Host #{server['name']} is being removed..."
1125
+ end
1122
1126
  #list([])
1123
1127
  end
1124
1128
  rescue RestClient::Exception => e
@@ -4607,7 +4607,7 @@ EOT
4607
4607
  end
4608
4608
 
4609
4609
  def apply(args)
4610
- default_refresh_interval = 15
4610
+ default_refresh_interval = 10
4611
4611
  params, payload, options = {}, {}, {}
4612
4612
  optparse = Morpheus::Cli::OptionParser.new do |opts|
4613
4613
  opts.banner = subcommand_usage("[instance] [options]")
@@ -275,7 +275,7 @@ EOT
275
275
  opt['fieldContext'] = nil
276
276
  end
277
277
  end
278
- config_prompt = Morpheus::Cli::OptionTypes.prompt(config_option_types, options[:options], @api_client, options[:params])
278
+ config_prompt = Morpheus::Cli::OptionTypes.prompt(config_option_types, options[:options], @api_client, options[:params], false, true)
279
279
  config_prompt.deep_compact!
280
280
  params.deep_merge!(config_prompt)
281
281
  end
@@ -627,6 +627,12 @@ Update an invoice.
627
627
  opts.on( '--date DATE', String, "Date to collect costing for. By default the cost data is collected for the end of the previous job interval (hour or day)." ) do |val|
628
628
  payload[:date] = val.to_s
629
629
  end
630
+ opts.on( '--period PERIOD', "Period in the format YYYYMM to process invoices for. Default is the current period. This is an alias for the --date option." ) do |val|
631
+ payload[:date] = val.to_s
632
+ end
633
+ opts.on( '--rebuild', "Rebuild invoices for period. Only applies to mode=costing." ) do |val|
634
+ query_params[:rebuild] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
635
+ end
630
636
  build_standard_update_options(opts, options, [:query, :auto_confirm])
631
637
  opts.footer = <<-EOT
632
638
  Refresh invoice costing data for the specified clouds.
@@ -674,6 +680,7 @@ EOT
674
680
  opts.on('-a', '--all', "Display all details, costs and prices." ) do
675
681
  options[:show_actual_costs] = true
676
682
  options[:show_costs] = true
683
+ options[:details] = true
677
684
  end
678
685
  # opts.on('--actuals', '--actuals', "Display all actual costs: Compute, Memory, Storage, Network, Extra" ) do
679
686
  # options[:show_actual_costs] = true
@@ -861,7 +868,7 @@ EOT
861
868
  {"COST" => lambda {|it| format_money(it['itemCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
862
869
  {"TAX" => lambda {|it| format_money(it['itemTax'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
863
870
  ] : []) + [
864
- {"ITEM ID" => lambda {|it| truncate_string_right(it['itemId'], 65) } },
871
+ {"ITEM ID" => lambda {|it| options[:details] ? it['itemId'] : truncate_string_right(it['itemId'], 65) } },
865
872
  {"ITEM NAME" => lambda {|it| it['itemName'] } },
866
873
  {"ITEM TYPE" => lambda {|it| it['itemType'] } },
867
874
  {"ITEM DESCRIPTION" => lambda {|it| it['itemDescription'] } },