morpheus-cli 8.0.5 → 8.0.6
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/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/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: 5bd49f7ba0c5284049c949b7eb9abab30586335cf7994071467ac2e40e5052f8
|
4
|
+
data.tar.gz: 8042138fa3aa60542f6a042a035172f15aac37483fd3fea25fd11ed550e1ba29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24dd7b12d6f4a3884844af6ad53736cfecf3c28102aae2f2b8a710bac97433955aae2d7771f367ae8241f721a701c5a8d375a95fe065af5162280ebbe737d342
|
7
|
+
data.tar.gz: 1dca804ca56f509dcf13d9a35312de4429b0163e74f4140952fa06d15b8928f8ebe3132537b77ae1939307a2fcb69aa9d9ea52e2293753a042fdf5a6cf8da2f2
|
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
|
@@ -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
|
@@ -6,7 +6,7 @@ class Morpheus::Cli::NetworkFloatingIps
|
|
6
6
|
|
7
7
|
set_command_name :'network-floating-ips'
|
8
8
|
set_command_description "View and manage network floating IPs."
|
9
|
-
register_subcommands :list, :get, :release
|
9
|
+
register_subcommands :list, :get, :release, :allocate
|
10
10
|
|
11
11
|
# RestCommand settings
|
12
12
|
register_interfaces :network_floating_ips
|
@@ -49,6 +49,44 @@ EOT
|
|
49
49
|
return 0, nil
|
50
50
|
end
|
51
51
|
|
52
|
+
def allocate(args)
|
53
|
+
options = {}
|
54
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
55
|
+
opts.banner = subcommand_usage()
|
56
|
+
build_standard_add_options(opts, options)
|
57
|
+
opts.footer = <<-EOT
|
58
|
+
Allocate a new #{rest_label.downcase}.
|
59
|
+
Only the following cloud types support this command: OpenStack, Huawei and OpenTelekom
|
60
|
+
EOT
|
61
|
+
end
|
62
|
+
optparse.parse!(args)
|
63
|
+
verify_args!(args:args, optparse:optparse, count:0)
|
64
|
+
connect(options)
|
65
|
+
payload = {}
|
66
|
+
if options[:payload]
|
67
|
+
payload = options[:payload]
|
68
|
+
payload.deep_merge!(parse_passed_options(options))
|
69
|
+
else
|
70
|
+
payload.deep_merge!(parse_passed_options(options))
|
71
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'networkServerId', 'fieldLabel' => 'Network Service', 'type' => 'select', 'optionSource' => 'floatingIpNetworkServers', 'required' => true, 'description' => 'Choose a network service.'}], options[:options], @api_client, {})
|
72
|
+
payload[:networkServerId] = v_prompt['networkServerId']
|
73
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'floatingIpPoolId', 'fieldLabel' => 'Network Floating Ip Pool', 'type' => 'select', 'optionSource' => 'floatingIpPools', 'required' => true, 'description' => 'Choose a network service.'}], options[:options], @api_client, {networkServerId: v_prompt['networkServerId']})
|
74
|
+
payload[:floatingIpPoolId] = v_prompt['floatingIpPoolId']
|
75
|
+
end
|
76
|
+
|
77
|
+
rest_interface.setopts(options)
|
78
|
+
if options[:dry_run]
|
79
|
+
print_dry_run rest_interface.dry.allocate(payload)
|
80
|
+
return 0, nil
|
81
|
+
end
|
82
|
+
json_response = rest_interface.allocate(payload)
|
83
|
+
render_response(json_response, options) do
|
84
|
+
print_green_success "Allocating #{rest_label.downcase} with ipAddress: #{json_response['networkFloatingIp']['ipAddress'] }"
|
85
|
+
id = json_response['networkFloatingIp']['id']
|
86
|
+
_get(id.to_s, {}, options )
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
52
90
|
protected
|
53
91
|
|
54
92
|
def build_list_options(opts, options, params)
|
@@ -328,6 +328,8 @@ class Morpheus::Cli::NetworkRoutersCommand
|
|
328
328
|
cloud = {'id' => cloud_id}
|
329
329
|
end
|
330
330
|
router['zone'] = params['zone'] = {'id' => cloud['id']}
|
331
|
+
# add router type to be used for option prompts
|
332
|
+
params['router']['zone'] = {'id' => cloud['id']}
|
331
333
|
end
|
332
334
|
|
333
335
|
# prompt for enabled
|
@@ -337,7 +339,18 @@ class Morpheus::Cli::NetworkRoutersCommand
|
|
337
339
|
|
338
340
|
# prompt options
|
339
341
|
option_opts = options[:options].deep_merge!({'config' => options[:options].clone})
|
340
|
-
|
342
|
+
# option types are mixing context router and networkRouter, so we need to copy these to avoid prompt for router.name if passed in
|
343
|
+
if option_opts['name'] || option_opts['description']
|
344
|
+
option_opts['router'] ||= {}
|
345
|
+
option_opts['router']['name'] = option_opts['name'] if option_opts['name']
|
346
|
+
option_opts['router']['description'] = option_opts['description'] if option_opts['description']
|
347
|
+
end
|
348
|
+
option_result = Morpheus::Cli::OptionTypes.prompt(option_types, option_opts.merge({:context_map => {'networkRouter' => 'router'}}), @api_client, params)
|
349
|
+
# option types are mixing context router and networkRouter, so we need to clean up the payload
|
350
|
+
router_params = option_result.delete('router')
|
351
|
+
if router_params.is_a?(Hash)
|
352
|
+
option_result = router_params.deep_merge(option_result)
|
353
|
+
end
|
341
354
|
payload = {'networkRouter' => router.deep_merge(option_result)}
|
342
355
|
payload['networkRouter']['config'] = option_result['config'] if option_result['config']
|
343
356
|
end
|