morpheus-cli 2.9.3.1 → 2.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 59ad606bfeda37fd17e920c117fb7c137b9a5311
4
- data.tar.gz: 53134a57f0230f128375239d942bfcdd5ebc0191
3
+ metadata.gz: 7efa35bc257cb762e29ce35995cc2291e5d21e54
4
+ data.tar.gz: ca41c50847ed8ee3a5e50d7e75c773332b1b64da
5
5
  SHA512:
6
- metadata.gz: 57818d33486bcfe687f44428fc395c6b2c8258e2bd4a1727ef35fad6d5e3aa206e602829c9b0f9668638892ebfe2154ed9232cb7ca2dc1c9d6ef4fdf8334404c
7
- data.tar.gz: 279d0d6179234c85b176678a7a5e2de383b127c4ec1bc9e16800dbf8010ee9aa66fb3ddbffba2030a78b9ab0b1ce3c2191642ce6b3c2d2f26c87df4cdb04b53e
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
- groupId = app_template['config']['siteId']
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 groupId.nil?
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: groupId})
374
- cloud = cloud_prompt['cloud']
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: cloud,
376
+ :zoneId => cloud_id,
399
377
  :instance => {
400
378
  :name => instance_name,
401
379
  :site => {
402
- :id => groupId
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: groupId, cloudId: cloud, instanceTypeId: instance_type['id']})
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: groupId, cloudId: cloud, instanceTypeId: instance_type['id'], version: version_prompt['version']})
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: groupId, cloudId: cloud, zoneId: cloud, instanceTypeId: instance_type['id'], version: version_prompt['version']})
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: groupId, cloudId: cloud, zoneId: cloud, instanceTypeId: instance_type['id'], version: version_prompt['version']})
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: groupId, cloudId: cloud, zoneId: cloud, instanceTypeId: instance_type['id'], version: version_prompt['version']})
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"=>groupId.to_s,
495
- "zoneId"=>cloud.to_s
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(groupId,name)
849
- option_results = @options_interface.options_for_source('clouds',{groupId: 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}"
@@ -27,12 +27,13 @@ class Morpheus::Cli::Apps
27
27
  end
28
28
 
29
29
  def handle(args)
30
- usage = "Usage: morpheus apps [list,add,remove,stop,start,restart,resize,upgrade,clone,envs,setenv,delenv,firewall_disable,firewall_enable,security_groups,apply_security_groups] [name]"
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
- when 'add'
35
- add(args[1..-1])
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|
@@ -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
- params = Morpheus::Cli::OptionTypes.prompt(server_type['optionTypes'],options[:options],@api_client, options[:params])
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
- server_payload = {server: {name: name, zone: {id: zone['id']}, computeServerType: [id: server_type['id']]}.merge(params['server']), config: params['config'], network: params['network']}
213
- json_response = @servers_interface.create(server_payload)
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(groupId, name)
530
- zone_results = @clouds_interface.get({groupId: groupId, name: name})
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
- groupId = nil
127
+ group_id = nil
128
128
  if !options[:group].nil?
129
- group = find_group_by_name(options[:group])
130
- if !group.nil?
131
- groupId = group
132
- end
129
+ group_id = find_group_by_name(options[:group])
133
130
  else
134
- groupId = @active_groups[@appliance_name.to_sym]
131
+ group_id = @active_groups[@appliance_name.to_sym]
135
132
  end
136
133
 
137
- if groupId.nil?
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
- cloud = find_cloud_by_name(groupId,options[:cloud])
147
- if cloud.nil?
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: cloud,
151
+ :zoneId => cloud_id,
155
152
  :instance => {
156
153
  :name => instance_name,
157
154
  :site => {
158
- :id => groupId
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: groupId, cloudId: cloud, instanceTypeId: instance_type['id']})
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: groupId, cloudId: cloud, instanceTypeId: instance_type['id'], version: version_prompt['version']})
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
- 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']})
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
- begin
179
- service_plan_options_json = @instance_types_interface.service_plan_options(plan_prompt['servicePlan'], {cloudId: cloud, zoneId: cloud, layoutId: layout_id})
180
-
181
- # puts ""
182
- # print JSON.pretty_generate(service_plan_options_json)
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
- # puts "VOLUMES:"
188
- # print JSON.pretty_generate(volumes)
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
- if !volumes.empty?
191
- payload[:volumes] = volumes
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: groupId, cloudId: cloud, zoneId: cloud, instanceTypeId: instance_type['id'], version: version_prompt['version']})
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: groupId, cloudId: cloud, zoneId: cloud, instanceTypeId: instance_type['id'], version: version_prompt['version']})
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
- #puts "Checking for option Types"
216
- provision_payload = Morpheus::Cli::OptionTypes.prompt(layout['provisionType']['optionTypes'],options[:options],@api_client,{groupId: groupId, cloudId: cloud, zoneId: cloud, instanceTypeId: instance_type['id'], version: version_prompt['version']})
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
- #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']})
665
- available_plans_result = @options_interface.options_for_source('instanceServicePlans',{groupId: group_id, zoneId: cloud_id, instanceTypeId: instance['instanceType']['id'], layoutId: layout_id, version: instance['instanceVersion']})
666
- available_plans = available_plans_result['data']
667
- available_plans.each do |plan|
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
- plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'New Plan', 'selectOptions' => available_plans, 'required' => true, 'description' => 'Choose the new plan for this instance'}],options[:options] )
674
- new_plan_id = plan_prompt['servicePlan']
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
- begin
681
- service_plan_options_json = @instance_types_interface.service_plan_options(new_plan_id, {cloudId: cloud_id, zoneId: cloud_id, layoutId: layout_id})
682
-
683
- # puts ""
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(groupId,name)
1052
- option_results = @options_interface.options_for_source('clouds',{groupId: 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 prompt_instance_volumes(plan_info, options={}, api_client=nil, api_params={})
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 prompt_resize_instance_volumes(current_volumes, plan_info, options={}, api_client=nil, api_params={})
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
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "2.9.3.1"
4
+ VERSION = "2.9.4"
5
5
  end
6
6
  end
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.3.1
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-01-25 00:00:00.000000000 Z
13
+ date: 2017-02-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler