morpheus-cli 0.9.9 → 0.9.10

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.
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