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 +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +4 -0
- data/lib/morpheus/api/clusters_interface.rb +8 -0
- data/lib/morpheus/api/network_floating_ips_interface.rb +3 -0
- data/lib/morpheus/api/storage_datastores_interface.rb +44 -0
- data/lib/morpheus/cli/commands/clients_command.rb +14 -7
- data/lib/morpheus/cli/commands/cloud_datastores_command.rb +113 -1
- data/lib/morpheus/cli/commands/clouds.rb +0 -1
- data/lib/morpheus/cli/commands/clouds_types.rb +0 -1
- data/lib/morpheus/cli/commands/clusters.rb +35 -0
- data/lib/morpheus/cli/commands/containers_command.rb +21 -19
- data/lib/morpheus/cli/commands/hosts.rb +45 -22
- data/lib/morpheus/cli/commands/license.rb +7 -1
- data/lib/morpheus/cli/commands/network_domains_command.rb +1 -1
- data/lib/morpheus/cli/commands/network_floating_ips.rb +39 -1
- data/lib/morpheus/cli/commands/network_routers_command.rb +14 -1
- data/lib/morpheus/cli/commands/service_plans_command.rb +1 -0
- data/lib/morpheus/cli/commands/storage_datastores.rb +457 -0
- data/lib/morpheus/cli/commands/user_settings_command.rb +22 -6
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +1 -0
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +13 -2
- data/lib/morpheus/cli/option_types.rb +5 -5
- data/lib/morpheus/cli/version.rb +1 -1
- data/test/api/clients_interface_test.rb +23 -0
- data/test/cli/clients_test.rb +45 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28b8927c521af95d6c463be3cf8de08ad7f84017e18ab89a8143759d6e11e722
|
4
|
+
data.tar.gz: 0a1c6677040bcb8e50a5bde9603b5cda373d8ee16c41cf3a74ed96f1ff23a1be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0dca9e1aedcf8daedd76aba8e43b93d56733c05d247aa8fc31b0324d2b22c122e6164519e870a590ff703ad5413b8b96cf822dd537533acd2f2dce53a6fc6697
|
7
|
+
data.tar.gz: a8cdd96b0895216198267f1b639b97654fa0e0c2c38db49f55eb6776153305d59148febbca8bac8fe81bf193d3b465a90fbcd38bf8b52d508e01bdc3dfc44670
|
data/Dockerfile
CHANGED
@@ -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
|
-
|
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
|
-
|
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!({'
|
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
|
-
|
803
|
-
if !
|
804
|
-
raise_command_error "
|
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 =
|
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 "
|
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
|
-
|
865
|
-
if !
|
866
|
-
raise_command_error "
|
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
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
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
|
-
|
963
|
+
raise_command_error "Unable to determine network server type for container #{container['id']}"
|
961
964
|
end
|
962
|
-
return
|
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("[
|
1481
|
-
|
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
|
-
|
1485
|
-
puts optparse
|
1486
|
-
exit 1
|
1487
|
-
end
|
1494
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
1488
1495
|
connect(options)
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
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
|
-
|
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:
|
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
|