morpheus-cli 0.9.9 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api/api_client.rb +4 -0
  3. data/lib/morpheus/api/app_templates_interface.rb +74 -0
  4. data/lib/morpheus/api/instance_types_interface.rb +9 -0
  5. data/lib/morpheus/api/instances_interface.rb +16 -0
  6. data/lib/morpheus/api/roles_interface.rb +37 -1
  7. data/lib/morpheus/cli.rb +4 -1
  8. data/lib/morpheus/cli/accounts.rb +82 -58
  9. data/lib/morpheus/cli/app_templates.rb +908 -0
  10. data/lib/morpheus/cli/apps.rb +226 -187
  11. data/lib/morpheus/cli/cli_command.rb +57 -30
  12. data/lib/morpheus/cli/clouds.rb +50 -65
  13. data/lib/morpheus/cli/deployments.rb +18 -33
  14. data/lib/morpheus/cli/deploys.rb +1 -3
  15. data/lib/morpheus/cli/groups.rb +54 -38
  16. data/lib/morpheus/cli/hosts.rb +86 -80
  17. data/lib/morpheus/cli/instance_types.rb +42 -29
  18. data/lib/morpheus/cli/instances.rb +192 -69
  19. data/lib/morpheus/cli/key_pairs.rb +70 -87
  20. data/lib/morpheus/cli/license.rb +7 -9
  21. data/lib/morpheus/cli/load_balancers.rb +23 -53
  22. data/lib/morpheus/cli/mixins/accounts_helper.rb +7 -8
  23. data/lib/morpheus/cli/mixins/print_helper.rb +67 -0
  24. data/lib/morpheus/cli/mixins/provisioning_helper.rb +461 -0
  25. data/lib/morpheus/cli/option_types.rb +71 -18
  26. data/lib/morpheus/cli/roles.rb +725 -34
  27. data/lib/morpheus/cli/security_group_rules.rb +50 -70
  28. data/lib/morpheus/cli/security_groups.rb +61 -48
  29. data/lib/morpheus/cli/shell.rb +123 -14
  30. data/lib/morpheus/cli/tasks.rb +24 -59
  31. data/lib/morpheus/cli/users.rb +86 -71
  32. data/lib/morpheus/cli/version.rb +1 -1
  33. data/lib/morpheus/cli/virtual_images.rb +21 -51
  34. data/lib/morpheus/cli/workflows.rb +14 -29
  35. data/lib/morpheus/ext/nil_class.rb +5 -0
  36. data/lib/morpheus/formatters.rb +1 -0
  37. metadata +7 -3
  38. data/lib/morpheus/cli/error_handler.rb +0 -44
@@ -1,8 +1,15 @@
1
+ require 'table_print'
2
+ require 'morpheus/cli/mixins/print_helper'
3
+
1
4
  # Mixin for Morpheus::Cli command classes
2
5
  # Provides common methods for fetching and printing accounts, roles, and users.
3
6
  # The including class must establish @accounts_interface, @roles_interface, @users_interface
4
7
  module Morpheus::Cli::AccountsHelper
5
8
 
9
+ def self.included(klass)
10
+ klass.include Morpheus::Cli::PrintHelper
11
+ end
12
+
6
13
  def find_account_by_id(id)
7
14
  raise "#{self.class} has not defined @accounts_interface" if @accounts_interface.nil?
8
15
  begin
@@ -182,12 +189,4 @@ module Morpheus::Cli::AccountsHelper
182
189
  print reset
183
190
  end
184
191
 
185
- def print_red_alert(msg)
186
- print red, bold, "\n#{msg}\n\n", reset
187
- end
188
-
189
- def print_green_success(msg)
190
- print green, bold, "\n#{msg}\n\n", reset
191
- end
192
-
193
192
  end
@@ -0,0 +1,67 @@
1
+ require 'term/ansicolor'
2
+ require 'json'
3
+
4
+ module Morpheus::Cli::PrintHelper
5
+
6
+ def self.included(klass)
7
+ klass.include Term::ANSIColor
8
+ end
9
+
10
+ def print_red_alert(msg)
11
+ print red, bold, "\n#{msg}\n\n", reset
12
+ end
13
+
14
+ def print_green_success(msg)
15
+ print green, bold, "\n#{msg}\n\n", reset
16
+ end
17
+
18
+ def print_errors(response, options={})
19
+ begin
20
+ if options[:json]
21
+ print red, "\n"
22
+ print JSON.pretty_generate(response)
23
+ print reset, "\n\n"
24
+ else
25
+ if !response['success']
26
+ print red,bold, "\n"
27
+ if response['msg']
28
+ puts response['msg']
29
+ end
30
+ if response['errors']
31
+ response['errors'].each do |key, value|
32
+ print "* #{key}: #{value}\n"
33
+ end
34
+ end
35
+ print reset, "\n"
36
+ else
37
+ # this should not really happen
38
+ print cyan,bold, "\nSuccess!"
39
+ end
40
+ end
41
+ ensure
42
+ print reset
43
+ end
44
+ end
45
+
46
+ def print_rest_exception(e, options={})
47
+ if e.response.code == 400
48
+ response = JSON.parse(e.response.to_s)
49
+ print_errors(response, options)
50
+ else
51
+ print_red_alert "Error Communicating with the Appliance. Please try again later. #{e}"
52
+ if options[:json]
53
+ begin
54
+ response = JSON.parse(e.response.to_s)
55
+ print red, "\n"
56
+ print JSON.pretty_generate(response)
57
+ print reset, "\n\n"
58
+ rescue TypeError, JSON::ParserError => ex
59
+ #print_red_alert "Failed to parse JSON response: #{ex}"
60
+ ensure
61
+ print reset
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,461 @@
1
+ require 'morpheus/cli/mixins/print_helper'
2
+ require 'morpheus/cli/option_types'
3
+ # Mixin for Morpheus::Cli command classes
4
+ # Provides common methods for provisioning instances
5
+ module Morpheus::Cli::ProvisioningHelper
6
+
7
+ def self.included(klass)
8
+ klass.include Morpheus::Cli::PrintHelper
9
+ end
10
+
11
+ # This recreates the behavior of multi_disk.js
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={})
14
+ #puts "Configure Volumes:"
15
+ no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
16
+
17
+ volumes = []
18
+
19
+ plan_size = nil
20
+ if plan_info['maxStorage']
21
+ plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
22
+ end
23
+
24
+ root_storage_types = []
25
+ if plan_info['rootStorageTypes']
26
+ plan_info['rootStorageTypes'].each do |opt|
27
+ root_storage_types << {'name' => opt['name'], 'value' => opt['id']}
28
+ end
29
+ end
30
+
31
+ storage_types = []
32
+ if plan_info['storageTypes']
33
+ plan_info['storageTypes'].each do |opt|
34
+ storage_types << {'name' => opt['name'], 'value' => opt['id']}
35
+ end
36
+ end
37
+
38
+ datastore_options = []
39
+ if plan_info['supportsAutoDatastore']
40
+ if plan_info['autoOptions']
41
+ plan_info['autoOptions'].each do |opt|
42
+ datastore_options << {'name' => opt['name'], 'value' => opt['id']}
43
+ end
44
+ end
45
+ end
46
+ if plan_info['datastores']
47
+ plan_info['datastores'].each do |k, v|
48
+ v.each do |opt|
49
+ datastore_options << {'name' => "#{k}: #{opt['name']}", 'value' => opt['id']}
50
+ end
51
+ end
52
+ end
53
+
54
+ #puts "Configure Root Volume"
55
+
56
+ field_context = "rootVolume"
57
+
58
+ if root_storage_types.empty?
59
+ # this means there's no configuration, just send a single root volume to the server
60
+ storage_type_id = nil
61
+ storage_type = nil
62
+ else
63
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => 'Root Storage Type', 'selectOptions' => root_storage_types, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
64
+ storage_type_id = v_prompt[field_context]['storageType']
65
+ storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
66
+ end
67
+
68
+ # sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
69
+ root_custom_size_options = []
70
+ if plan_info['rootCustomSizeOptions'] && plan_info['rootCustomSizeOptions'][storage_type_id.to_s]
71
+ plan_info['rootCustomSizeOptions'][storage_type_id.to_s].each do |opt|
72
+ root_custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
73
+ end
74
+ end
75
+
76
+ volume_label = 'root'
77
+ volume = {
78
+ 'id' => -1,
79
+ 'rootVolume' => true,
80
+ 'name' => volume_label,
81
+ 'size' => plan_size,
82
+ 'sizeId' => nil,
83
+ 'storageType' => storage_type_id,
84
+ 'datastoreId' => nil
85
+ }
86
+
87
+ if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customLabel']
88
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Root Volume Label', 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume_label}], options[:options])
89
+ volume['name'] = v_prompt[field_context]['name']
90
+ end
91
+ if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
92
+ if root_custom_size_options.empty?
93
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => 'Root Volume Size (GB)', 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => plan_size}], options[:options])
94
+ volume['size'] = v_prompt[field_context]['size']
95
+ volume['sizeId'] = nil #volume.delete('sizeId')
96
+ else
97
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => 'Root Volume Size', 'selectOptions' => root_custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
98
+ volume['sizeId'] = v_prompt[field_context]['sizeId']
99
+ volume['size'] = nil #volume.delete('size')
100
+ end
101
+ else
102
+ # might need different logic here ? =o
103
+ volume['size'] = plan_size
104
+ volume['sizeId'] = nil #volume.delete('sizeId')
105
+ end
106
+ if !datastore_options.empty?
107
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => 'Root Datastore', 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
108
+ volume['datastoreId'] = v_prompt[field_context]['datastoreId']
109
+ end
110
+
111
+ volumes << volume
112
+
113
+ if plan_info['addVolumes']
114
+ volume_index = 1
115
+
116
+ has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
117
+ add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?"))
118
+
119
+ while add_another_volume do
120
+
121
+ #puts "Configure Data #{volume_index} Volume"
122
+
123
+ field_context = "dataVolume#{volume_index}"
124
+
125
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
126
+ storage_type_id = v_prompt[field_context]['storageType']
127
+ storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
128
+
129
+
130
+ # sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
131
+ custom_size_options = []
132
+ if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
133
+ plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
134
+ custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
135
+ end
136
+ end
137
+
138
+ volume_label = (volume_index == 1 ? 'data' : "data #{volume_index}")
139
+ volume = {
140
+ 'id' => -1,
141
+ 'rootVolume' => false,
142
+ 'name' => volume_label,
143
+ 'size' => plan_size,
144
+ 'sizeId' => nil,
145
+ 'storageType' => storage_type_id,
146
+ 'datastoreId' => nil
147
+ }
148
+
149
+ if plan_info['customizeVolume'] && storage_type['customLabel']
150
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume_label}], options[:options])
151
+ volume['name'] = v_prompt[field_context]['name']
152
+ end
153
+ if plan_info['customizeVolume'] && storage_type['customSize']
154
+ if custom_size_options.empty?
155
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => plan_size}], options[:options])
156
+ volume['size'] = v_prompt[field_context]['size']
157
+ volume['sizeId'] = nil #volume.delete('sizeId')
158
+ else
159
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
160
+ volume['sizeId'] = v_prompt[field_context]['sizeId']
161
+ volume['size'] = nil #volume.delete('size')
162
+ end
163
+ else
164
+ # might need different logic here ? =o
165
+ volume['size'] = plan_size
166
+ volume['sizeId'] = nil #volume.delete('sizeId')
167
+ end
168
+ if !datastore_options.empty?
169
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Datastore", 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
170
+ volume['datastoreId'] = v_prompt[field_context]['datastoreId']
171
+ end
172
+
173
+ volumes << volume
174
+
175
+ # todo: should maxDisk check consider the root volume too?
176
+ if plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
177
+ add_another_volume = false
178
+ else
179
+ volume_index += 1
180
+ has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
181
+ add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?"))
182
+ end
183
+
184
+ end
185
+
186
+ end
187
+
188
+ return volumes
189
+ end
190
+
191
+
192
+ # This recreates the behavior of multi_disk.js
193
+ # returns array of volumes based on service plan options (plan_info)
194
+ def prompt_resize_instance_volumes(current_volumes, plan_info, options={}, api_client=nil, api_params={})
195
+ #puts "Configure Volumes:"
196
+ no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
197
+
198
+ current_root_volume = current_volumes[0]
199
+
200
+ volumes = []
201
+
202
+ plan_size = nil
203
+ if plan_info['maxStorage']
204
+ plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
205
+ end
206
+
207
+ root_storage_types = []
208
+ if plan_info['rootStorageTypes']
209
+ plan_info['rootStorageTypes'].each do |opt|
210
+ root_storage_types << {'name' => opt['name'], 'value' => opt['id']}
211
+ end
212
+ end
213
+
214
+ storage_types = []
215
+ if plan_info['storageTypes']
216
+ plan_info['storageTypes'].each do |opt|
217
+ storage_types << {'name' => opt['name'], 'value' => opt['id']}
218
+ end
219
+ end
220
+
221
+ datastore_options = []
222
+ if plan_info['supportsAutoDatastore']
223
+ if plan_info['autoOptions']
224
+ plan_info['autoOptions'].each do |opt|
225
+ datastore_options << {'name' => opt['name'], 'value' => opt['id']}
226
+ end
227
+ end
228
+ end
229
+ if plan_info['datastores']
230
+ plan_info['datastores'].each do |k, v|
231
+ v.each do |opt|
232
+ datastore_options << {'name' => "#{k}: #{opt['name']}", 'value' => opt['id']}
233
+ end
234
+ end
235
+ end
236
+
237
+ #puts "Configure Root Volume"
238
+
239
+ field_context = "rootVolume"
240
+
241
+ if root_storage_types.empty?
242
+ # this means there's no configuration, just send a single root volume to the server
243
+ storage_type_id = nil
244
+ storage_type = nil
245
+ else
246
+ #v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => 'Root Storage Type', 'selectOptions' => root_storage_types, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
247
+ #storage_type_id = v_prompt[field_context]['storageType']
248
+ storage_type_id = current_root_volume['type'] || current_root_volume['storageType']
249
+ storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
250
+ end
251
+
252
+ # sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
253
+ root_custom_size_options = []
254
+ if plan_info['rootCustomSizeOptions'] && plan_info['rootCustomSizeOptions'][storage_type_id.to_s]
255
+ plan_info['rootCustomSizeOptions'][storage_type_id.to_s].each do |opt|
256
+ root_custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
257
+ end
258
+ end
259
+
260
+ volume = {
261
+ 'id' => current_root_volume['id'],
262
+ 'rootVolume' => true,
263
+ 'name' => current_root_volume['name'],
264
+ 'size' => current_root_volume['size'] > plan_size ? current_root_volume['size'] : plan_size,
265
+ 'sizeId' => nil,
266
+ 'storageType' => storage_type_id,
267
+ 'datastoreId' => current_root_volume['datastoreId']
268
+ }
269
+
270
+ if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customLabel']
271
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Root Volume Label', 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
272
+ volume['name'] = v_prompt[field_context]['name']
273
+ end
274
+ if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
275
+ if root_custom_size_options.empty?
276
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => 'Root Volume Size (GB)', 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
277
+ volume['size'] = v_prompt[field_context]['size']
278
+ volume['sizeId'] = nil #volume.delete('sizeId')
279
+ else
280
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => 'Root Volume Size', 'selectOptions' => root_custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
281
+ volume['sizeId'] = v_prompt[field_context]['sizeId']
282
+ volume['size'] = nil #volume.delete('size')
283
+ end
284
+ else
285
+ # might need different logic here ? =o
286
+ volume['size'] = plan_size
287
+ volume['sizeId'] = nil #volume.delete('sizeId')
288
+ end
289
+ # if !datastore_options.empty?
290
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => 'Root Datastore', 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
291
+ # volume['datastoreId'] = v_prompt[field_context]['datastoreId']
292
+ # end
293
+
294
+ volumes << volume
295
+
296
+ # modify or delete existing data volumes
297
+ (1..(current_volumes.size-1)).each do |volume_index|
298
+ current_volume = current_volumes[volume_index]
299
+
300
+ if current_volume
301
+
302
+ field_context = "dataVolume#{volume_index}"
303
+
304
+ if no_prompt
305
+ volume_action = 'keep'
306
+ else
307
+ action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
308
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'action', 'type' => 'select', 'fieldLabel' => "Modify/Keep/Delete volume '#{current_volume['name']}'", 'selectOptions' => action_options, 'required' => true, 'description' => 'Modify, Keep or Delete existing data volume?'}], options[:options])
309
+ volume_action = v_prompt[field_context]['action']
310
+ end
311
+
312
+ if volume_action == 'delete'
313
+ # deleted volume is just excluded from post params
314
+ next
315
+ elsif volume_action == 'keep'
316
+ volume = {
317
+ 'id' => current_volume['id'].to_i,
318
+ 'rootVolume' => false,
319
+ 'name' => current_volume['name'],
320
+ 'size' => current_volume['size'] > plan_size ? current_volume['size'] : plan_size,
321
+ 'sizeId' => nil,
322
+ 'storageType' => (current_volume['type'] || current_volume['storageType']),
323
+ 'datastoreId' => current_volume['datastoreId']
324
+ }
325
+ volumes << volume
326
+ else
327
+
328
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
329
+ # storage_type_id = v_prompt[field_context]['storageType']
330
+ storage_type_id = current_volume['type'] || current_volume['storageType']
331
+ storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
332
+
333
+ # sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
334
+ custom_size_options = []
335
+ if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
336
+ plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
337
+ custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
338
+ end
339
+ end
340
+
341
+ volume = {
342
+ 'id' => current_volume['id'].to_i,
343
+ 'rootVolume' => false,
344
+ 'name' => current_volume['name'],
345
+ 'size' => current_volume['size'] > plan_size ? current_volume['size'] : plan_size,
346
+ 'sizeId' => nil,
347
+ 'storageType' => (current_volume['type'] || current_volume['storageType']),
348
+ 'datastoreId' => current_volume['datastoreId']
349
+ }
350
+
351
+ if plan_info['customizeVolume'] && storage_type['customLabel']
352
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
353
+ volume['name'] = v_prompt[field_context]['name']
354
+ end
355
+ if plan_info['customizeVolume'] && storage_type['customSize']
356
+ if custom_size_options.empty?
357
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
358
+ volume['size'] = v_prompt[field_context]['size']
359
+ volume['sizeId'] = nil #volume.delete('sizeId')
360
+ else
361
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
362
+ volume['sizeId'] = v_prompt[field_context]['sizeId']
363
+ volume['size'] = nil #volume.delete('size')
364
+ end
365
+ else
366
+ # might need different logic here ? =o
367
+ volume['size'] = plan_size
368
+ volume['sizeId'] = nil #volume.delete('sizeId')
369
+ end
370
+ # if !datastore_options.empty?
371
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Datastore", 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
372
+ # volume['datastoreId'] = v_prompt[field_context]['datastoreId']
373
+ # end
374
+
375
+ volumes << volume
376
+
377
+ end
378
+
379
+ end
380
+ end
381
+
382
+
383
+ if plan_info['addVolumes']
384
+ volume_index = current_volumes.size
385
+
386
+ has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
387
+ add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?"))
388
+
389
+ while add_another_volume do
390
+
391
+ #puts "Configure Data #{volume_index} Volume"
392
+
393
+ field_context = "dataVolume#{volume_index}"
394
+
395
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
396
+ storage_type_id = v_prompt[field_context]['storageType']
397
+ storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
398
+
399
+
400
+ # sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
401
+ custom_size_options = []
402
+ if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
403
+ plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
404
+ custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
405
+ end
406
+ end
407
+
408
+ volume_label = (volume_index == 1 ? 'data' : "data #{volume_index}")
409
+ volume = {
410
+ 'id' => -1,
411
+ 'rootVolume' => false,
412
+ 'name' => volume_label,
413
+ 'size' => plan_size,
414
+ 'sizeId' => nil,
415
+ 'storageType' => storage_type_id,
416
+ 'datastoreId' => nil
417
+ }
418
+
419
+ if plan_info['customizeVolume'] && storage_type['customLabel']
420
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume_label}], options[:options])
421
+ volume['name'] = v_prompt[field_context]['name']
422
+ end
423
+ if plan_info['customizeVolume'] && storage_type['customSize']
424
+ if custom_size_options.empty?
425
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => plan_size}], options[:options])
426
+ volume['size'] = v_prompt[field_context]['size']
427
+ volume['sizeId'] = nil #volume.delete('sizeId')
428
+ else
429
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
430
+ volume['sizeId'] = v_prompt[field_context]['sizeId']
431
+ volume['size'] = nil #volume.delete('size')
432
+ end
433
+ else
434
+ # might need different logic here ? =o
435
+ volume['size'] = plan_size
436
+ volume['sizeId'] = nil #volume.delete('sizeId')
437
+ end
438
+ if !datastore_options.empty?
439
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Datastore", 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
440
+ volume['datastoreId'] = v_prompt[field_context]['datastoreId']
441
+ end
442
+
443
+ volumes << volume
444
+
445
+ # todo: should maxDisk check consider the root volume too?
446
+ if plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
447
+ add_another_volume = false
448
+ else
449
+ volume_index += 1
450
+ has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
451
+ add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?"))
452
+ end
453
+
454
+ end
455
+
456
+ end
457
+
458
+ return volumes
459
+ end
460
+
461
+ end