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.
- checksums.yaml +4 -4
- data/lib/morpheus/api/api_client.rb +4 -0
- data/lib/morpheus/api/app_templates_interface.rb +74 -0
- data/lib/morpheus/api/instance_types_interface.rb +9 -0
- data/lib/morpheus/api/instances_interface.rb +16 -0
- data/lib/morpheus/api/roles_interface.rb +37 -1
- data/lib/morpheus/cli.rb +4 -1
- data/lib/morpheus/cli/accounts.rb +82 -58
- data/lib/morpheus/cli/app_templates.rb +908 -0
- data/lib/morpheus/cli/apps.rb +226 -187
- data/lib/morpheus/cli/cli_command.rb +57 -30
- data/lib/morpheus/cli/clouds.rb +50 -65
- data/lib/morpheus/cli/deployments.rb +18 -33
- data/lib/morpheus/cli/deploys.rb +1 -3
- data/lib/morpheus/cli/groups.rb +54 -38
- data/lib/morpheus/cli/hosts.rb +86 -80
- data/lib/morpheus/cli/instance_types.rb +42 -29
- data/lib/morpheus/cli/instances.rb +192 -69
- data/lib/morpheus/cli/key_pairs.rb +70 -87
- data/lib/morpheus/cli/license.rb +7 -9
- data/lib/morpheus/cli/load_balancers.rb +23 -53
- data/lib/morpheus/cli/mixins/accounts_helper.rb +7 -8
- data/lib/morpheus/cli/mixins/print_helper.rb +67 -0
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +461 -0
- data/lib/morpheus/cli/option_types.rb +71 -18
- data/lib/morpheus/cli/roles.rb +725 -34
- data/lib/morpheus/cli/security_group_rules.rb +50 -70
- data/lib/morpheus/cli/security_groups.rb +61 -48
- data/lib/morpheus/cli/shell.rb +123 -14
- data/lib/morpheus/cli/tasks.rb +24 -59
- data/lib/morpheus/cli/users.rb +86 -71
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +21 -51
- data/lib/morpheus/cli/workflows.rb +14 -29
- data/lib/morpheus/ext/nil_class.rb +5 -0
- data/lib/morpheus/formatters.rb +1 -0
- metadata +7 -3
- 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
|