morpheus-cli 5.5.0 → 5.5.1

Sign up to get free protection for your applications and to get access to all the features.
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'] } },