morpheus-cli 2.9.3.1 → 2.9.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/morpheus/api/instance_types_interface.rb +0 -22
- data/lib/morpheus/api/instances_interface.rb +8 -1
- data/lib/morpheus/api/servers_interface.rb +9 -0
- data/lib/morpheus/cli/app_templates.rb +25 -43
- data/lib/morpheus/cli/apps.rb +5 -3
- data/lib/morpheus/cli/hosts.rb +74 -8
- data/lib/morpheus/cli/instances.rb +62 -78
- data/lib/morpheus/cli/mixins/print_helper.rb +4 -0
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +134 -2
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7efa35bc257cb762e29ce35995cc2291e5d21e54
|
4
|
+
data.tar.gz: ca41c50847ed8ee3a5e50d7e75c773332b1b64da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff52228f42aca0f2caa7727e9a14f9e1004c3878d62fa5a121efff7f7b240141b9914c64ebdc060828079df1fb2fcbfcfbbbfc5fdb89568b2b4263f4302e372a
|
7
|
+
data.tar.gz: 37c3835e75478fc8b595e86486b237941798d66806aea5c8d607803cc5f49aad1715b364aa607f46a9e568ec9b8e9e1ac65d7bd70cfb8ab4407b4c78f664039b
|
@@ -26,26 +26,4 @@ class Morpheus::InstanceTypesInterface < Morpheus::APIClient
|
|
26
26
|
JSON.parse(response.to_s)
|
27
27
|
end
|
28
28
|
|
29
|
-
def service_plans(layout_id, name=nil)
|
30
|
-
url = "#{@base_url}/api/instance-types/service-plans/#{layout_id}"
|
31
|
-
headers = { params: {}, authorization: "Bearer #{@access_token}" }
|
32
|
-
|
33
|
-
if !name.nil?
|
34
|
-
headers[:params][:name] = name
|
35
|
-
end
|
36
|
-
response = Morpheus::RestClient.execute(method: :get, url: url,
|
37
|
-
timeout: 30, headers: headers, verify_ssl: false)
|
38
|
-
JSON.parse(response.to_s)
|
39
|
-
end
|
40
|
-
|
41
|
-
def service_plan_options(service_plan_id, params)
|
42
|
-
url = "#{@base_url}/api/instance-types/service-plans/#{service_plan_id}/options"
|
43
|
-
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
44
|
-
|
45
|
-
response = Morpheus::RestClient.execute(method: :get, url: url,
|
46
|
-
timeout: 30, headers: headers, verify_ssl: false)
|
47
|
-
JSON.parse(response.to_s)
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
29
|
end
|
@@ -155,10 +155,17 @@ class Morpheus::InstancesInterface < Morpheus::APIClient
|
|
155
155
|
url = "#{@base_url}/api/instances/#{id}/security-groups"
|
156
156
|
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
157
157
|
payload = options
|
158
|
-
puts "payload #{payload}"
|
159
158
|
response = Morpheus::RestClient.execute(method: :post, url: url,
|
160
159
|
timeout: 30, headers: headers,verify_ssl: false, payload: payload.to_json)
|
161
160
|
JSON.parse(response.to_s)
|
162
161
|
end
|
163
162
|
|
163
|
+
def service_plans(params)
|
164
|
+
url = "#{@base_url}/api/instances/service-plans"
|
165
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
166
|
+
response = Morpheus::RestClient.execute(method: :get, url: url,
|
167
|
+
timeout: 30, headers: headers, verify_ssl: false)
|
168
|
+
JSON.parse(response.to_s)
|
169
|
+
end
|
170
|
+
|
164
171
|
end
|
@@ -107,4 +107,13 @@ class Morpheus::ServersInterface < Morpheus::APIClient
|
|
107
107
|
timeout: 30, headers: headers, verify_ssl:false)
|
108
108
|
JSON.parse(response.to_s)
|
109
109
|
end
|
110
|
+
|
111
|
+
def service_plans(params)
|
112
|
+
url = "#{@base_url}/api/servers/service-plans"
|
113
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
114
|
+
response = Morpheus::RestClient.execute(method: :get, url: url,
|
115
|
+
timeout: 30, headers: headers, verify_ssl: false)
|
116
|
+
JSON.parse(response.to_s)
|
117
|
+
end
|
118
|
+
|
110
119
|
end
|
@@ -22,6 +22,7 @@ class Morpheus::Cli::AppTemplates
|
|
22
22
|
@api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
|
23
23
|
@app_templates_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).app_templates
|
24
24
|
@groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
|
25
|
+
@instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
|
25
26
|
@instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
|
26
27
|
@options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
|
27
28
|
end
|
@@ -352,40 +353,17 @@ class Morpheus::Cli::AppTemplates
|
|
352
353
|
exit 1
|
353
354
|
end
|
354
355
|
|
355
|
-
|
356
|
-
# groupId = nil
|
357
|
-
# if !options[:group].nil?
|
358
|
-
# group = find_group_by_name(options[:group])
|
359
|
-
# if !group.nil?
|
360
|
-
# groupId = group
|
361
|
-
# end
|
362
|
-
# else
|
363
|
-
# groupId = @active_groups[@appliance_name.to_sym]
|
364
|
-
# end
|
356
|
+
group_id = app_template['config']['siteId']
|
365
357
|
|
366
|
-
if
|
358
|
+
if group_id.nil?
|
367
359
|
#puts "Group not found or specified! \n #{optparse}"
|
368
360
|
print_red_alert("Group not found or specified for this template!")
|
369
361
|
puts "#{optparse}"
|
370
362
|
exit 1
|
371
363
|
end
|
372
364
|
|
373
|
-
cloud_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'type' => 'select', 'fieldLabel' => 'Cloud', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Select Cloud.'}],options[:options],@api_client,{groupId:
|
374
|
-
|
375
|
-
|
376
|
-
# if options[:cloud].nil?
|
377
|
-
# #puts "Cloud not specified! \n #{optparse}"
|
378
|
-
# print_red_alert("Cloud not specified!")
|
379
|
-
# puts "#{optparse}"
|
380
|
-
# exit 1
|
381
|
-
# end
|
382
|
-
# cloud = find_cloud_by_name(groupId,options[:cloud])
|
383
|
-
# if cloud.nil?
|
384
|
-
# #puts "Cloud not found! \n #{optparse}"
|
385
|
-
# #print_red_alert("Cloud not found!")
|
386
|
-
# puts "#{optparse}"
|
387
|
-
# exit 1
|
388
|
-
# end
|
365
|
+
cloud_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'type' => 'select', 'fieldLabel' => 'Cloud', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Select Cloud.'}],options[:options],@api_client,{groupId: group_id})
|
366
|
+
cloud_id = cloud_prompt['cloud']
|
389
367
|
|
390
368
|
|
391
369
|
instance_option_types = [{'fieldName' => 'name', 'fieldLabel' => 'Instance Name', 'type' => 'text'}]
|
@@ -395,11 +373,11 @@ class Morpheus::Cli::AppTemplates
|
|
395
373
|
# copied from instances command, this payload isn't used
|
396
374
|
payload = {
|
397
375
|
:servicePlan => nil,
|
398
|
-
zoneId
|
376
|
+
:zoneId => cloud_id,
|
399
377
|
:instance => {
|
400
378
|
:name => instance_name,
|
401
379
|
:site => {
|
402
|
-
:id =>
|
380
|
+
:id => group_id
|
403
381
|
},
|
404
382
|
:instanceType => {
|
405
383
|
:code => instance_type_code
|
@@ -407,22 +385,26 @@ class Morpheus::Cli::AppTemplates
|
|
407
385
|
}
|
408
386
|
}
|
409
387
|
|
410
|
-
version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'optionSource' => 'instanceVersions', 'required' => true, 'skipSingleOption' => true, 'description' => 'Select which version of the instance type to be provisioned.'}],options[:options],@api_client,{groupId:
|
411
|
-
layout_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'optionSource' => 'layoutsForCloud', 'required' => true, 'description' => 'Select which configuration of the instance type to be provisioned.'}],options[:options],@api_client,{groupId:
|
388
|
+
version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'optionSource' => 'instanceVersions', 'required' => true, 'skipSingleOption' => true, 'description' => 'Select which version of the instance type to be provisioned.'}],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
|
389
|
+
layout_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'optionSource' => 'layoutsForCloud', 'required' => true, 'description' => 'Select which configuration of the instance type to be provisioned.'}],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], version: version_prompt['version']})
|
412
390
|
layout_id = layout_prompt['layout']
|
413
|
-
plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'optionSource' => 'instanceServicePlans', 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options],@api_client,{groupId: groupId, zoneId: cloud, instanceTypeId: instance_type['id'], layoutId: layout_id, version: version_prompt['version']})
|
414
|
-
payload[:servicePlan] = plan_prompt['servicePlan']
|
415
|
-
|
416
391
|
layout = instance_type['instanceTypeLayouts'].find{ |lt| lt['id'].to_i == layout_id.to_i}
|
417
|
-
instance_type['instanceTypeLayouts'].sort! { |x,y| y['sortOrder'] <=> x['sortOrder'] }
|
418
|
-
|
419
392
|
payload[:instance][:layout] = {id: layout['id']}
|
420
393
|
|
394
|
+
# prompt for service plan
|
395
|
+
service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, layoutId: layout_id})
|
396
|
+
service_plans = service_plans_json["plans"]
|
397
|
+
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
|
398
|
+
plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
|
399
|
+
service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
|
400
|
+
payload[:servicePlan] = service_plan["id"]
|
401
|
+
|
402
|
+
|
421
403
|
type_payload = {}
|
422
404
|
if !layout['optionTypes'].nil? && !layout['optionTypes'].empty?
|
423
|
-
type_payload = Morpheus::Cli::OptionTypes.prompt(layout['optionTypes'],options[:options],@api_client,{groupId:
|
405
|
+
type_payload = Morpheus::Cli::OptionTypes.prompt(layout['optionTypes'],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_prompt['version']})
|
424
406
|
elsif !instance_type['optionTypes'].nil? && !instance_type['optionTypes'].empty?
|
425
|
-
type_payload = Morpheus::Cli::OptionTypes.prompt(instance_type['optionTypes'],options[:options],@api_client,{groupId:
|
407
|
+
type_payload = Morpheus::Cli::OptionTypes.prompt(instance_type['optionTypes'],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_prompt['version']})
|
426
408
|
end
|
427
409
|
if !type_payload['config'].nil?
|
428
410
|
payload.merge!(type_payload['config'])
|
@@ -431,7 +413,7 @@ class Morpheus::Cli::AppTemplates
|
|
431
413
|
provision_payload = {}
|
432
414
|
if !layout['provisionType'].nil? && !layout['provisionType']['optionTypes'].nil? && !layout['provisionType']['optionTypes'].empty?
|
433
415
|
puts "Checking for option Types"
|
434
|
-
provision_payload = Morpheus::Cli::OptionTypes.prompt(layout['provisionType']['optionTypes'],options[:options],@api_client,{groupId:
|
416
|
+
provision_payload = Morpheus::Cli::OptionTypes.prompt(layout['provisionType']['optionTypes'],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_prompt['version']})
|
435
417
|
end
|
436
418
|
|
437
419
|
if !provision_payload.nil? && !provision_payload['config'].nil?
|
@@ -491,8 +473,8 @@ class Morpheus::Cli::AppTemplates
|
|
491
473
|
# "volumes.storageType": nil,
|
492
474
|
|
493
475
|
"version"=>version_prompt['version'],
|
494
|
-
"siteId"=>
|
495
|
-
"zoneId"=>
|
476
|
+
"siteId"=>group_id.to_s,
|
477
|
+
"zoneId"=>cloud_id.to_s
|
496
478
|
},
|
497
479
|
"grabbable"=>true, "group"=>"nodes", "locked"=>false,
|
498
480
|
#"position"=>{"x"=>-79.83254449505226, "y"=>458.33806818181824},
|
@@ -845,8 +827,8 @@ private
|
|
845
827
|
return group_results['groups'][0]
|
846
828
|
end
|
847
829
|
|
848
|
-
def find_cloud_by_name(
|
849
|
-
option_results = @options_interface.options_for_source('clouds',{groupId:
|
830
|
+
def find_cloud_by_name(group_id, name)
|
831
|
+
option_results = @options_interface.options_for_source('clouds',{groupId: group_id})
|
850
832
|
match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
|
851
833
|
if match.nil?
|
852
834
|
print_red_alert "Cloud not found by name #{name}"
|
data/lib/morpheus/cli/apps.rb
CHANGED
@@ -27,12 +27,13 @@ class Morpheus::Cli::Apps
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def handle(args)
|
30
|
-
usage = "Usage: morpheus apps [list,
|
30
|
+
usage = "Usage: morpheus apps [list,remove,stop,start,restart,resize,upgrade,clone,envs,setenv,delenv,firewall_disable,firewall_enable,security_groups,apply_security_groups] [name]"
|
31
31
|
case args[0]
|
32
32
|
when 'list'
|
33
33
|
list(args[1..-1])
|
34
|
-
|
35
|
-
|
34
|
+
# JD: this has never worked, it is time to implement it!
|
35
|
+
# when 'add'
|
36
|
+
# add(args[1..-1])
|
36
37
|
when 'remove'
|
37
38
|
remove(args[1..-1])
|
38
39
|
when 'stop'
|
@@ -101,6 +102,7 @@ class Morpheus::Cli::Apps
|
|
101
102
|
}
|
102
103
|
}
|
103
104
|
|
105
|
+
# JD: this is old and busted.. appTypeLayouts is not returned..
|
104
106
|
instance_type['appTypeLayouts'].sort! { |x,y| y['sortOrder'] <=> x['sortOrder'] }
|
105
107
|
puts "Configurations: "
|
106
108
|
instance_type['appTypeLayouts'].each_with_index do |layout, index|
|
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -3,11 +3,13 @@ require 'io/console'
|
|
3
3
|
require 'rest_client'
|
4
4
|
require 'optparse'
|
5
5
|
require 'morpheus/cli/cli_command'
|
6
|
+
require 'morpheus/cli/mixins/provisioning_helper'
|
6
7
|
require 'morpheus/cli/option_types'
|
7
8
|
require 'json'
|
8
9
|
|
9
10
|
class Morpheus::Cli::Hosts
|
10
11
|
include Morpheus::Cli::CliCommand
|
12
|
+
include Morpheus::Cli::ProvisioningHelper
|
11
13
|
|
12
14
|
def initialize()
|
13
15
|
@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
@@ -165,7 +167,7 @@ class Morpheus::Cli::Hosts
|
|
165
167
|
opts.on( '-t', '--type TYPE', "Server Type" ) do |server_type|
|
166
168
|
options[:server_type] = server_type
|
167
169
|
end
|
168
|
-
build_common_options(opts, options, [:options, :json, :remote])
|
170
|
+
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
169
171
|
end
|
170
172
|
if args.count < 2
|
171
173
|
puts "\n#{optparse}\n\n"
|
@@ -180,7 +182,7 @@ class Morpheus::Cli::Hosts
|
|
180
182
|
zone=nil
|
181
183
|
if !options[:zone].nil?
|
182
184
|
zone = find_zone_by_name(nil, options[:zone])
|
183
|
-
options[:params][:zoneId] = zone['id']
|
185
|
+
options[:params][:zoneId] = zone['id'] if zone
|
184
186
|
end
|
185
187
|
|
186
188
|
if zone.nil?
|
@@ -190,7 +192,7 @@ class Morpheus::Cli::Hosts
|
|
190
192
|
zone_type = cloud_type_for_id(zone['zoneTypeId'])
|
191
193
|
end
|
192
194
|
|
193
|
-
cloud_server_types = zone_type['serverTypes'].select{|b| b['creatable'] == true }
|
195
|
+
cloud_server_types = zone_type['serverTypes'].select{|b| b['creatable'] == true }.sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
|
194
196
|
if options[:server_type]
|
195
197
|
server_type_code = options[:server_type]
|
196
198
|
else
|
@@ -206,11 +208,75 @@ class Morpheus::Cli::Hosts
|
|
206
208
|
exit 1
|
207
209
|
end
|
208
210
|
|
209
|
-
|
211
|
+
payload = {}
|
212
|
+
|
213
|
+
# prompt for service plan
|
214
|
+
service_plans_json = @servers_interface.service_plans({zoneId: zone['id'], serverTypeId: server_type["id"]})
|
215
|
+
service_plans = service_plans_json["plans"]
|
216
|
+
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
|
217
|
+
plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this server'}],options[:options])
|
218
|
+
service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
|
219
|
+
# payload[:servicePlan] = plan_prompt['servicePlan']
|
220
|
+
|
221
|
+
# prompt for volumes
|
222
|
+
volumes = prompt_volumes(service_plan, options, @api_client, {})
|
223
|
+
if !volumes.empty?
|
224
|
+
payload[:volumes] = volumes
|
225
|
+
end
|
226
|
+
|
227
|
+
# prompt for network interfaces (if supported)
|
228
|
+
if server_type["provisionType"] && server_type["provisionType"]["id"] && server_type["provisionType"]["hasNetworks"]
|
229
|
+
begin
|
230
|
+
network_interfaces = prompt_network_interfaces(zone['id'], server_type["provisionType"]["id"], options, @api_client)
|
231
|
+
if !network_interfaces.empty?
|
232
|
+
payload[:networkInterfaces] = network_interfaces
|
233
|
+
end
|
234
|
+
rescue RestClient::Exception => e
|
235
|
+
print_yellow_warning "Unable to load network options. Proceeding..."
|
236
|
+
print_rest_exception(e, options) if Morpheus::Logging.print_stacktrace?
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
server_type_option_types = server_type['optionTypes']
|
241
|
+
# remove volume options if volumes were configured
|
242
|
+
if !payload[:volumes].empty?
|
243
|
+
server_type_option_types = reject_volume_option_types(server_type_option_types)
|
244
|
+
end
|
245
|
+
# remove networkId option if networks were configured above
|
246
|
+
if !payload[:networkInterfaces].empty?
|
247
|
+
server_type_option_types = reject_networking_option_types(server_type_option_types)
|
248
|
+
end
|
249
|
+
# remove cpu and memory option types, which now come from the plan
|
250
|
+
server_type_option_types = reject_service_plan_option_types(server_type_option_types)
|
251
|
+
|
252
|
+
params = Morpheus::Cli::OptionTypes.prompt(server_type_option_types,options[:options],@api_client, options[:params])
|
210
253
|
begin
|
211
254
|
params['server'] = params['server'] || {}
|
212
|
-
|
213
|
-
|
255
|
+
payload = payload.merge({
|
256
|
+
server: {
|
257
|
+
name: name,
|
258
|
+
zone: {id: zone['id']},
|
259
|
+
computeServerType: {id: server_type['id']},
|
260
|
+
plan: {id: service_plan["id"]}
|
261
|
+
}.merge(params['server'])
|
262
|
+
})
|
263
|
+
payload[:network] = params['network'] if params['network']
|
264
|
+
payload[:config] = params['config'] if params['config']
|
265
|
+
if options[:dry_run]
|
266
|
+
print "\n" ,cyan, bold, "DRY RUN\n","==================", "\n\n", reset
|
267
|
+
print cyan
|
268
|
+
print "Request: ", "\n"
|
269
|
+
print reset
|
270
|
+
print "POST #{@appliance_url}/api/servers", "\n\n"
|
271
|
+
print cyan
|
272
|
+
print "JSON: ", "\n"
|
273
|
+
print reset
|
274
|
+
print JSON.pretty_generate(payload)
|
275
|
+
print "\n"
|
276
|
+
print reset
|
277
|
+
return
|
278
|
+
end
|
279
|
+
json_response = @servers_interface.create(payload)
|
214
280
|
if options[:json]
|
215
281
|
print JSON.pretty_generate(json_response)
|
216
282
|
print "\n"
|
@@ -526,8 +592,8 @@ private
|
|
526
592
|
return group_results['groups'][0]
|
527
593
|
end
|
528
594
|
|
529
|
-
def find_zone_by_name(
|
530
|
-
zone_results = @clouds_interface.get({groupId:
|
595
|
+
def find_zone_by_name(group_id, name)
|
596
|
+
zone_results = @clouds_interface.get({groupId: group_id, name: name})
|
531
597
|
if zone_results['zones'].empty?
|
532
598
|
puts "Zone not found by name #{name}"
|
533
599
|
return nil
|
@@ -124,17 +124,14 @@ class Morpheus::Cli::Instances
|
|
124
124
|
if instance_type.nil?
|
125
125
|
exit 1
|
126
126
|
end
|
127
|
-
|
127
|
+
group_id = nil
|
128
128
|
if !options[:group].nil?
|
129
|
-
|
130
|
-
if !group.nil?
|
131
|
-
groupId = group
|
132
|
-
end
|
129
|
+
group_id = find_group_by_name(options[:group])
|
133
130
|
else
|
134
|
-
|
131
|
+
group_id = @active_groups[@appliance_name.to_sym]
|
135
132
|
end
|
136
133
|
|
137
|
-
if
|
134
|
+
if group_id.nil?
|
138
135
|
puts "Group not found or specified! \n #{optparse}"
|
139
136
|
exit 1
|
140
137
|
end
|
@@ -143,19 +140,19 @@ class Morpheus::Cli::Instances
|
|
143
140
|
puts "Cloud not specified! \n #{optparse}"
|
144
141
|
exit 1
|
145
142
|
end
|
146
|
-
|
147
|
-
if
|
143
|
+
cloud_id = find_cloud_by_name(group_id, options[:cloud])
|
144
|
+
if cloud_id.nil?
|
148
145
|
puts "Cloud not found! \n #{optparse}"
|
149
146
|
exit 1
|
150
147
|
end
|
151
148
|
|
152
149
|
payload = {
|
153
150
|
:servicePlan => nil,
|
154
|
-
zoneId
|
151
|
+
:zoneId => cloud_id,
|
155
152
|
:instance => {
|
156
153
|
:name => instance_name,
|
157
154
|
:site => {
|
158
|
-
:id =>
|
155
|
+
:id => group_id
|
159
156
|
},
|
160
157
|
:instanceType => {
|
161
158
|
:code => instance_type_code
|
@@ -163,48 +160,45 @@ class Morpheus::Cli::Instances
|
|
163
160
|
}
|
164
161
|
}
|
165
162
|
|
166
|
-
version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'optionSource' => 'instanceVersions', 'required' => true, 'skipSingleOption' => true, 'description' => 'Select which version of the instance type to be provisioned.'}],options[:options],@api_client,{groupId:
|
167
|
-
layout_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'optionSource' => 'layoutsForCloud', 'required' => true, 'description' => 'Select which configuration of the instance type to be provisioned.'}],options[:options],@api_client,{groupId:
|
163
|
+
version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'optionSource' => 'instanceVersions', 'required' => true, 'skipSingleOption' => true, 'description' => 'Select which version of the instance type to be provisioned.'}],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
|
164
|
+
layout_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'optionSource' => 'layoutsForCloud', 'required' => true, 'description' => 'Select which configuration of the instance type to be provisioned.'}],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], version: version_prompt['version']})
|
168
165
|
layout_id = layout_prompt['layout']
|
169
|
-
|
170
|
-
payload[:servicePlan] = plan_prompt['servicePlan']
|
171
|
-
|
172
|
-
layout = instance_type['instanceTypeLayouts'].find{ |lt| lt['id'].to_i == layout_id.to_i}
|
173
|
-
instance_type['instanceTypeLayouts'].sort! { |x,y| y['sortOrder'] <=> x['sortOrder'] }
|
174
|
-
|
166
|
+
layout = instance_type['instanceTypeLayouts'].find{ |lt| lt['id'] == layout_id.to_i}
|
175
167
|
payload[:instance][:layout] = {id: layout['id']}
|
176
168
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
plan_options = service_plan_options_json['plan']
|
185
|
-
volumes = prompt_instance_volumes(plan_options, options, @api_client, {})
|
169
|
+
# prompt for service plan
|
170
|
+
service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, layoutId: layout_id})
|
171
|
+
service_plans = service_plans_json["plans"]
|
172
|
+
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
|
173
|
+
plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
|
174
|
+
service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
|
175
|
+
payload[:servicePlan] = service_plan["id"]
|
186
176
|
|
187
|
-
|
188
|
-
|
177
|
+
# prompt for volumes
|
178
|
+
volumes = prompt_volumes(service_plan, options, @api_client, {})
|
179
|
+
if !volumes.empty?
|
180
|
+
payload[:volumes] = volumes
|
181
|
+
end
|
189
182
|
|
190
|
-
|
191
|
-
|
183
|
+
if layout["provisionType"] && layout["provisionType"]["id"] && layout["provisionType"]["hasNetworks"]
|
184
|
+
# prompt for network interfaces (if supported)
|
185
|
+
begin
|
186
|
+
network_interfaces = prompt_network_interfaces(cloud_id, layout["provisionType"]["id"], options, @api_client)
|
187
|
+
if !network_interfaces.empty?
|
188
|
+
payload[:networkInterfaces] = network_interfaces
|
189
|
+
end
|
190
|
+
rescue RestClient::Exception => e
|
191
|
+
print_yellow_warning "Unable to load network options. Proceeding..."
|
192
|
+
print_rest_exception(e, options) if Morpheus::Logging.print_stacktrace?
|
192
193
|
end
|
193
|
-
|
194
|
-
# puts "\nexiting early...\n"
|
195
|
-
# exit 1
|
196
|
-
|
197
|
-
rescue RestClient::Exception => e
|
198
|
-
print_red_alert "Unable to load options for selected plan."
|
199
|
-
print_rest_exception(e, options)
|
200
|
-
exit 1
|
201
194
|
end
|
202
|
-
|
195
|
+
|
196
|
+
|
203
197
|
type_payload = {}
|
204
198
|
if !layout['optionTypes'].nil? && !layout['optionTypes'].empty?
|
205
|
-
type_payload = Morpheus::Cli::OptionTypes.prompt(layout['optionTypes'],options[:options],@api_client,{groupId:
|
199
|
+
type_payload = Morpheus::Cli::OptionTypes.prompt(layout['optionTypes'],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_prompt['version']})
|
206
200
|
elsif !instance_type['optionTypes'].nil? && !instance_type['optionTypes'].empty?
|
207
|
-
type_payload = Morpheus::Cli::OptionTypes.prompt(instance_type['optionTypes'],options[:options],@api_client,{groupId:
|
201
|
+
type_payload = Morpheus::Cli::OptionTypes.prompt(instance_type['optionTypes'],options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_prompt['version']})
|
208
202
|
end
|
209
203
|
if !type_payload['config'].nil?
|
210
204
|
payload.merge!(type_payload['config'])
|
@@ -212,8 +206,16 @@ class Morpheus::Cli::Instances
|
|
212
206
|
|
213
207
|
provision_payload = {}
|
214
208
|
if !layout['provisionType'].nil? && !layout['provisionType']['optionTypes'].nil? && !layout['provisionType']['optionTypes'].empty?
|
215
|
-
|
216
|
-
|
209
|
+
instance_type_option_types = layout['provisionType']['optionTypes']
|
210
|
+
# remove volume options if volumes were configured
|
211
|
+
if !payload[:volumes].empty?
|
212
|
+
instance_type_option_types = reject_volume_option_types(instance_type_option_types)
|
213
|
+
end
|
214
|
+
# remove networkId option if networks were configured above
|
215
|
+
if !payload[:networkInterfaces].empty?
|
216
|
+
instance_type_option_types = reject_networking_option_types(instance_type_option_types)
|
217
|
+
end
|
218
|
+
provision_payload = Morpheus::Cli::OptionTypes.prompt(instance_type_option_types,options[:options],@api_client,{groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_prompt['version']})
|
217
219
|
end
|
218
220
|
|
219
221
|
if !provision_payload.nil? && !provision_payload['config'].nil?
|
@@ -660,46 +662,28 @@ class Morpheus::Cli::Instances
|
|
660
662
|
|
661
663
|
puts "\nDue to limitations by most Guest Operating Systems, Disk sizes can only be expanded and not reduced.\nIf a smaller plan is selected, memory and CPU (if relevant) will be reduced but storage will not.\n\n"
|
662
664
|
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
665
|
+
# prompt for service plan
|
666
|
+
service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, layoutId: layout_id})
|
667
|
+
service_plans = service_plans_json["plans"]
|
668
|
+
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
|
669
|
+
service_plans_dropdown.each do |plan|
|
668
670
|
if plan['value'] && plan['value'].to_i == plan_id.to_i
|
669
671
|
plan['name'] = "#{plan['name']} (current)"
|
670
672
|
end
|
671
673
|
end
|
672
|
-
|
673
|
-
|
674
|
-
new_plan_id =
|
674
|
+
plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
|
675
|
+
service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
|
676
|
+
new_plan_id = service_plan["id"]
|
677
|
+
#payload[:servicePlan] = new_plan_id # ew, this api uses servicePlanId instead
|
675
678
|
payload[:servicePlanId] = new_plan_id
|
676
679
|
|
677
680
|
volumes_response = @instances_interface.volumes(instance['id'])
|
678
681
|
current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
679
682
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
# print JSON.pretty_generate(service_plan_options_json)
|
685
|
-
|
686
|
-
plan_options = service_plan_options_json['plan']
|
687
|
-
volumes = prompt_resize_instance_volumes(current_volumes, plan_options, options, @api_client, {})
|
688
|
-
|
689
|
-
# puts "VOLUMES:"
|
690
|
-
# print JSON.pretty_generate(volumes)
|
691
|
-
|
692
|
-
if !volumes.empty?
|
693
|
-
payload[:volumes] = volumes
|
694
|
-
end
|
695
|
-
|
696
|
-
# puts "\nexiting early...\n"
|
697
|
-
# exit 1
|
698
|
-
|
699
|
-
rescue RestClient::Exception => e
|
700
|
-
print_red_alert "Unable to load options for selected plan."
|
701
|
-
print_rest_exception(e, options)
|
702
|
-
exit 1
|
683
|
+
# prompt for volumes
|
684
|
+
volumes = prompt_resize_volumes(current_volumes, service_plan, options, @api_client, {})
|
685
|
+
if !volumes.empty?
|
686
|
+
payload[:volumes] = volumes
|
703
687
|
end
|
704
688
|
|
705
689
|
# only amazon supports this option
|
@@ -1048,8 +1032,8 @@ private
|
|
1048
1032
|
end
|
1049
1033
|
end
|
1050
1034
|
|
1051
|
-
def find_cloud_by_name(
|
1052
|
-
option_results = @options_interface.options_for_source('clouds',{groupId:
|
1035
|
+
def find_cloud_by_name(group_id, name)
|
1036
|
+
option_results = @options_interface.options_for_source('clouds',{groupId: group_id})
|
1053
1037
|
match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
|
1054
1038
|
if match.nil?
|
1055
1039
|
return nil
|
@@ -11,6 +11,10 @@ module Morpheus::Cli::PrintHelper
|
|
11
11
|
print red, bold, "\n#{msg}\n\n", reset
|
12
12
|
end
|
13
13
|
|
14
|
+
def print_yellow_warning(msg)
|
15
|
+
print yellow, bold, "\n#{msg}\n\n", reset
|
16
|
+
end
|
17
|
+
|
14
18
|
def print_green_success(msg)
|
15
19
|
print green, bold, "\n#{msg}\n\n", reset
|
16
20
|
end
|
@@ -10,7 +10,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
10
10
|
|
11
11
|
# This recreates the behavior of multi_disk.js
|
12
12
|
# returns array of volumes based on service plan options (plan_info)
|
13
|
-
def
|
13
|
+
def prompt_volumes(plan_info, options={}, api_client=nil, api_params={})
|
14
14
|
#puts "Configure Volumes:"
|
15
15
|
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
16
16
|
|
@@ -203,7 +203,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
203
203
|
|
204
204
|
# This recreates the behavior of multi_disk.js
|
205
205
|
# returns array of volumes based on service plan options (plan_info)
|
206
|
-
def
|
206
|
+
def prompt_resize_volumes(current_volumes, plan_info, options={}, api_client=nil, api_params={})
|
207
207
|
#puts "Configure Volumes:"
|
208
208
|
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
209
209
|
|
@@ -484,4 +484,136 @@ module Morpheus::Cli::ProvisioningHelper
|
|
484
484
|
return volumes
|
485
485
|
end
|
486
486
|
|
487
|
+
|
488
|
+
# This recreates the behavior of multi_networks.js
|
489
|
+
# This is used by both `instances add` and `hosts add`
|
490
|
+
# returns array of networkInterfaces based on provision type and cloud settings
|
491
|
+
def prompt_network_interfaces(zone_id, provision_type_id, options={}, api_client=nil)
|
492
|
+
#puts "Configure Networks:"
|
493
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
494
|
+
|
495
|
+
network_interfaces = []
|
496
|
+
|
497
|
+
zone_network_options_json = api_client.options.options_for_source('zoneNetworkOptions', {zoneId: zone_id, provisionTypeId: provision_type_id})
|
498
|
+
# puts "zoneNetworkOptions JSON"
|
499
|
+
# puts JSON.pretty_generate(zone_network_options_json)
|
500
|
+
zone_network_data = zone_network_options_json['data'] || {}
|
501
|
+
networks = zone_network_data['networks']
|
502
|
+
network_interface_types = (zone_network_data['networkTypes'] || []).sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
|
503
|
+
enable_network_type_selection = (zone_network_data['enableNetworkTypeSelection'] == 'on' || zone_network_data['enableNetworkTypeSelection'] == true)
|
504
|
+
has_networks = zone_network_data["hasNetworks"] == true
|
505
|
+
max_networks = zone_network_data["maxNetworks"] ? zone_network_data["maxNetworks"].to_i : nil
|
506
|
+
|
507
|
+
# skip unless provision type supports networks
|
508
|
+
if !has_networks
|
509
|
+
return nil
|
510
|
+
end
|
511
|
+
|
512
|
+
# no networks available, shouldn't happen
|
513
|
+
if networks.empty?
|
514
|
+
return network_interfaces
|
515
|
+
end
|
516
|
+
|
517
|
+
network_options = []
|
518
|
+
networks.each do |opt|
|
519
|
+
if !opt.nil?
|
520
|
+
network_options << {'name' => opt['name'], 'value' => opt['id']}
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
network_interface_type_options = []
|
525
|
+
network_interface_types.each do |opt|
|
526
|
+
if !opt.nil?
|
527
|
+
network_interface_type_options << {'name' => opt['name'], 'value' => opt['id']}
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
|
532
|
+
interface_index = 1
|
533
|
+
|
534
|
+
# has_another_interface = options[:options] && options[:options]["networkInterface"]
|
535
|
+
# add_another_interface = has_another_interface || (!no_prompt)
|
536
|
+
add_another_interface = true
|
537
|
+
|
538
|
+
while add_another_interface do
|
539
|
+
|
540
|
+
# if !no_prompt
|
541
|
+
# if interface_index == 1
|
542
|
+
# puts "Configure Network Interface"
|
543
|
+
# else
|
544
|
+
# puts "Configure Network Interface #{interface_index}"
|
545
|
+
# end
|
546
|
+
# end
|
547
|
+
|
548
|
+
field_context = interface_index == 1 ? "networkInterface" : "networkInterface#{interface_index}"
|
549
|
+
|
550
|
+
network_interface = {}
|
551
|
+
|
552
|
+
# choose network
|
553
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'networkId', 'type' => 'select', 'fieldLabel' => "Network", 'selectOptions' => network_options, 'required' => true, 'skipSingleOption' => false, 'description' => 'Choose a network for this interface.', 'defaultValue' => network_interface['networkId']}], options[:options])
|
554
|
+
network_interface['network'] = {}
|
555
|
+
network_interface['network']['id'] = v_prompt[field_context]['networkId'].to_i
|
556
|
+
|
557
|
+
selected_network = networks.find {|it| it["id"] == network_interface['network']['id'] }
|
558
|
+
|
559
|
+
# choose network interface type
|
560
|
+
if enable_network_type_selection && !network_interface_type_options.empty?
|
561
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'networkInterfaceTypeId', 'type' => 'select', 'fieldLabel' => "Network Interface Type", 'selectOptions' => network_interface_type_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a network interface type.', 'defaultValue' => network_interface['networkInterfaceTypeId']}], options[:options])
|
562
|
+
network_interface['networkInterfaceTypeId'] = v_prompt[field_context]['networkInterfaceTypeId'].to_i
|
563
|
+
end
|
564
|
+
|
565
|
+
# choose IP unless network has a pool configured
|
566
|
+
if selected_network['pool']
|
567
|
+
puts "IP Address: Using pool '#{selected_network['pool']['name']}'" if !no_prompt
|
568
|
+
elsif selected_network['dhcpServer']
|
569
|
+
puts "IP Address: Using DHCP" if !no_prompt
|
570
|
+
else
|
571
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'ipAddress', 'type' => 'text', 'fieldLabel' => "IP Address", 'required' => true, 'description' => 'Enter an IP for this network interface. x.x.x.x', 'defaultValue' => network_interface['ipAddress']}], options[:options])
|
572
|
+
network_interface['ipAddress'] = v_prompt[field_context]['ipAddress']
|
573
|
+
end
|
574
|
+
|
575
|
+
network_interfaces << network_interface
|
576
|
+
|
577
|
+
interface_index += 1
|
578
|
+
has_another_interface = options[:options] && options[:options]["networkInterface#{interface_index}"]
|
579
|
+
add_another_interface = has_another_interface || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another network interface?"))
|
580
|
+
if max_networks && network_interfaces.size >= max_networks
|
581
|
+
add_another_interface = false
|
582
|
+
end
|
583
|
+
|
584
|
+
end
|
585
|
+
|
586
|
+
return network_interfaces
|
587
|
+
|
588
|
+
end
|
589
|
+
|
590
|
+
# reject old volume option types
|
591
|
+
# these will eventually get removed from the associated optionTypes
|
592
|
+
def reject_volume_option_types(option_types)
|
593
|
+
option_types.reject {|opt|
|
594
|
+
['osDiskSize', 'osDiskType',
|
595
|
+
'diskSize', 'diskType',
|
596
|
+
'datastoreId', 'storagePodId'
|
597
|
+
].include?(opt['fieldName'])
|
598
|
+
}
|
599
|
+
end
|
600
|
+
|
601
|
+
# reject old networking option types
|
602
|
+
# these will eventually get removed from the associated optionTypes
|
603
|
+
def reject_networking_option_types(option_types)
|
604
|
+
option_types.reject {|opt|
|
605
|
+
['networkId', 'networkType', 'ipAddress', 'netmask', 'gateway', 'nameservers',
|
606
|
+
'vmwareNetworkType', 'vmwareIpAddress', 'vmwareNetmask', 'vmwareGateway', 'vmwareNameservers'
|
607
|
+
].include?(opt['fieldName'])
|
608
|
+
}
|
609
|
+
end
|
610
|
+
|
611
|
+
# reject old option types that now come from the selected service plan
|
612
|
+
# these will eventually get removed from the associated optionTypes
|
613
|
+
def reject_service_plan_option_types(option_types)
|
614
|
+
option_types.reject {|opt|
|
615
|
+
['cpuCount', 'memorySize', 'memory'].include?(opt['fieldName'])
|
616
|
+
}
|
617
|
+
end
|
618
|
+
|
487
619
|
end
|
data/lib/morpheus/cli/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.9.
|
4
|
+
version: 2.9.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Estes
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-
|
13
|
+
date: 2017-02-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|