morpheus-cli 8.0.5 → 8.0.7

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36e5150354f68d0d1bf97da71cfc98e20bd78e68ab59a919d464b8d453a06ed3
4
- data.tar.gz: 7bf57c87149c0eb357886fccafe0c1b8ead22b289c23127d5b6a6b0947ae12e1
3
+ metadata.gz: 28b8927c521af95d6c463be3cf8de08ad7f84017e18ab89a8143759d6e11e722
4
+ data.tar.gz: 0a1c6677040bcb8e50a5bde9603b5cda373d8ee16c41cf3a74ed96f1ff23a1be
5
5
  SHA512:
6
- metadata.gz: f3d3be35646cafaf52af86eeef145350af72995ee762b5b958e2d49a10f263eb2803a4223b286f4358bf0d2904e2a1694a5282520ade5941184b7628bcc379d0
7
- data.tar.gz: b744429719628a8048759e8844f3687f1800e5e3bb45b5369c87efc76d577a0fa626821b8ff468f3f4166d12f6bef40ee4381a6e208cd9ea6c5f7836896edf3c
6
+ metadata.gz: 0dca9e1aedcf8daedd76aba8e43b93d56733c05d247aa8fc31b0324d2b22c122e6164519e870a590ff703ad5413b8b96cf822dd537533acd2f2dce53a6fc6697
7
+ data.tar.gz: a8cdd96b0895216198267f1b639b97654fa0e0c2c38db49f55eb6776153305d59148febbca8bac8fe81bf193d3b465a90fbcd38bf8b52d508e01bdc3dfc44670
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.7.5
2
2
 
3
- RUN gem install morpheus-cli -v 8.0.5
3
+ RUN gem install morpheus-cli -v 8.0.7
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
@@ -746,6 +746,10 @@ class Morpheus::APIClient
746
746
  Morpheus::StorageVolumeTypesInterface.new(common_interface_options).setopts(@options)
747
747
  end
748
748
 
749
+ def storage_datastores
750
+ Morpheus::StorageDatastoresInterface.new(common_interface_options).setopts(@options)
751
+ end
752
+
749
753
  def library_instance_types
750
754
  Morpheus::LibraryInstanceTypesInterface.new(common_interface_options).setopts(@options)
751
755
  end
@@ -345,4 +345,12 @@ class Morpheus::ClustersInterface < Morpheus::APIClient
345
345
  execute(method: :get, url: url, headers: headers)
346
346
  end
347
347
 
348
+ def load_balancer_port(params={})
349
+ url = "#{@base_url}/api/clusters/load-balancer-port"
350
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
351
+ headers[:params].merge!(params)
352
+
353
+ execute(method: :get, url: url, headers: headers)
354
+ end
355
+
348
356
  end
@@ -34,4 +34,7 @@ class Morpheus::NetworkFloatingIpsInterface < Morpheus::APIClient
34
34
  execute(method: :put, url: "#{base_path}/#{CGI::escape(id.to_s)}/release", params: params, payload: payload, headers: headers)
35
35
  end
36
36
 
37
+ def allocate(payload={}, params={}, headers={})
38
+ execute(method: :post, url: "#{base_path}/allocate", params: params, payload: payload, headers: headers)
39
+ end
37
40
  end
@@ -0,0 +1,44 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::StorageDatastoresInterface < Morpheus::APIClient
4
+
5
+ def base_path
6
+ "#{@base_url}/api/data-stores"
7
+ end
8
+
9
+ def get(id, params={})
10
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
11
+ url = "#{@base_url}/api/data-stores/#{id}"
12
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
13
+ opts = {method: :get, url: url, headers: headers}
14
+ execute(opts)
15
+ end
16
+
17
+ def list(params={})
18
+ url = base_path
19
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
20
+ opts = {method: :get, url: url, headers: headers}
21
+ execute(opts)
22
+ end
23
+
24
+ def load_type_options(datastore_type)
25
+ url = "/api/data-stores/#{datastore_type}/option-types"
26
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
27
+ opts = {method: :get, url: url, headers: headers}
28
+ execute(opts)
29
+ end
30
+
31
+ def create(options)
32
+ url = "#{@base_url}/api/data-stores"
33
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
34
+ payload = options
35
+ execute(method: :post, url: url, headers: headers, payload: payload.to_json)
36
+ end
37
+
38
+ def update(id, payload)
39
+ url = "#{@base_url}/api/data-stores/#{id}"
40
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
41
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
42
+ execute(opts)
43
+ end
44
+ end
@@ -102,9 +102,10 @@ class Morpheus::Cli::ClientsCommand
102
102
  "ID" => 'id',
103
103
  "Client ID" => 'clientId',
104
104
  "Access Token Validity Seconds" => 'accessTokenValiditySeconds',
105
- "Refresh Token Validity Seconds" => 'refreshTokenValiditySeconds'
105
+ "Refresh Token Validity Seconds" => 'refreshTokenValiditySeconds',
106
+ # "Scopes" => lambda {|client| client['scopes'].join(", ")},
107
+ "Redirect URI" => lambda {|client| client['redirectUris'].join(", ")}
106
108
  }
107
-
108
109
  print_description_list(client_columns, client)
109
110
  print reset,"\n"
110
111
 
@@ -122,7 +123,7 @@ class Morpheus::Cli::ClientsCommand
122
123
  optparse = Morpheus::Cli::OptionParser.new do |opts|
123
124
  opts.banner = subcommand_usage("[clientId] [options]")
124
125
  build_option_type_options(opts, options, add_client_option_types)
125
- build_common_options(opts, options, [:payload, :options, :json, :dry_run, :remote])
126
+ build_standard_add_options(opts, options)
126
127
  opts.footer = "Add New Oauth Client Record."
127
128
  end
128
129
  optparse.parse!(args)
@@ -150,6 +151,9 @@ class Morpheus::Cli::ClientsCommand
150
151
  payload.deep_merge!({'client' => passed_options}) unless passed_options.empty?
151
152
  # prompt for options
152
153
  params = Morpheus::Cli::OptionTypes.prompt(add_client_option_types, options[:options], @api_client, options[:params])
154
+ if params['redirectUris'] && params['redirectUris'].is_a?(String)
155
+ params['redirectUris'] = params['redirectUris'].split(',').collect {|it| it.strip}.reject {|it| it.empty?}
156
+ end
153
157
  payload.deep_merge!({'client' => params}) unless params.empty?
154
158
  end
155
159
 
@@ -179,7 +183,7 @@ class Morpheus::Cli::ClientsCommand
179
183
  optparse = Morpheus::Cli::OptionParser.new do |opts|
180
184
  opts.banner = subcommand_usage("[clientId] [options]")
181
185
  build_option_type_options(opts, options, client_option_types)
182
- build_common_options(opts, options, [:payload, :options, :json, :dry_run, :remote])
186
+ build_standard_update_options(opts, options)
183
187
  opts.footer = "Update Oauth Client Record."
184
188
  end
185
189
  optparse.parse!(args)
@@ -206,11 +210,13 @@ class Morpheus::Cli::ClientsCommand
206
210
  }
207
211
  }
208
212
  # allow arbitrary -O options
209
- payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
213
+ payload.deep_merge!({'client' => passed_options}) unless passed_options.empty?
210
214
  # prompt for options
211
215
  #params = Morpheus::Cli::OptionTypes.prompt(update_wiki_page_option_types, options[:options], @api_client, options[:params])
212
216
  params = passed_options
213
-
217
+ if params['redirectUris'] && params['redirectUris'].is_a?(String)
218
+ params['redirectUris'] = params['redirectUris'].split(',').collect {|it| it.strip}.reject {|it| it.empty?}
219
+ end
214
220
  if params.empty?
215
221
  raise_command_error "Specify at least one option to update.\n#{optparse}"
216
222
  end
@@ -332,7 +338,8 @@ class Morpheus::Cli::ClientsCommand
332
338
  {'fieldName' => 'clientId', 'fieldLabel' => 'Client Id', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
333
339
  {'fieldName' => 'clientSecret', 'fieldLabel' => 'Client Secret', 'type' => 'text', 'displayOrder' => 2},
334
340
  {'fieldName' => 'accessTokenValiditySeconds', 'fieldLabel' => 'Access Token Validity Length (Seconds)', 'type' => 'number', 'required' => true,'defaultValue' => 43200, 'displayOrder' => 3},
335
- {'fieldName' => 'refreshTokenValiditySeconds', 'fieldLabel' => 'Refresh Token Validity Length (Seconds)', 'type' => 'number', 'required' => true,'defaultValue' => 43200, 'displayOrder' => 4}
341
+ {'fieldName' => 'refreshTokenValiditySeconds', 'fieldLabel' => 'Refresh Token Validity Length (Seconds)', 'type' => 'number', 'required' => true,'defaultValue' => 43200, 'displayOrder' => 4},
342
+ {'fieldName' => 'redirectUris', 'fieldLabel' => 'Redirect URI', 'type' => 'text', 'displayOrder' => 5}
336
343
  ]
337
344
  end
338
345
  end
@@ -7,7 +7,7 @@ class Morpheus::Cli::CloudDatastoresCommand
7
7
  # set_command_name :'cloud-datastores'
8
8
  set_command_name :'datastores'
9
9
 
10
- register_subcommands :list, :get, :update
10
+ register_subcommands :list, :get, :update, :add
11
11
 
12
12
  def initialize()
13
13
  # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
@@ -18,6 +18,7 @@ class Morpheus::Cli::CloudDatastoresCommand
18
18
  @cloud_datastores_interface = @api_client.cloud_datastores
19
19
  @clouds_interface = @api_client.clouds
20
20
  @options_interface = @api_client.options
21
+ @storage_datastore_interface = @api_client.storage_datastores
21
22
  end
22
23
 
23
24
  def handle(args)
@@ -379,6 +380,114 @@ class Morpheus::Cli::CloudDatastoresCommand
379
380
  end
380
381
  end
381
382
 
383
+ def add(args)
384
+ options = {}
385
+ params = {}
386
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
387
+ opts.banner = subcommand_usage("[name] [options]")
388
+ build_common_options(opts, options, [:options, :payload, :json, :yaml, :dry_run, :quiet])
389
+ opts.on( '-n', '--name NAME', "Name" ) do |val|
390
+ options['name'] = val
391
+ end
392
+ opts.on( '-t', '--type DATASTORE_TYPE', "Datastore Type" ) do |val|
393
+ options['datastoreType'] = val
394
+ end
395
+ opts.on( '-c', '--cloud DATASTORE_CLOUD', "Datastore Cloud" ) do |val|
396
+ options['cloud'] = val
397
+ end
398
+ opts.footer = "Create a new Datastore.\n" +
399
+ "[name] is required. This is the name of the new datastore. It may also be passed as --name or inside your config."
400
+ end
401
+ optparse.parse!(args)
402
+ if args.count > 1
403
+ print_error Morpheus::Terminal.angry_prompt
404
+ puts_error "#{command_name} add expects 0-1 arguments and received #{args.count}: #{args}\n#{optparse}"
405
+ return 1
406
+ end
407
+ # allow name as first argument
408
+ if args[0] # && !options[:name]
409
+ options[:name] = args[0]
410
+ end
411
+ connect(options)
412
+ begin
413
+ options[:options] ||= {}
414
+ passed_options = (options[:options] || {}).reject {|k,v| k.is_a?(Symbol) }
415
+ payload = {}
416
+ if options[:payload]
417
+ # payload is from parsed json|yaml files or arguments.
418
+ payload = options[:payload]
419
+ # merge -O options
420
+ payload.deep_merge!(passed_options) unless passed_options.empty?
421
+ # support some options on top of --payload
422
+ [:name, :description, :environment].each do |k|
423
+ if options.key?(k)
424
+ payload[k.to_s] = options[k]
425
+ end
426
+ end
427
+ else
428
+ # prompt for payload
429
+ payload = {}
430
+ # merge -O options
431
+ payload.deep_merge!(passed_options) unless passed_options.empty?
432
+
433
+ # Name
434
+ if passed_options['name']
435
+ payload['name'] = passed_options['name']
436
+ else
437
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this archive bucket.'}], options, @api_client)
438
+ payload['name'] = v_prompt['name']
439
+ end
440
+
441
+ #Datastore Type
442
+ if passed_options['datastoreType']
443
+ payload['datastoreType'] = passed_options['datastoreType']
444
+ else
445
+ payload['datastoreType'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'datastoreType', 'fieldLabel' => 'Type', 'type' => 'select', 'required' => true, 'optionSource' => 'datastoreTypes'}], options[:options], @api_client)['datastoreType']
446
+ end
447
+
448
+ if passed_options['cloud']
449
+ zone = passed_options['cloud']
450
+ else
451
+ zone = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'zone', 'fieldLabel' => 'Cloud', 'type' => 'select', 'required' => true, 'optionSource' => 'cloudsForDatastores'}], options[:options], @api_client)['zone']
452
+ end
453
+
454
+ if zone
455
+ payload['refType'] = 'ComputeZone'
456
+ payload['refId'] = zone
457
+ end
458
+
459
+ option_types = load_option_types_for_datastore_type(payload['datastoreType'])
460
+
461
+ values = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client)
462
+ if values['domain']
463
+ payload.merge!(values['domain']) if values['domain'].is_a?(Hash)
464
+ end
465
+ if values['config']
466
+ payload['config'] = {}
467
+ payload['config'].merge!(values['config']) if values['config'].is_a?(Hash)
468
+ end
469
+
470
+ @storage_datastore_interface.setopts(options)
471
+ if options[:dry_run]
472
+ print_dry_run @storage_datastore_interface.dry.create({'datastore' => payload})
473
+ return
474
+ end
475
+ json_response = @storage_datastore_interface.create({'datastore' => payload})
476
+ datastore = json_response['datastore']
477
+ if options[:json]
478
+ print JSON.pretty_generate(json_response),"\n"
479
+ elsif !options[:quiet]
480
+ datastore = json_response['datastore']
481
+ print_green_success "Datastore #{datastore['name']} created"
482
+ #get([datastore['id']])
483
+ end
484
+ end
485
+ rescue RestClient::Exception => e
486
+ print_rest_exception(e, options)
487
+ exit 1
488
+ end
489
+ end
490
+
382
491
  private
383
492
 
384
493
 
@@ -428,4 +537,7 @@ class Morpheus::Cli::CloudDatastoresCommand
428
537
  end
429
538
  end
430
539
 
540
+ def load_option_types_for_datastore_type(datastore_type)
541
+ return @storage_datastore_interface.load_type_options(datastore_type)
542
+ end
431
543
  end
@@ -848,7 +848,6 @@ EOT
848
848
  "Discovery" => lambda {|it| format_boolean it['hasDiscovery'] },
849
849
  "Cloud Init" => lambda {|it| format_boolean it['hasCloudInit'] },
850
850
  "Folders" => lambda {|it| format_boolean it['hasFolders'] },
851
- "Floating Ips" => lambda {|it| format_boolean it['hasFloatingIps'] },
852
851
  # "Marketplace" => lambda {|it| format_boolean it['hasMarketplace'] },
853
852
  "Public Cloud" => lambda {|it| format_boolean(it['cloud'] == 'public') },
854
853
  }
@@ -123,7 +123,6 @@ EOT
123
123
  "Discovery" => lambda {|it| format_boolean it['hasDiscovery'] },
124
124
  "Cloud Init" => lambda {|it| format_boolean it['hasCloudInit'] },
125
125
  "Folders" => lambda {|it| format_boolean it['hasFolders'] },
126
- "Floating Ips" => lambda {|it| format_boolean it['hasFloatingIps'] },
127
126
  # "Marketplace" => lambda {|it| format_boolean it['hasMarketplace'] },
128
127
  "Public Cloud" => lambda {|it| format_boolean(it['cloud'] == 'public') },
129
128
  }
@@ -652,6 +652,10 @@ class Morpheus::Cli::Clusters
652
652
  metadata_option_type = option_type_list.find {|type| type['fieldName'] == 'metadata' }
653
653
  option_type_list = option_type_list.reject {|type| type['fieldName'] == 'metadata' }
654
654
 
655
+ # remove load balancer option_type, prompt manually
656
+ loadbalancer_option_type = option_type_list.find{|type| type['fieldName'] == 'loadBalancerId'}
657
+ option_type_list = option_type_list.reject { |type| type['fieldName'] == 'loadBalancerId' }
658
+
655
659
  server_count = layout['serverCount']
656
660
 
657
661
  # KLUDGE: google zone required for network selection
@@ -754,6 +758,37 @@ class Morpheus::Cli::Clusters
754
758
  end
755
759
  end
756
760
 
761
+ if loadbalancer_option_type
762
+ lb_payload = { computeTypeLayoutId: cluster_payload['layout']['id']}
763
+ load_balancer_id = prompt_cluster_load_balancer(cluster_payload, options)
764
+ if load_balancer_id != false
765
+ lb_payload['loadBalancerId'] = load_balancer_id
766
+ lb_payload['loadBalancerInstanceId'] = -1
767
+ lb_port_result = @clusters_interface.load_balancer_port(lb_payload)
768
+ lb_options = lb_port_result['optionTypes']
769
+ lb_option_results = Morpheus::Cli::OptionTypes.prompt(lb_options, options[:options], @api_client, api_params)
770
+
771
+ load_balancer_payload = {
772
+ port: lb_port_result.dig('loadBalancerPort', 'externalPort'),
773
+ enabled: lb_port_result.dig('loadBalancer', 'enabled'),
774
+ loadBalancerId: load_balancer_id,
775
+ backendPort: lb_port_result.dig('loadBalancerPort', 'internalPort'),
776
+ loadBalancer: { id: load_balancer_id },
777
+ vipPool: (lb_option_results.dig('domain', 'vipPool') == 'none') ? nil : lb_option_results.dig('domain', 'vipPool'),
778
+ vipAddress: lb_option_results.dig('domain', 'vipAddress'),
779
+ externalAddress: (lb_port_result.dig('loadBalancer', 'externalAddress') == true ) ? 'on': 'off',
780
+ vipShared: (lb_port_result.dig('loadBalancer', 'vipShared') == true ) ? 'on' : 'off',
781
+ vipProtocol: lb_port_result.dig('loadBalancerPort', 'loadBalanceProtocol'),
782
+ instanceId: lb_payload['loadBalancerInstanceId'],
783
+ name: lb_option_results['vipName']
784
+ }
785
+ if lb_option_results['domain']
786
+ load_balancer_payload.merge!(lb_option_results['domain']) { |key, old_val, new_val| old_val }
787
+ end
788
+ cluster_payload['lbInstances'] = [load_balancer_payload.compact!]
789
+ end
790
+ end
791
+
757
792
  cluster_payload['server'] = server_payload
758
793
  payload = {'cluster' => cluster_payload}
759
794
  end
@@ -4,6 +4,7 @@ class Morpheus::Cli::ContainersCommand
4
4
  include Morpheus::Cli::CliCommand
5
5
  include Morpheus::Cli::ProvisioningHelper
6
6
  include Morpheus::Cli::LogsHelper
7
+ include Morpheus::Cli::InfrastructureHelper
7
8
 
8
9
  set_command_name :containers
9
10
  set_command_description "View and manage containers (nodes)."
@@ -18,6 +19,7 @@ class Morpheus::Cli::ContainersCommand
18
19
  @logs_interface = @api_client.logs
19
20
  @execution_request_interface = @api_client.execution_request
20
21
  @clouds_interface = @api_client.clouds
22
+ @network_server_types_interface = @api_client.network_server_types
21
23
  end
22
24
 
23
25
  def handle(args)
@@ -799,14 +801,14 @@ EOT
799
801
  connect(options)
800
802
  container = find_container_by_id(args[0])
801
803
  return 1 if container.nil?
802
- cloud_type = load_container_cloud_type(container)
803
- if !cloud_type['hasFloatingIps']
804
- raise_command_error "Cloud Type #{cloud_type['name']} does support floating IPs."
804
+ network_server_type = load_container_network_server_type(container)
805
+ if !network_server_type['hasFloatingIps']
806
+ raise_command_error "Network Server Type #{network_server_type['name']} does support floating IPs."
805
807
  end
806
808
  payload = parse_payload(options)
807
809
  if payload.nil?
808
810
  payload = parse_passed_options(options)
809
- attach_floating_ip_option_types = cloud_type['floatingIpTypes']
811
+ attach_floating_ip_option_types = network_server_type['floatingIpTypes']
810
812
  if attach_floating_ip_option_types && !attach_floating_ip_option_types.empty?
811
813
  if options[:ip]
812
814
  floating_ip = options[:ip].to_s.sub(/\Aip\-/i, '')
@@ -829,7 +831,7 @@ EOT
829
831
  # payload.deep_merge!({'container' => v_prompt})
830
832
  payload.deep_merge!(v_prompt)
831
833
  else
832
- # raise_command_error "Cloud Type #{cloud_type['name']} does not defined any floating IP inputs."
834
+ # raise_command_error "Network Server Type #{network_server_type['name']} does not defined any floating IP inputs."
833
835
  end
834
836
  end
835
837
  confirm!("Are you sure you would like to attach this floating IP to container #{container['id']}?", options)
@@ -861,9 +863,9 @@ EOT
861
863
  connect(options)
862
864
  container = find_container_by_id(args[0])
863
865
  return 1 if container.nil?
864
- cloud_type = load_container_cloud_type(container)
865
- if !cloud_type['hasFloatingIps']
866
- raise_command_error "Cloud Type #{cloud_type['name']} does support floating IPs."
866
+ network_server_type = load_container_network_server_type(container)
867
+ if !network_server_type['hasFloatingIps']
868
+ raise_command_error "Network Type #{network_server_type['name']} does support floating IPs."
867
869
  end
868
870
  payload = parse_payload(options)
869
871
  if payload.nil?
@@ -948,18 +950,18 @@ EOT
948
950
  return provision_type
949
951
  end
950
952
 
951
- def load_container_cloud_type(container)
952
- cloud_type_code = container['cloud']['type'] rescue nil
953
- cloud_type = nil
954
- if cloud_type_code
955
- cloud_type = @clouds_interface.cloud_types({code:cloud_type_code})['zoneTypes'][0]
956
- if cloud_type.nil?
957
- raise_command_error "Cloud Type not found by code #{cloud_type_code}"
958
- end
953
+ def load_container_network_server_type(container)
954
+ cloud = find_cloud_by_id(container['cloud']['id'])
955
+ network_server_type_code = cloud['networkServer']['type'] rescue nil
956
+ network_server_type = nil
957
+ if network_server_type_code
958
+ network_server_type = @network_server_types_interface.list({code:network_server_type_code})['networkServerTypes'][0]
959
+ if network_server_type.nil?
960
+ raise_command_error "Network Server Type not found by code #{network_server_type_code}"
961
+ end
959
962
  else
960
- raise_command_error "Unable to determine cloud type for container #{container['id']}"
963
+ raise_command_error "Unable to determine network server type for container #{container['id']}"
961
964
  end
962
- return cloud_type
965
+ return network_server_type
963
966
  end
964
-
965
967
  end
@@ -1477,33 +1477,56 @@ class Morpheus::Cli::Hosts
1477
1477
  def upgrade_agent(args)
1478
1478
  options = {}
1479
1479
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1480
- opts.banner = subcommand_usage("[name]")
1481
- build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
1480
+ opts.banner = subcommand_usage("[host]")
1481
+ opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
1482
+ options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
1483
+ end
1484
+ opts.on(nil, '--no-refresh', "Do not refresh" ) do
1485
+ options[:no_refresh] = true
1486
+ end
1487
+ build_standard_update_options(opts, options, [:auto_confirm])
1488
+ opts.footer = <<-EOT
1489
+ Upgrade agent for a host.
1490
+ [host] is required. This is the name or id of a host.
1491
+ EOT
1482
1492
  end
1483
1493
  optparse.parse!(args)
1484
- if args.count < 1
1485
- puts optparse
1486
- exit 1
1487
- end
1494
+ verify_args!(args:args, optparse:optparse, count:1)
1488
1495
  connect(options)
1489
- begin
1490
- host = find_host_by_name_or_id(args[0])
1491
- @servers_interface.setopts(options)
1492
- if options[:dry_run]
1493
- print_dry_run @servers_interface.dry.upgrade(host['id'])
1494
- return
1495
- end
1496
- json_response = @servers_interface.upgrade(host['id'])
1497
- if options[:json]
1498
- print JSON.pretty_generate(json_response)
1499
- print "\n"
1496
+
1497
+ host = find_host_by_name_or_id(args[0])
1498
+ return 1 if host.nil?
1499
+
1500
+ payload = {}
1501
+ if options[:payload]
1502
+ payload = options[:payload]
1503
+ payload.deep_merge!({'server' => parse_passed_options(options)})
1504
+ else
1505
+ payload.deep_merge!({'server' => parse_passed_options(options)})
1506
+ end
1507
+
1508
+ @servers_interface.setopts(options)
1509
+ if options[:dry_run]
1510
+ print_dry_run @servers_interface.dry.upgrade(host['id'], payload)
1511
+ return
1512
+ end
1513
+ json_response = @servers_interface.upgrade(host['id'], payload)
1514
+ render_response(json_response, options) do
1515
+ #get([host['id']])
1516
+ if json_response['success']
1517
+ if json_response['msg'] == nil
1518
+ print_green_success "Upgrading agent on host #{host['name']}..."
1519
+ else
1520
+ print_green_success json_response['msg']
1521
+ end
1522
+ execution_id = json_response['executionId']
1523
+ if !options[:no_refresh] && execution_id
1524
+ wait_for_execution_request(json_response['executionId'], options.merge({waiting_status:['new', 'pending', 'executing']}))
1525
+ end
1500
1526
  else
1501
- puts "Host #{host['name']} upgrading..." unless options[:quiet]
1527
+ # never reached because unsuccessful requests raise an exception
1528
+ print_red_alert "API Request failed: #{json_response['msg']}"
1502
1529
  end
1503
- return
1504
- rescue RestClient::Exception => e
1505
- print_rest_exception(e, options)
1506
- exit 1
1507
1530
  end
1508
1531
  end
1509
1532
 
@@ -326,6 +326,7 @@ class Morpheus::Cli::License
326
326
  'Never'
327
327
  end
328
328
  },
329
+ "Version" => lambda {|it| it["licenseVersion"] },
329
330
  "Multi-Tenant" => lambda {|it| format_boolean it["multiTenant"] },
330
331
  "White Label" => lambda {|it| format_boolean it["whitelabel"] },
331
332
  "Stats Reporting" => lambda {|it| format_boolean it["reportStatus"] },
@@ -361,6 +362,7 @@ class Morpheus::Cli::License
361
362
  used_hosts = current_usage['hosts']
362
363
  used_mvm = current_usage['mvm']
363
364
  used_mvm_sockets = current_usage['mvmSockets']
365
+ used_sockets = current_usage['sockets'].to_f.round(1)
364
366
  used_iac = current_usage['iac']
365
367
  used_xaas = current_usage['xaas']
366
368
  used_executions = current_usage['executions']
@@ -373,6 +375,7 @@ class Morpheus::Cli::License
373
375
  max_hosts = license['maxHosts']
374
376
  max_mvm = license['maxMvm']
375
377
  max_mvm_sockets = license['maxMvmSockets']
378
+ max_sockets = license['maxSockets']
376
379
  max_iac = license['maxIac']
377
380
  max_xaas = license['maxXaas']
378
381
  max_executions = license['maxExecutions']
@@ -381,6 +384,7 @@ class Morpheus::Cli::License
381
384
  label_width = 20
382
385
  chart_opts = {max_bars: 20, unlimited_label: '0%', percent_sigdig: 0}
383
386
  out = ""
387
+ out << cyan + "Sockets".rjust(label_width, ' ') + ": " + generate_usage_bar(used_sockets, max_sockets, chart_opts) + cyan + used_sockets.to_s.rjust(8, ' ') + " / " + (max_sockets ? max_sockets.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
384
388
  out << cyan + "Managed Servers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_managed_servers, max_managed_servers, chart_opts) + cyan + used_managed_servers.to_s.rjust(8, ' ') + " / " + (max_managed_servers ? max_managed_servers.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
385
389
  out << cyan + "Discovered Servers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_discovered_servers, max_discovered_servers, chart_opts) + cyan + used_discovered_servers.to_s.rjust(8, ' ') + " / " + (max_discovered_servers ? max_discovered_servers.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
386
390
  out << cyan + "Hosts".rjust(label_width, ' ') + ": " + generate_usage_bar(used_hosts, max_hosts, chart_opts) + cyan + used_hosts.to_s.rjust(8, ' ') + " / " + (max_hosts ? max_hosts.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
@@ -439,6 +443,7 @@ class Morpheus::Cli::License
439
443
  'Never'
440
444
  end
441
445
  },
446
+ "Version" => lambda {|it| it["licenseVersion"] },
442
447
  "Multi-Tenant" => lambda {|it| format_boolean it["multiTenant"] },
443
448
  "White Label" => lambda {|it| format_boolean it["whitelabel"] },
444
449
  "Stats Reporting" => lambda {|it| format_boolean it["reportStatus"] },
@@ -451,11 +456,12 @@ class Morpheus::Cli::License
451
456
  })
452
457
  else
453
458
  license_columns.merge!({
459
+ "Sockets" => 'maxSockets',
460
+ "HPE VM Sockets" => 'maxMvmSockets',
454
461
  "Managed Servers" => 'maxManagedServers',
455
462
  "Discovered Servers" => 'maxDiscoveredServers',
456
463
  "Hosts" => 'maxHosts',
457
464
  "HPE VM Hosts" => 'maxMvm',
458
- "HPE VM Sockets" => 'maxMvmSockets',
459
465
  "Iac Deployments" => 'maxIac',
460
466
  "Xaas Instances" => 'maxXaas',
461
467
  "Executions" => 'maxExecutions',
@@ -840,7 +840,7 @@ class Morpheus::Cli::NetworkDomainsCommand
840
840
  print_red_alert "#{network_domains.size} network domains found by name #{name}"
841
841
  # print_networks_table(networks, {color: red})
842
842
  rows = network_domains.collect do |network_domain|
843
- {id: it['id'], name: it['name']}
843
+ {id: network_domain['id'], name: network_domain['name']}
844
844
  end
845
845
  puts as_pretty_table(rows, [:id, :name], {color:red})
846
846
  return nil