morpheus-cli 2.10.0 → 2.10.1
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/bin/morpheus +27 -32
- data/lib/morpheus/api/accounts_interface.rb +36 -47
- data/lib/morpheus/api/api_client.rb +141 -110
- data/lib/morpheus/api/app_templates_interface.rb +56 -72
- data/lib/morpheus/api/apps_interface.rb +111 -132
- data/lib/morpheus/api/auth_interface.rb +30 -0
- data/lib/morpheus/api/clouds_interface.rb +71 -76
- data/lib/morpheus/api/custom_instance_types_interface.rb +21 -46
- data/lib/morpheus/api/dashboard_interface.rb +10 -17
- data/lib/morpheus/api/deploy_interface.rb +60 -72
- data/lib/morpheus/api/deployments_interface.rb +53 -71
- data/lib/morpheus/api/groups_interface.rb +55 -45
- data/lib/morpheus/api/instance_types_interface.rb +19 -23
- data/lib/morpheus/api/instances_interface.rb +179 -177
- data/lib/morpheus/api/key_pairs_interface.rb +11 -17
- data/lib/morpheus/api/license_interface.rb +18 -23
- data/lib/morpheus/api/load_balancers_interface.rb +54 -69
- data/lib/morpheus/api/logs_interface.rb +25 -29
- data/lib/morpheus/api/options_interface.rb +13 -17
- data/lib/morpheus/api/provision_types_interface.rb +19 -22
- data/lib/morpheus/api/roles_interface.rb +75 -94
- data/lib/morpheus/api/security_group_rules_interface.rb +28 -37
- data/lib/morpheus/api/security_groups_interface.rb +39 -51
- data/lib/morpheus/api/servers_interface.rb +113 -115
- data/lib/morpheus/api/setup_interface.rb +31 -0
- data/lib/morpheus/api/task_sets_interface.rb +36 -38
- data/lib/morpheus/api/tasks_interface.rb +56 -69
- data/lib/morpheus/api/users_interface.rb +67 -76
- data/lib/morpheus/api/virtual_images_interface.rb +61 -61
- data/lib/morpheus/api/whoami_interface.rb +12 -15
- data/lib/morpheus/cli.rb +71 -60
- data/lib/morpheus/cli/accounts.rb +254 -315
- data/lib/morpheus/cli/alias_command.rb +219 -0
- data/lib/morpheus/cli/app_templates.rb +264 -272
- data/lib/morpheus/cli/apps.rb +608 -671
- data/lib/morpheus/cli/cli_command.rb +259 -21
- data/lib/morpheus/cli/cli_registry.rb +99 -14
- data/lib/morpheus/cli/clouds.rb +599 -372
- data/lib/morpheus/cli/config_file.rb +126 -0
- data/lib/morpheus/cli/credentials.rb +141 -117
- data/lib/morpheus/cli/dashboard_command.rb +48 -56
- data/lib/morpheus/cli/deployments.rb +254 -268
- data/lib/morpheus/cli/deploys.rb +150 -142
- data/lib/morpheus/cli/error_handler.rb +38 -0
- data/lib/morpheus/cli/groups.rb +551 -179
- data/lib/morpheus/cli/hosts.rb +862 -617
- data/lib/morpheus/cli/instance_types.rb +103 -95
- data/lib/morpheus/cli/instances.rb +1335 -1009
- data/lib/morpheus/cli/key_pairs.rb +82 -90
- data/lib/morpheus/cli/library.rb +498 -499
- data/lib/morpheus/cli/license.rb +83 -101
- data/lib/morpheus/cli/load_balancers.rb +314 -300
- data/lib/morpheus/cli/login.rb +66 -44
- data/lib/morpheus/cli/logout.rb +47 -46
- data/lib/morpheus/cli/mixins/accounts_helper.rb +69 -31
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +106 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +181 -17
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -458
- data/lib/morpheus/cli/mixins/whoami_helper.rb +2 -2
- data/lib/morpheus/cli/option_parser.rb +35 -0
- data/lib/morpheus/cli/option_types.rb +232 -192
- data/lib/morpheus/cli/recent_activity_command.rb +61 -65
- data/lib/morpheus/cli/remote.rb +446 -199
- data/lib/morpheus/cli/roles.rb +884 -906
- data/lib/morpheus/cli/security_group_rules.rb +213 -203
- data/lib/morpheus/cli/security_groups.rb +237 -192
- data/lib/morpheus/cli/shell.rb +338 -231
- data/lib/morpheus/cli/tasks.rb +326 -308
- data/lib/morpheus/cli/users.rb +457 -462
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/version_command.rb +16 -18
- data/lib/morpheus/cli/virtual_images.rb +526 -345
- data/lib/morpheus/cli/whoami.rb +125 -111
- data/lib/morpheus/cli/workflows.rb +338 -185
- data/lib/morpheus/formatters.rb +8 -1
- data/lib/morpheus/logging.rb +1 -1
- data/lib/morpheus/rest_client.rb +17 -8
- metadata +9 -3
- data/lib/morpheus/api/custom_instance_types.rb +0 -55
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'uri'
|
1
2
|
require 'term/ansicolor'
|
2
3
|
require 'json'
|
3
4
|
|
@@ -8,26 +9,26 @@ module Morpheus::Cli::PrintHelper
|
|
8
9
|
end
|
9
10
|
|
10
11
|
def print_red_alert(msg)
|
11
|
-
print
|
12
|
+
print "#{red}#{msg}#{reset}\n"
|
12
13
|
end
|
13
14
|
|
14
15
|
def print_yellow_warning(msg)
|
15
|
-
print
|
16
|
+
print "#{yellow}#{msg}#{reset}\n"
|
16
17
|
end
|
17
18
|
|
18
19
|
def print_green_success(msg)
|
19
|
-
print
|
20
|
+
print "#{green}#{msg}#{reset}\n"
|
20
21
|
end
|
21
22
|
|
22
23
|
def print_errors(response, options={})
|
23
24
|
begin
|
24
25
|
if options[:json]
|
25
|
-
print red
|
26
|
+
print red
|
26
27
|
print JSON.pretty_generate(response)
|
27
|
-
print reset, "\n
|
28
|
+
print reset, "\n"
|
28
29
|
else
|
29
30
|
if !response['success']
|
30
|
-
print red,bold
|
31
|
+
print red,bold
|
31
32
|
if response['msg']
|
32
33
|
puts response['msg']
|
33
34
|
end
|
@@ -36,7 +37,7 @@ module Morpheus::Cli::PrintHelper
|
|
36
37
|
print "* #{key}: #{value}\n"
|
37
38
|
end
|
38
39
|
end
|
39
|
-
print reset
|
40
|
+
print reset
|
40
41
|
else
|
41
42
|
# this should not really happen
|
42
43
|
print cyan,bold, "\nSuccess!"
|
@@ -49,19 +50,30 @@ module Morpheus::Cli::PrintHelper
|
|
49
50
|
|
50
51
|
def print_rest_exception(e, options={})
|
51
52
|
if e.response
|
53
|
+
if options[:debug]
|
54
|
+
begin
|
55
|
+
print_rest_exception_request_and_response(e)
|
56
|
+
ensure
|
57
|
+
print reset
|
58
|
+
end
|
59
|
+
return
|
60
|
+
end
|
52
61
|
if e.response.code == 400
|
53
62
|
response = JSON.parse(e.response.to_s)
|
54
63
|
print_errors(response, options)
|
55
64
|
else
|
56
|
-
print_red_alert "Error Communicating with the Appliance.
|
57
|
-
if options[:json]
|
65
|
+
print_red_alert "Error Communicating with the Appliance. #{e}"
|
66
|
+
if options[:json] || options[:debug]
|
58
67
|
begin
|
59
68
|
response = JSON.parse(e.response.to_s)
|
60
|
-
print red
|
69
|
+
print red
|
61
70
|
print JSON.pretty_generate(response)
|
62
|
-
print reset, "\n
|
71
|
+
print reset, "\n"
|
63
72
|
rescue TypeError, JSON::ParserError => ex
|
64
|
-
|
73
|
+
print_red_alert "Failed to parse JSON response: #{ex}"
|
74
|
+
print red
|
75
|
+
print response.to_s
|
76
|
+
print reset, "\n"
|
65
77
|
ensure
|
66
78
|
print reset
|
67
79
|
end
|
@@ -72,21 +84,173 @@ module Morpheus::Cli::PrintHelper
|
|
72
84
|
end
|
73
85
|
end
|
74
86
|
|
75
|
-
def
|
87
|
+
def print_rest_request(req)
|
88
|
+
# JD: IOError when accessing payload... we should probably just be printing at the time the request is made..
|
89
|
+
#out = []
|
90
|
+
#out << "#{req.method} #{req.url.inspect}"
|
91
|
+
#out << req.payload.short_inspect if req.payload
|
92
|
+
# payload = req.instance_variable_get("@payload")
|
93
|
+
# out << payload if payload
|
94
|
+
#out << req.processed_headers.to_a.sort.map { |(k, v)| [k.inspect, v.inspect].join("=>") }.join(", ")
|
95
|
+
#print out.join(', ') + "\n"
|
96
|
+
print "Request:"
|
97
|
+
print "\n"
|
98
|
+
print "#{req.method.to_s.upcase} #{req.url.inspect}"
|
99
|
+
print "\n"
|
100
|
+
end
|
101
|
+
|
102
|
+
def print_rest_response(res)
|
103
|
+
# size = @raw_response ? File.size(@tf.path) : (res.body.nil? ? 0 : res.body.size)
|
104
|
+
size = (res.body.nil? ? 0 : res.body.size)
|
105
|
+
print "Response:"
|
106
|
+
print "\n"
|
107
|
+
display_size = Filesize.from("#{size} B").pretty rescue size
|
108
|
+
print "HTTP #{res.net_http_res.code} - #{res.net_http_res.message} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{display_size}"
|
109
|
+
print "\n"
|
110
|
+
begin
|
111
|
+
print JSON.pretty_generate(JSON.parse(res.body))
|
112
|
+
rescue
|
113
|
+
print res.body.to_s
|
114
|
+
end
|
115
|
+
print "\n"
|
116
|
+
end
|
117
|
+
|
118
|
+
def print_rest_exception_request_and_response(e)
|
119
|
+
print_red_alert "Error Communicating with the Appliance. (#{e.response.code}) #{e}"
|
120
|
+
response = e.response
|
121
|
+
request = response.instance_variable_get("@request")
|
122
|
+
print red
|
123
|
+
print_rest_request(request)
|
124
|
+
print "\n"
|
125
|
+
print_rest_response(response)
|
126
|
+
print reset
|
127
|
+
end
|
128
|
+
|
129
|
+
def print_dry_run(opts)
|
130
|
+
http_method = opts[:method]
|
131
|
+
url = opts[:url]
|
132
|
+
params = opts[:params]
|
133
|
+
params = opts[:headers][:params] if opts[:headers] && opts[:headers][:params]
|
134
|
+
query_string = params.respond_to?(:map) ? URI.encode_www_form(params) : query_string
|
135
|
+
if query_string && !query_string.empty?
|
136
|
+
url = "#{url}?#{query_string}"
|
137
|
+
end
|
138
|
+
request_string = "#{http_method.to_s.upcase} #{url}".strip
|
139
|
+
payload = opts[:payload]
|
76
140
|
print "\n" ,cyan, bold, "DRY RUN\n","==================", "\n\n", reset
|
77
141
|
print cyan
|
78
142
|
print "Request: ", "\n"
|
79
143
|
print reset
|
80
|
-
print
|
144
|
+
print request_string, "\n"
|
81
145
|
print cyan
|
82
|
-
|
83
|
-
|
84
|
-
|
146
|
+
if payload
|
147
|
+
if payload.is_a?(String)
|
148
|
+
begin
|
149
|
+
payload = JSON.parse(payload)
|
150
|
+
rescue => e
|
151
|
+
#payload = "(unparsable) #{payload}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
print "\n"
|
155
|
+
print "JSON: ", "\n"
|
156
|
+
print reset
|
157
|
+
print JSON.pretty_generate(payload)
|
158
|
+
end
|
85
159
|
print "\n"
|
86
160
|
print reset
|
87
161
|
end
|
88
162
|
|
163
|
+
def print_results_pagination(json_response)
|
164
|
+
if json_response && json_response["meta"]
|
165
|
+
print cyan,"\nViewing #{json_response['meta']['offset'].to_i + 1}-#{json_response['meta']['offset'].to_i + json_response['meta']['size'].to_i} of #{json_response['meta']['total']}\n"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
89
169
|
def required_blue_prompt
|
90
170
|
"#{cyan}|#{reset}"
|
91
171
|
end
|
172
|
+
|
173
|
+
|
174
|
+
# shows cyan, yellow, red progress bar where 50% looks like [||||| ]
|
175
|
+
# todo: render units used / available here too maybe
|
176
|
+
def generate_usage_bar(used_value, max_value, opts={})
|
177
|
+
rainbow = opts[:rainbow] != false
|
178
|
+
max_bars = opts[:max_bars] || 50
|
179
|
+
out = ""
|
180
|
+
bars = []
|
181
|
+
percent = 0
|
182
|
+
if max_value.to_i == 0
|
183
|
+
percent = 0
|
184
|
+
else
|
185
|
+
percent = ((used_value.to_f / max_value.to_f) * 100)
|
186
|
+
end
|
187
|
+
percent_label = (used_value.nil? || max_value.to_f == 0.0) ? "n/a" : "#{percent.round(2)}%".rjust(6, ' ')
|
188
|
+
bar_display = ""
|
189
|
+
if percent > 100
|
190
|
+
max_bars.times { bars << "|" }
|
191
|
+
# percent = 100
|
192
|
+
else
|
193
|
+
n_bars = ((percent / 100.0) * max_bars).ceil
|
194
|
+
n_bars.times { bars << "|" }
|
195
|
+
end
|
196
|
+
|
197
|
+
if rainbow
|
198
|
+
rainbow_bar = ""
|
199
|
+
cur_rainbow_color = white
|
200
|
+
bars.each_with_index {|bar, i|
|
201
|
+
reached_percent = (i / max_bars.to_f) * 100
|
202
|
+
new_bar_color = cur_rainbow_color
|
203
|
+
if reached_percent > 80
|
204
|
+
new_bar_color = red
|
205
|
+
elsif reached_percent > 50
|
206
|
+
new_bar_color = yellow
|
207
|
+
elsif reached_percent > 10
|
208
|
+
new_bar_color = cyan
|
209
|
+
end
|
210
|
+
if cur_rainbow_color != new_bar_color
|
211
|
+
cur_rainbow_color = new_bar_color
|
212
|
+
rainbow_bar << cur_rainbow_color
|
213
|
+
end
|
214
|
+
rainbow_bar << bar
|
215
|
+
}
|
216
|
+
padding = max_bars - bars.size
|
217
|
+
if padding > 0
|
218
|
+
padding.times { rainbow_bar << " " }
|
219
|
+
#rainbow_bar << " " * padding
|
220
|
+
end
|
221
|
+
rainbow_bar << reset
|
222
|
+
bar_display = white + "[" + rainbow_bar + white + "]" + " #{cur_rainbow_color}#{percent_label}#{reset}"
|
223
|
+
out << bar_display
|
224
|
+
else
|
225
|
+
bar_color = cyan
|
226
|
+
if percent > 80
|
227
|
+
bar_color = red
|
228
|
+
elsif percent > 50
|
229
|
+
bar_color = yellow
|
230
|
+
end
|
231
|
+
bar_display = white + "[" + bar_color + bars.join.ljust(max_bars, ' ') + white + "]" + " #{percent_label}" + reset
|
232
|
+
out << bar_display
|
233
|
+
end
|
234
|
+
return out
|
235
|
+
end
|
236
|
+
|
237
|
+
def print_stats_usage(stats, opts={})
|
238
|
+
opts[:include] ||= [:memory, :storage, :cpu]
|
239
|
+
if opts[:include].include?(:memory)
|
240
|
+
print cyan, "Memory:".ljust(10, ' ') + generate_usage_bar(stats['usedMemory'], stats['maxMemory']) + cyan + Filesize.from("#{stats['usedMemory']} B").pretty.strip.rjust(15, ' ') + " / " + Filesize.from("#{stats['maxMemory']} B").pretty.strip.ljust(15, ' ') + "\n"
|
241
|
+
end
|
242
|
+
if opts[:include].include?(:storage)
|
243
|
+
print cyan, "Storage:".ljust(10, ' ') + generate_usage_bar(stats['usedStorage'], stats['maxStorage']) + cyan + Filesize.from("#{stats['usedStorage']} B").pretty.strip.rjust(15, ' ') + " / " + Filesize.from("#{stats['maxStorage']} B").pretty.strip.ljust(15, ' ') + "\n"
|
244
|
+
end
|
245
|
+
if opts[:include].include?(:cpu)
|
246
|
+
cpu_usage = (stats['usedCpu'] || stats['cpuUsage'])
|
247
|
+
print cyan, "CPU:".ljust(10, ' ') + generate_usage_bar(cpu_usage.to_f, 100) + "\n"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def print_available_options(option_types)
|
252
|
+
option_lines = option_types.collect {|it| "\t-O #{it['fieldContext'] ? it['fieldContext'] + '.' : ''}#{it['fieldName']}=\"value\"" }.join("\n")
|
253
|
+
puts "Available Options:\n#{option_lines}\n\n"
|
254
|
+
end
|
255
|
+
|
92
256
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'morpheus/cli/mixins/print_helper'
|
2
2
|
require 'morpheus/cli/option_types'
|
3
|
-
# Mixin for Morpheus::Cli command classes
|
3
|
+
# Mixin for Morpheus::Cli command classes
|
4
4
|
# Provides common methods for provisioning instances
|
5
5
|
module Morpheus::Cli::ProvisioningHelper
|
6
6
|
|
@@ -8,23 +8,53 @@ module Morpheus::Cli::ProvisioningHelper
|
|
8
8
|
klass.send :include, Morpheus::Cli::PrintHelper
|
9
9
|
end
|
10
10
|
|
11
|
+
def api_client
|
12
|
+
raise "#{self.class} has not defined @api_client" if @api_client.nil?
|
13
|
+
@api_client
|
14
|
+
end
|
15
|
+
|
16
|
+
def instances_interface
|
17
|
+
# @api_client.instances
|
18
|
+
raise "#{self.class} has not defined @instances_interface" if @instances_interface.nil?
|
19
|
+
@instances_interface
|
20
|
+
end
|
21
|
+
|
22
|
+
def options_interface
|
23
|
+
# @api_client.options
|
24
|
+
raise "#{self.class} has not defined @options_interface" if @options_interface.nil?
|
25
|
+
@options_interface
|
26
|
+
end
|
27
|
+
|
28
|
+
def instance_types_interface
|
29
|
+
# @api_client.instance_types
|
30
|
+
raise "#{self.class} has not defined @instance_types_interface" if @instance_types_interface.nil?
|
31
|
+
@instance_types_interface
|
32
|
+
end
|
33
|
+
|
11
34
|
def get_available_groups(refresh=false)
|
12
35
|
if !@available_groups || refresh
|
13
|
-
option_results =
|
36
|
+
option_results = options_interface.options_for_source('groups',{})
|
14
37
|
@available_groups = option_results['data'].collect {|it|
|
15
38
|
{"id" => it["value"], "name" => it["name"], "value" => it["value"]}
|
16
39
|
}
|
17
40
|
end
|
41
|
+
#puts "get_available_groups() rtn: #{@available_groups.inspect}"
|
18
42
|
return @available_groups
|
19
43
|
end
|
20
44
|
|
21
45
|
def get_available_clouds(group_id, refresh=false)
|
22
|
-
|
46
|
+
if !group_id
|
47
|
+
option_results = options_interface.options_for_source('clouds', {})
|
48
|
+
return option_results['data'].collect {|it|
|
49
|
+
{"id" => it["value"], "name" => it["name"], "value" => it["value"], "zoneTypeId" => it["zoneTypeId"]}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
group = find_group_by_id_for_provisioning(group_id)
|
23
53
|
if !group
|
24
54
|
return []
|
25
55
|
end
|
26
56
|
if !group["clouds"] || refresh
|
27
|
-
option_results =
|
57
|
+
option_results = options_interface.options_for_source('clouds', {groupId: group_id})
|
28
58
|
group["clouds"] = option_results['data'].collect {|it|
|
29
59
|
{"id" => it["value"], "name" => it["name"], "value" => it["value"], "zoneTypeId" => it["zoneTypeId"]}
|
30
60
|
}
|
@@ -32,7 +62,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
32
62
|
return group["clouds"]
|
33
63
|
end
|
34
64
|
|
35
|
-
def
|
65
|
+
def find_group_by_id_for_provisioning(val)
|
36
66
|
groups = get_available_groups()
|
37
67
|
group = groups.find {|it| it["id"].to_s == val.to_s }
|
38
68
|
if !group
|
@@ -42,7 +72,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
42
72
|
return group
|
43
73
|
end
|
44
74
|
|
45
|
-
def
|
75
|
+
def find_group_by_name_for_provisioning(val)
|
46
76
|
groups = get_available_groups()
|
47
77
|
group = groups.find {|it| it["name"].to_s.downcase == val.to_s.downcase }
|
48
78
|
if !group
|
@@ -52,19 +82,15 @@ module Morpheus::Cli::ProvisioningHelper
|
|
52
82
|
return group
|
53
83
|
end
|
54
84
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
group = find_group_by_name(options[:group_name])
|
61
|
-
elsif options[:group_id]
|
62
|
-
group = find_group_by_id(options[:group_id])
|
85
|
+
def find_group_by_name_or_id_for_provisioning(val)
|
86
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
87
|
+
return find_group_by_id_for_provisioning(val)
|
88
|
+
else
|
89
|
+
return find_group_by_name_for_provisioning(val)
|
63
90
|
end
|
64
|
-
return group
|
65
91
|
end
|
66
92
|
|
67
|
-
def
|
93
|
+
def find_cloud_by_id_for_provisioning(group_id, val)
|
68
94
|
clouds = get_available_clouds(group_id)
|
69
95
|
cloud = clouds.find {|it| it["id"].to_s == val.to_s }
|
70
96
|
if !cloud
|
@@ -74,7 +100,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
74
100
|
return cloud
|
75
101
|
end
|
76
102
|
|
77
|
-
def
|
103
|
+
def find_cloud_by_name_for_provisioning(group_id, val)
|
78
104
|
clouds = get_available_clouds(group_id)
|
79
105
|
cloud = clouds.find {|it| it["name"].to_s.downcase == val.to_s.downcase }
|
80
106
|
if !cloud
|
@@ -84,62 +110,98 @@ module Morpheus::Cli::ProvisioningHelper
|
|
84
110
|
return cloud
|
85
111
|
end
|
86
112
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
cloud = find_cloud_by_name(group_id, options[:cloud_name])
|
93
|
-
elsif options[:cloud_id]
|
94
|
-
cloud = find_cloud_by_id(group_id, options[:cloud_id])
|
113
|
+
def find_cloud_by_name_or_id_for_provisioning(group_id, val)
|
114
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
115
|
+
return find_cloud_by_id_for_provisioning(group_id, val)
|
116
|
+
else
|
117
|
+
return find_cloud_by_name_for_provisioning(group_id, val)
|
95
118
|
end
|
96
|
-
return cloud
|
97
119
|
end
|
98
|
-
|
99
120
|
def find_instance_type_by_code(code)
|
100
|
-
results =
|
121
|
+
results = instance_types_interface.get({code: code})
|
101
122
|
if results['instanceTypes'].empty?
|
102
123
|
print_red_alert "Instance Type not found by code #{code}"
|
124
|
+
# return nil
|
103
125
|
exit 1
|
104
126
|
end
|
105
127
|
return results['instanceTypes'][0]
|
106
128
|
end
|
107
129
|
|
130
|
+
def find_instance_type_by_name(name)
|
131
|
+
results = instance_types_interface.get({name: name})
|
132
|
+
if results['instanceTypes'].empty?
|
133
|
+
print_red_alert "Instance Type not found by name #{name}"
|
134
|
+
# return nil
|
135
|
+
exit 1
|
136
|
+
end
|
137
|
+
return results['instanceTypes'][0]
|
138
|
+
end
|
139
|
+
|
140
|
+
def find_instance_by_name_or_id(val)
|
141
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
142
|
+
return find_instance_by_id(val)
|
143
|
+
else
|
144
|
+
return find_instance_by_name(val)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def find_instance_by_id(id)
|
149
|
+
begin
|
150
|
+
json_response = instances_interface.get(id.to_i)
|
151
|
+
return json_response['instance']
|
152
|
+
rescue RestClient::Exception => e
|
153
|
+
if e.response && e.response.code == 404
|
154
|
+
print_red_alert "Instance not found by id #{id}"
|
155
|
+
exit 1
|
156
|
+
else
|
157
|
+
raise e
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def find_instance_by_name(name)
|
163
|
+
json_results = instances_interface.get({name: name.to_s})
|
164
|
+
if json_results['instances'].empty?
|
165
|
+
print_red_alert "Instance not found by name #{name}"
|
166
|
+
exit 1
|
167
|
+
end
|
168
|
+
instance = json_results['instances'][0]
|
169
|
+
return instance
|
170
|
+
end
|
171
|
+
|
108
172
|
# prompts user for all the configuartion options for a particular instance
|
109
173
|
# returns payload of data for a new instance
|
110
174
|
def prompt_new_instance(options={})
|
111
175
|
|
112
176
|
# Group
|
113
177
|
group_id = nil
|
114
|
-
group =
|
178
|
+
group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
|
115
179
|
if group
|
116
180
|
group_id = group["id"]
|
117
181
|
else
|
118
182
|
# print_red_alert "Group not found or specified!"
|
119
183
|
# exit 1
|
120
|
-
group_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group', 'selectOptions' => get_available_groups(), 'required' => true, 'description' => 'Select Group.'}],options[:options]
|
121
|
-
group_id =
|
184
|
+
group_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group', 'selectOptions' => get_available_groups(), 'required' => true, 'description' => 'Select Group.'}],options[:options],api_client,{})
|
185
|
+
group_id = group_prompt['group']
|
122
186
|
end
|
123
|
-
|
124
187
|
|
125
188
|
# Cloud
|
126
189
|
cloud_id = nil
|
127
|
-
cloud =
|
190
|
+
cloud = options[:cloud] ? find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud]) : nil
|
128
191
|
if cloud
|
129
192
|
cloud_id = cloud["id"]
|
130
193
|
else
|
131
194
|
# print_red_alert "Cloud not specified!"
|
132
195
|
# exit 1
|
133
|
-
cloud_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'type' => 'select', 'fieldLabel' => 'Cloud', 'selectOptions' => get_available_clouds(group_id), 'required' => true, 'description' => 'Select Cloud.'}],options[:options]
|
196
|
+
cloud_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'type' => 'select', 'fieldLabel' => 'Cloud', 'selectOptions' => get_available_clouds(group_id), 'required' => true, 'description' => 'Select Cloud.'}],options[:options],api_client,{groupId: group_id})
|
134
197
|
cloud_id = cloud_prompt['cloud']
|
135
198
|
end
|
136
|
-
|
137
199
|
# Instance Type
|
138
200
|
instance_type_code = nil
|
139
201
|
if options[:instance_type_code]
|
140
202
|
instance_type_code = options[:instance_type_code]
|
141
203
|
else
|
142
|
-
instance_type_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Type', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Select Instance Type.'}],options[:options]
|
204
|
+
instance_type_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Type', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Select Instance Type.'}],options[:options],api_client,{groupId: group_id})
|
143
205
|
instance_type_code = instance_type_prompt['type']
|
144
206
|
end
|
145
207
|
instance_type = find_instance_type_by_code(instance_type_code)
|
@@ -178,12 +240,11 @@ module Morpheus::Cli::ProvisioningHelper
|
|
178
240
|
# Tags
|
179
241
|
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'tags', 'fieldLabel' => 'Tags', 'type' => 'text', 'required' => false}], options[:options])
|
180
242
|
payload[:instance][:tags] = v_prompt['tags'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['tags'].empty?
|
181
|
-
|
182
243
|
|
183
244
|
# Version and Layout
|
184
245
|
|
185
|
-
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]
|
186
|
-
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]
|
246
|
+
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']})
|
247
|
+
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']})
|
187
248
|
layout_id = layout_prompt['layout']
|
188
249
|
layout = instance_type['instanceTypeLayouts'].find{ |lt| lt['id'] == layout_id.to_i}
|
189
250
|
payload[:instance][:layout] = {id: layout['id']}
|
@@ -195,11 +256,11 @@ module Morpheus::Cli::ProvisioningHelper
|
|
195
256
|
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])
|
196
257
|
service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
|
197
258
|
# todo: pick one of these three, let's go with the last one...
|
198
|
-
payload[:servicePlan] = service_plan["id"] # pre-2.10 appliances
|
259
|
+
#payload[:servicePlan] = service_plan["id"] # pre-2.10 appliances
|
199
260
|
payload[:instance][:plan] = {id: service_plan["id"]}
|
200
261
|
|
201
262
|
# prompt for volumes
|
202
|
-
volumes = prompt_volumes(service_plan, options,
|
263
|
+
volumes = prompt_volumes(service_plan, options, api_client, {})
|
203
264
|
if !volumes.empty?
|
204
265
|
payload[:volumes] = volumes
|
205
266
|
end
|
@@ -207,22 +268,20 @@ module Morpheus::Cli::ProvisioningHelper
|
|
207
268
|
if layout["provisionType"] && layout["provisionType"]["id"] && layout["provisionType"]["hasNetworks"]
|
208
269
|
# prompt for network interfaces (if supported)
|
209
270
|
begin
|
210
|
-
network_interfaces = prompt_network_interfaces(cloud_id, layout["provisionType"]["id"], options
|
271
|
+
network_interfaces = prompt_network_interfaces(cloud_id, layout["provisionType"]["id"], options)
|
211
272
|
if !network_interfaces.empty?
|
212
273
|
payload[:networkInterfaces] = network_interfaces
|
213
274
|
end
|
214
275
|
rescue RestClient::Exception => e
|
215
276
|
print_yellow_warning "Unable to load network options. Proceeding..."
|
216
|
-
print_rest_exception(e, options) if Morpheus::Logging.
|
277
|
+
print_rest_exception(e, options) if Morpheus::Logging.debug?
|
217
278
|
end
|
218
279
|
end
|
219
|
-
|
220
|
-
|
221
280
|
type_payload = {}
|
222
281
|
if !layout['optionTypes'].nil? && !layout['optionTypes'].empty?
|
223
|
-
type_payload = Morpheus::Cli::OptionTypes.prompt(layout['optionTypes'],options[:options]
|
282
|
+
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']})
|
224
283
|
elsif !instance_type['optionTypes'].nil? && !instance_type['optionTypes'].empty?
|
225
|
-
type_payload = Morpheus::Cli::OptionTypes.prompt(instance_type['optionTypes'],options[:options]
|
284
|
+
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']})
|
226
285
|
end
|
227
286
|
if !type_payload['config'].nil?
|
228
287
|
payload.merge!(type_payload['config'])
|
@@ -239,7 +298,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
239
298
|
if !payload[:networkInterfaces].empty?
|
240
299
|
instance_type_option_types = reject_networking_option_types(instance_type_option_types)
|
241
300
|
end
|
242
|
-
provision_payload = Morpheus::Cli::OptionTypes.prompt(instance_type_option_types,options[:options]
|
301
|
+
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']})
|
243
302
|
end
|
244
303
|
|
245
304
|
payload[:config] = provision_payload['config'] || {}
|
@@ -247,6 +306,12 @@ module Morpheus::Cli::ProvisioningHelper
|
|
247
306
|
payload[:server] = provision_payload['server'] || {}
|
248
307
|
end
|
249
308
|
|
309
|
+
# prompt for environment variables
|
310
|
+
evars = prompt_evars(options)
|
311
|
+
if !evars.empty?
|
312
|
+
payload[:evars] = evars
|
313
|
+
end
|
314
|
+
|
250
315
|
return payload
|
251
316
|
end
|
252
317
|
|
@@ -327,7 +392,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
327
392
|
|
328
393
|
volume_label = 'root'
|
329
394
|
volume = {
|
330
|
-
'id' => -1,
|
395
|
+
'id' => -1,
|
331
396
|
'rootVolume' => true,
|
332
397
|
'name' => volume_label,
|
333
398
|
'size' => plan_size,
|
@@ -352,7 +417,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
352
417
|
end
|
353
418
|
else
|
354
419
|
# might need different logic here ? =o
|
355
|
-
volume['size'] = plan_size
|
420
|
+
volume['size'] = plan_size
|
356
421
|
volume['sizeId'] = nil #volume.delete('sizeId')
|
357
422
|
end
|
358
423
|
if !datastore_options.empty?
|
@@ -364,502 +429,514 @@ module Morpheus::Cli::ProvisioningHelper
|
|
364
429
|
|
365
430
|
if plan_info['addVolumes']
|
366
431
|
volume_index = 1
|
367
|
-
|
368
432
|
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
369
|
-
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?"))
|
370
|
-
|
433
|
+
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?", {:default => false}))
|
371
434
|
while add_another_volume do
|
372
|
-
|
373
|
-
#puts "Configure Data #{volume_index} Volume"
|
435
|
+
#puts "Configure Data #{volume_index} Volume"
|
374
436
|
|
375
|
-
|
437
|
+
field_context = "dataVolume#{volume_index}"
|
376
438
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
439
|
+
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])
|
440
|
+
storage_type_id = v_prompt[field_context]['storageType']
|
441
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
381
442
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
443
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
444
|
+
custom_size_options = []
|
445
|
+
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
446
|
+
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
447
|
+
if !opt.nil?
|
448
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
449
|
+
end
|
388
450
|
end
|
389
451
|
end
|
390
|
-
end
|
391
452
|
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
453
|
+
volume_label = (volume_index == 1 ? 'data' : "data #{volume_index}")
|
454
|
+
volume = {
|
455
|
+
'id' => -1,
|
456
|
+
'rootVolume' => false,
|
457
|
+
'name' => volume_label,
|
458
|
+
'size' => plan_size,
|
459
|
+
'sizeId' => nil,
|
460
|
+
'storageType' => storage_type_id,
|
461
|
+
'datastoreId' => nil
|
462
|
+
}
|
402
463
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
464
|
+
if plan_info['customizeVolume'] && storage_type['customLabel']
|
465
|
+
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])
|
466
|
+
volume['name'] = v_prompt[field_context]['name']
|
467
|
+
end
|
468
|
+
if plan_info['customizeVolume'] && storage_type['customSize']
|
469
|
+
if custom_size_options.empty?
|
470
|
+
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])
|
471
|
+
volume['size'] = v_prompt[field_context]['size']
|
472
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
473
|
+
else
|
474
|
+
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])
|
475
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
476
|
+
volume['size'] = nil #volume.delete('size')
|
477
|
+
end
|
412
478
|
else
|
413
|
-
|
414
|
-
volume['
|
415
|
-
volume['
|
479
|
+
# might need different logic here ? =o
|
480
|
+
volume['size'] = plan_size
|
481
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
416
482
|
end
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
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])
|
424
|
-
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
425
|
-
end
|
483
|
+
if !datastore_options.empty?
|
484
|
+
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])
|
485
|
+
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
486
|
+
end
|
487
|
+
|
488
|
+
volumes << volume
|
426
489
|
|
427
|
-
|
490
|
+
# todo: should maxDisk check consider the root volume too?
|
491
|
+
if plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
492
|
+
add_another_volume = false
|
493
|
+
else
|
494
|
+
volume_index += 1
|
495
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
496
|
+
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?", {:default => false}))
|
497
|
+
end
|
428
498
|
|
429
|
-
# todo: should maxDisk check consider the root volume too?
|
430
|
-
if plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
431
|
-
add_another_volume = false
|
432
|
-
else
|
433
|
-
volume_index += 1
|
434
|
-
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
435
|
-
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?"))
|
436
499
|
end
|
437
500
|
|
438
501
|
end
|
439
502
|
|
503
|
+
return volumes
|
440
504
|
end
|
441
505
|
|
442
|
-
return volumes
|
443
|
-
end
|
444
506
|
|
507
|
+
# This recreates the behavior of multi_disk.js
|
508
|
+
# returns array of volumes based on service plan options (plan_info)
|
509
|
+
def prompt_resize_volumes(current_volumes, plan_info, options={})
|
510
|
+
#puts "Configure Volumes:"
|
511
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
445
512
|
|
446
|
-
|
447
|
-
# returns array of volumes based on service plan options (plan_info)
|
448
|
-
def prompt_resize_volumes(current_volumes, plan_info, options={}, api_client=nil, api_params={})
|
449
|
-
#puts "Configure Volumes:"
|
450
|
-
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
513
|
+
current_root_volume = current_volumes[0]
|
451
514
|
|
452
|
-
|
515
|
+
volumes = []
|
453
516
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
|
459
|
-
end
|
517
|
+
plan_size = nil
|
518
|
+
if plan_info['maxStorage']
|
519
|
+
plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
|
520
|
+
end
|
460
521
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
522
|
+
root_storage_types = []
|
523
|
+
if plan_info['rootStorageTypes']
|
524
|
+
plan_info['rootStorageTypes'].each do |opt|
|
525
|
+
if !opt.nil?
|
526
|
+
root_storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
527
|
+
end
|
466
528
|
end
|
467
529
|
end
|
468
|
-
end
|
469
530
|
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
531
|
+
storage_types = []
|
532
|
+
if plan_info['storageTypes']
|
533
|
+
plan_info['storageTypes'].each do |opt|
|
534
|
+
if !opt.nil?
|
535
|
+
storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
536
|
+
end
|
475
537
|
end
|
476
538
|
end
|
477
|
-
end
|
478
539
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
540
|
+
datastore_options = []
|
541
|
+
if plan_info['supportsAutoDatastore']
|
542
|
+
if plan_info['autoOptions']
|
543
|
+
plan_info['autoOptions'].each do |opt|
|
544
|
+
if !opt.nil?
|
545
|
+
datastore_options << {'name' => opt['name'], 'value' => opt['id']}
|
546
|
+
end
|
485
547
|
end
|
486
548
|
end
|
487
549
|
end
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
550
|
+
if plan_info['datastores']
|
551
|
+
plan_info['datastores'].each do |k, v|
|
552
|
+
v.each do |opt|
|
553
|
+
if !opt.nil?
|
554
|
+
datastore_options << {'name' => "#{k}: #{opt['name']}", 'value' => opt['id']}
|
555
|
+
end
|
494
556
|
end
|
495
557
|
end
|
496
558
|
end
|
497
|
-
end
|
498
559
|
|
499
|
-
|
560
|
+
#puts "Configure Root Volume"
|
500
561
|
|
501
|
-
|
562
|
+
field_context = "rootVolume"
|
502
563
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
564
|
+
if root_storage_types.empty?
|
565
|
+
# this means there's no configuration, just send a single root volume to the server
|
566
|
+
storage_type_id = nil
|
567
|
+
storage_type = nil
|
568
|
+
else
|
569
|
+
#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])
|
570
|
+
#storage_type_id = v_prompt[field_context]['storageType']
|
571
|
+
storage_type_id = current_root_volume['type'] || current_root_volume['storageType']
|
572
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
573
|
+
end
|
513
574
|
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
575
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
576
|
+
root_custom_size_options = []
|
577
|
+
if plan_info['rootCustomSizeOptions'] && plan_info['rootCustomSizeOptions'][storage_type_id.to_s]
|
578
|
+
plan_info['rootCustomSizeOptions'][storage_type_id.to_s].each do |opt|
|
579
|
+
if !opt.nil?
|
580
|
+
root_custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
581
|
+
end
|
520
582
|
end
|
521
583
|
end
|
522
|
-
end
|
523
584
|
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
585
|
+
volume = {
|
586
|
+
'id' => current_root_volume['id'],
|
587
|
+
'rootVolume' => true,
|
588
|
+
'name' => current_root_volume['name'],
|
589
|
+
'size' => current_root_volume['size'] > plan_size ? current_root_volume['size'] : plan_size,
|
590
|
+
'sizeId' => nil,
|
591
|
+
'storageType' => storage_type_id,
|
592
|
+
'datastoreId' => current_root_volume['datastoreId']
|
593
|
+
}
|
533
594
|
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
595
|
+
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customLabel']
|
596
|
+
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])
|
597
|
+
volume['name'] = v_prompt[field_context]['name']
|
598
|
+
end
|
599
|
+
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
|
600
|
+
if root_custom_size_options.empty?
|
601
|
+
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])
|
602
|
+
volume['size'] = v_prompt[field_context]['size']
|
603
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
604
|
+
else
|
605
|
+
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])
|
606
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
607
|
+
volume['size'] = nil #volume.delete('size')
|
608
|
+
end
|
543
609
|
else
|
544
|
-
|
545
|
-
volume['
|
546
|
-
volume['
|
610
|
+
# might need different logic here ? =o
|
611
|
+
volume['size'] = plan_size
|
612
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
547
613
|
end
|
548
|
-
|
549
|
-
#
|
550
|
-
volume['
|
551
|
-
|
552
|
-
end
|
553
|
-
# if !datastore_options.empty?
|
554
|
-
# 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])
|
555
|
-
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
556
|
-
# end
|
614
|
+
# if !datastore_options.empty?
|
615
|
+
# 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])
|
616
|
+
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
617
|
+
# end
|
557
618
|
|
558
|
-
|
619
|
+
volumes << volume
|
559
620
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
if current_volume
|
621
|
+
# modify or delete existing data volumes
|
622
|
+
(1..(current_volumes.size-1)).each do |volume_index|
|
623
|
+
current_volume = current_volumes[volume_index]
|
624
|
+
if current_volume
|
565
625
|
|
566
|
-
|
626
|
+
field_context = "dataVolume#{volume_index}"
|
567
627
|
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
628
|
+
if no_prompt
|
629
|
+
volume_action = 'keep'
|
630
|
+
else
|
631
|
+
action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
|
632
|
+
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])
|
633
|
+
volume_action = v_prompt[field_context]['action']
|
634
|
+
end
|
575
635
|
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
636
|
+
if volume_action == 'delete'
|
637
|
+
# deleted volume is just excluded from post params
|
638
|
+
next
|
639
|
+
elsif volume_action == 'keep'
|
640
|
+
volume = {
|
641
|
+
'id' => current_volume['id'].to_i,
|
642
|
+
'rootVolume' => false,
|
643
|
+
'name' => current_volume['name'],
|
644
|
+
'size' => current_volume['size'] > plan_size ? current_volume['size'] : plan_size,
|
645
|
+
'sizeId' => nil,
|
646
|
+
'storageType' => (current_volume['type'] || current_volume['storageType']),
|
647
|
+
'datastoreId' => current_volume['datastoreId']
|
648
|
+
}
|
649
|
+
volumes << volume
|
650
|
+
else
|
651
|
+
# 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])
|
652
|
+
# storage_type_id = v_prompt[field_context]['storageType']
|
653
|
+
storage_type_id = current_volume['type'] || current_volume['storageType']
|
654
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
655
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
656
|
+
custom_size_options = []
|
657
|
+
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
658
|
+
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
659
|
+
if !opt.nil?
|
660
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
661
|
+
end
|
603
662
|
end
|
604
663
|
end
|
605
|
-
end
|
606
|
-
|
607
|
-
volume = {
|
608
|
-
'id' => current_volume['id'].to_i,
|
609
|
-
'rootVolume' => false,
|
610
|
-
'name' => current_volume['name'],
|
611
|
-
'size' => current_volume['size'] > plan_size ? current_volume['size'] : plan_size,
|
612
|
-
'sizeId' => nil,
|
613
|
-
'storageType' => (current_volume['type'] || current_volume['storageType']),
|
614
|
-
'datastoreId' => current_volume['datastoreId']
|
615
|
-
}
|
616
664
|
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
665
|
+
volume = {
|
666
|
+
'id' => current_volume['id'].to_i,
|
667
|
+
'rootVolume' => false,
|
668
|
+
'name' => current_volume['name'],
|
669
|
+
'size' => current_volume['size'] > plan_size ? current_volume['size'] : plan_size,
|
670
|
+
'sizeId' => nil,
|
671
|
+
'storageType' => (current_volume['type'] || current_volume['storageType']),
|
672
|
+
'datastoreId' => current_volume['datastoreId']
|
673
|
+
}
|
674
|
+
|
675
|
+
if plan_info['customizeVolume'] && storage_type['customLabel']
|
676
|
+
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])
|
677
|
+
volume['name'] = v_prompt[field_context]['name']
|
678
|
+
end
|
679
|
+
if plan_info['customizeVolume'] && storage_type['customSize']
|
680
|
+
if custom_size_options.empty?
|
681
|
+
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])
|
682
|
+
volume['size'] = v_prompt[field_context]['size']
|
683
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
684
|
+
else
|
685
|
+
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])
|
686
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
687
|
+
volume['size'] = nil #volume.delete('size')
|
688
|
+
end
|
626
689
|
else
|
627
|
-
|
628
|
-
volume['
|
629
|
-
volume['
|
690
|
+
# might need different logic here ? =o
|
691
|
+
volume['size'] = plan_size
|
692
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
630
693
|
end
|
631
|
-
|
632
|
-
#
|
633
|
-
volume['
|
634
|
-
|
635
|
-
end
|
636
|
-
# if !datastore_options.empty?
|
637
|
-
# 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])
|
638
|
-
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
639
|
-
# end
|
694
|
+
# if !datastore_options.empty?
|
695
|
+
# 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])
|
696
|
+
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
697
|
+
# end
|
640
698
|
|
641
|
-
|
699
|
+
volumes << volume
|
642
700
|
|
643
|
-
|
701
|
+
end
|
644
702
|
|
703
|
+
end
|
645
704
|
end
|
646
|
-
end
|
647
705
|
|
648
706
|
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
while add_another_volume do
|
656
|
-
|
657
|
-
#puts "Configure Data #{volume_index} Volume"
|
707
|
+
if plan_info['addVolumes']
|
708
|
+
volume_index = current_volumes.size
|
709
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
710
|
+
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?"))
|
711
|
+
while add_another_volume do
|
712
|
+
#puts "Configure Data #{volume_index} Volume"
|
658
713
|
|
659
|
-
|
714
|
+
field_context = "dataVolume#{volume_index}"
|
660
715
|
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
716
|
+
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])
|
717
|
+
storage_type_id = v_prompt[field_context]['storageType']
|
718
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
665
719
|
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
720
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
721
|
+
custom_size_options = []
|
722
|
+
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
723
|
+
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
724
|
+
if !opt.nil?
|
725
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
726
|
+
end
|
727
|
+
end
|
672
728
|
end
|
673
|
-
end
|
674
|
-
end
|
675
729
|
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
730
|
+
volume_label = (volume_index == 1 ? 'data' : "data #{volume_index}")
|
731
|
+
volume = {
|
732
|
+
'id' => -1,
|
733
|
+
'rootVolume' => false,
|
734
|
+
'name' => volume_label,
|
735
|
+
'size' => plan_size,
|
736
|
+
'sizeId' => nil,
|
737
|
+
'storageType' => storage_type_id,
|
738
|
+
'datastoreId' => nil
|
739
|
+
}
|
740
|
+
|
741
|
+
if plan_info['customizeVolume'] && storage_type['customLabel']
|
742
|
+
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])
|
743
|
+
volume['name'] = v_prompt[field_context]['name']
|
744
|
+
end
|
745
|
+
if plan_info['customizeVolume'] && storage_type['customSize']
|
746
|
+
if custom_size_options.empty?
|
747
|
+
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])
|
748
|
+
volume['size'] = v_prompt[field_context]['size']
|
749
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
750
|
+
else
|
751
|
+
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])
|
752
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
753
|
+
volume['size'] = nil #volume.delete('size')
|
754
|
+
end
|
755
|
+
else
|
756
|
+
# might need different logic here ? =o
|
757
|
+
volume['size'] = plan_size
|
758
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
759
|
+
end
|
760
|
+
if !datastore_options.empty?
|
761
|
+
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])
|
762
|
+
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
763
|
+
end
|
686
764
|
|
687
|
-
|
688
|
-
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])
|
689
|
-
volume['name'] = v_prompt[field_context]['name']
|
690
|
-
end
|
691
|
-
if plan_info['customizeVolume'] && storage_type['customSize']
|
692
|
-
if custom_size_options.empty?
|
693
|
-
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])
|
694
|
-
volume['size'] = v_prompt[field_context]['size']
|
695
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
696
|
-
else
|
697
|
-
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])
|
698
|
-
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
699
|
-
volume['size'] = nil #volume.delete('size')
|
700
|
-
end
|
701
|
-
else
|
702
|
-
# might need different logic here ? =o
|
703
|
-
volume['size'] = plan_size
|
704
|
-
volume['sizeId'] = nil #volume.delete('sizeId')
|
705
|
-
end
|
706
|
-
if !datastore_options.empty?
|
707
|
-
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])
|
708
|
-
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
709
|
-
end
|
765
|
+
volumes << volume
|
710
766
|
|
711
|
-
|
767
|
+
# todo: should maxDisk check consider the root volume too?
|
768
|
+
if plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
769
|
+
add_another_volume = false
|
770
|
+
else
|
771
|
+
volume_index += 1
|
772
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
773
|
+
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?"))
|
774
|
+
end
|
775
|
+
|
776
|
+
end
|
712
777
|
|
713
|
-
# todo: should maxDisk check consider the root volume too?
|
714
|
-
if plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
715
|
-
add_another_volume = false
|
716
|
-
else
|
717
|
-
volume_index += 1
|
718
|
-
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
719
|
-
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another data volume?"))
|
720
778
|
end
|
721
779
|
|
780
|
+
return volumes
|
722
781
|
end
|
723
782
|
|
724
|
-
end
|
725
|
-
|
726
|
-
return volumes
|
727
|
-
end
|
728
|
-
|
729
|
-
|
730
|
-
# This recreates the behavior of multi_networks.js
|
731
|
-
# This is used by both `instances add` and `hosts add`
|
732
|
-
# returns array of networkInterfaces based on provision type and cloud settings
|
733
|
-
def prompt_network_interfaces(zone_id, provision_type_id, options={}, api_client=nil)
|
734
|
-
#puts "Configure Networks:"
|
735
|
-
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
736
|
-
|
737
|
-
network_interfaces = []
|
738
|
-
|
739
|
-
zone_network_options_json = api_client.options.options_for_source('zoneNetworkOptions', {zoneId: zone_id, provisionTypeId: provision_type_id})
|
740
|
-
# puts "zoneNetworkOptions JSON"
|
741
|
-
# puts JSON.pretty_generate(zone_network_options_json)
|
742
|
-
zone_network_data = zone_network_options_json['data'] || {}
|
743
|
-
networks = zone_network_data['networks']
|
744
|
-
network_interface_types = (zone_network_data['networkTypes'] || []).sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
|
745
|
-
enable_network_type_selection = (zone_network_data['enableNetworkTypeSelection'] == 'on' || zone_network_data['enableNetworkTypeSelection'] == true)
|
746
|
-
has_networks = zone_network_data["hasNetworks"] == true
|
747
|
-
max_networks = zone_network_data["maxNetworks"] ? zone_network_data["maxNetworks"].to_i : nil
|
748
783
|
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
784
|
+
# This recreates the behavior of multi_networks.js
|
785
|
+
# This is used by both `instances add` and `hosts add`
|
786
|
+
# returns array of networkInterfaces based on provision type and cloud settings
|
787
|
+
def prompt_network_interfaces(zone_id, provision_type_id, options={})
|
788
|
+
#puts "Configure Networks:"
|
789
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
790
|
+
network_interfaces = []
|
791
|
+
|
792
|
+
zone_network_options_json = api_client.options.options_for_source('zoneNetworkOptions', {zoneId: zone_id, provisionTypeId: provision_type_id})
|
793
|
+
# puts "zoneNetworkOptions JSON"
|
794
|
+
# puts JSON.pretty_generate(zone_network_options_json)
|
795
|
+
zone_network_data = zone_network_options_json['data'] || {}
|
796
|
+
networks = zone_network_data['networks']
|
797
|
+
network_interface_types = (zone_network_data['networkTypes'] || []).sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
|
798
|
+
enable_network_type_selection = (zone_network_data['enableNetworkTypeSelection'] == 'on' || zone_network_data['enableNetworkTypeSelection'] == true)
|
799
|
+
has_networks = zone_network_data["hasNetworks"] == true
|
800
|
+
max_networks = zone_network_data["maxNetworks"] ? zone_network_data["maxNetworks"].to_i : nil
|
801
|
+
|
802
|
+
# skip unless provision type supports networks
|
803
|
+
if !has_networks
|
804
|
+
return nil
|
805
|
+
end
|
765
806
|
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
end
|
771
|
-
end
|
807
|
+
# no networks available, shouldn't happen
|
808
|
+
if networks.empty?
|
809
|
+
return network_interfaces
|
810
|
+
end
|
772
811
|
|
812
|
+
network_options = []
|
813
|
+
networks.each do |opt|
|
814
|
+
if !opt.nil?
|
815
|
+
network_options << {'name' => opt['name'], 'value' => opt['id']}
|
816
|
+
end
|
817
|
+
end
|
773
818
|
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
while add_another_interface do
|
781
|
-
|
782
|
-
# if !no_prompt
|
783
|
-
# if interface_index == 1
|
784
|
-
# puts "Configure Network Interface"
|
785
|
-
# else
|
786
|
-
# puts "Configure Network Interface #{interface_index}"
|
787
|
-
# end
|
788
|
-
# end
|
819
|
+
network_interface_type_options = []
|
820
|
+
network_interface_types.each do |opt|
|
821
|
+
if !opt.nil?
|
822
|
+
network_interface_type_options << {'name' => opt['name'], 'value' => opt['id']}
|
823
|
+
end
|
824
|
+
end
|
789
825
|
|
790
|
-
field_context = interface_index == 1 ? "networkInterface" : "networkInterface#{interface_index}"
|
791
|
-
|
792
|
-
network_interface = {}
|
793
826
|
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
827
|
+
interface_index = 1
|
828
|
+
add_another_interface = true
|
829
|
+
while add_another_interface do
|
830
|
+
# if !no_prompt
|
831
|
+
# if interface_index == 1
|
832
|
+
# puts "Configure Network Interface"
|
833
|
+
# else
|
834
|
+
# puts "Configure Network Interface #{interface_index}"
|
835
|
+
# end
|
836
|
+
# end
|
837
|
+
|
838
|
+
field_context = interface_index == 1 ? "networkInterface" : "networkInterface#{interface_index}"
|
839
|
+
network_interface = {}
|
840
|
+
|
841
|
+
# choose network
|
842
|
+
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])
|
843
|
+
network_interface['network'] = {}
|
844
|
+
network_interface['network']['id'] = v_prompt[field_context]['networkId'].to_i
|
845
|
+
selected_network = networks.find {|it| it["id"] == network_interface['network']['id'] }
|
846
|
+
|
847
|
+
# if !selected_network
|
848
|
+
# print_red_alert "Network not found by id #{network_interface['network']['id']}!"
|
849
|
+
# exit 1
|
850
|
+
# end
|
851
|
+
|
852
|
+
# choose network interface type
|
853
|
+
if enable_network_type_selection && !network_interface_type_options.empty?
|
854
|
+
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])
|
855
|
+
network_interface['networkInterfaceTypeId'] = v_prompt[field_context]['networkInterfaceTypeId'].to_i
|
856
|
+
end
|
798
857
|
|
799
|
-
|
858
|
+
# choose IP unless network has a pool configured
|
859
|
+
if selected_network['pool']
|
860
|
+
puts "IP Address: Using pool '#{selected_network['pool']['name']}'" if !no_prompt
|
861
|
+
elsif selected_network['dhcpServer']
|
862
|
+
puts "IP Address: Using DHCP" if !no_prompt
|
863
|
+
else
|
864
|
+
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])
|
865
|
+
network_interface['ipAddress'] = v_prompt[field_context]['ipAddress']
|
866
|
+
end
|
867
|
+
network_interfaces << network_interface
|
868
|
+
interface_index += 1
|
869
|
+
has_another_interface = options[:options] && options[:options]["networkInterface#{interface_index}"]
|
870
|
+
add_another_interface = has_another_interface || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another network interface?", {:default => false}))
|
871
|
+
if max_networks && network_interfaces.size >= max_networks
|
872
|
+
add_another_interface = false
|
873
|
+
end
|
800
874
|
|
801
|
-
|
802
|
-
if enable_network_type_selection && !network_interface_type_options.empty?
|
803
|
-
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])
|
804
|
-
network_interface['networkInterfaceTypeId'] = v_prompt[field_context]['networkInterfaceTypeId'].to_i
|
805
|
-
end
|
875
|
+
end
|
806
876
|
|
807
|
-
|
808
|
-
if selected_network['pool']
|
809
|
-
puts "IP Address: Using pool '#{selected_network['pool']['name']}'" if !no_prompt
|
810
|
-
elsif selected_network['dhcpServer']
|
811
|
-
puts "IP Address: Using DHCP" if !no_prompt
|
812
|
-
else
|
813
|
-
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])
|
814
|
-
network_interface['ipAddress'] = v_prompt[field_context]['ipAddress']
|
815
|
-
end
|
816
|
-
|
817
|
-
network_interfaces << network_interface
|
818
|
-
|
819
|
-
interface_index += 1
|
820
|
-
has_another_interface = options[:options] && options[:options]["networkInterface#{interface_index}"]
|
821
|
-
add_another_interface = has_another_interface || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another network interface?"))
|
822
|
-
if max_networks && network_interfaces.size >= max_networks
|
823
|
-
add_another_interface = false
|
824
|
-
end
|
877
|
+
return network_interfaces
|
825
878
|
|
826
|
-
|
879
|
+
end
|
827
880
|
|
828
|
-
|
881
|
+
# Prompts user for environment variables for new instance
|
882
|
+
# returns array of evar objects {id: null, name: "VAR", value: "somevalue"}
|
883
|
+
def prompt_evars(options={})
|
884
|
+
#puts "Configure Environment Variables:"
|
885
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
886
|
+
evars = []
|
887
|
+
evar_index = 0
|
888
|
+
has_another_evar = options[:options] && options[:options]["evar#{evar_index}"]
|
889
|
+
add_another_evar = has_another_evar || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add an environment variable?", {default: false}))
|
890
|
+
while add_another_evar do
|
891
|
+
field_context = "evar#{evar_index}"
|
892
|
+
evar = {}
|
893
|
+
evar['id'] = nil
|
894
|
+
evar_label = evar_index == 0 ? "ENV" : "ENV [#{evar_index+1}]"
|
895
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{evar_label} Name", 'required' => true, 'description' => 'Environment Variable Name.', 'defaultValue' => evar['name']}], options[:options])
|
896
|
+
evar['name'] = v_prompt[field_context]['name']
|
897
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'value', 'type' => 'text', 'fieldLabel' => "#{evar_label} Value", 'required' => true, 'description' => 'Environment Variable Value', 'defaultValue' => evar['value']}], options[:options])
|
898
|
+
evar['value'] = v_prompt[field_context]['value']
|
899
|
+
evars << evar
|
900
|
+
evar_index += 1
|
901
|
+
has_another_evar = options[:options] && options[:options]["evar#{evar_index}"]
|
902
|
+
add_another_evar = has_another_evar || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another environment variable?", {default: false}))
|
903
|
+
end
|
829
904
|
|
830
|
-
|
905
|
+
return evars
|
906
|
+
end
|
831
907
|
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
908
|
+
# reject old volume option types
|
909
|
+
# these will eventually get removed from the associated optionTypes
|
910
|
+
def reject_volume_option_types(option_types)
|
911
|
+
option_types.reject {|opt|
|
912
|
+
['osDiskSize', 'osDiskType',
|
913
|
+
'diskSize', 'diskType',
|
914
|
+
'datastoreId', 'storagePodId'
|
915
|
+
].include?(opt['fieldName'])
|
916
|
+
}
|
917
|
+
end
|
842
918
|
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
919
|
+
# reject old networking option types
|
920
|
+
# these will eventually get removed from the associated optionTypes
|
921
|
+
def reject_networking_option_types(option_types)
|
922
|
+
option_types.reject {|opt|
|
923
|
+
['networkId', 'networkType', 'ipAddress', 'netmask', 'gateway', 'nameservers',
|
924
|
+
'vmwareNetworkType', 'vmwareIpAddress', 'vmwareNetmask', 'vmwareGateway', 'vmwareNameservers',
|
925
|
+
'subnetId'
|
926
|
+
].include?(opt['fieldName'])
|
927
|
+
}
|
928
|
+
end
|
852
929
|
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
930
|
+
# reject old option types that now come from the selected service plan
|
931
|
+
# these will eventually get removed from the associated optionTypes
|
932
|
+
def reject_service_plan_option_types(option_types)
|
933
|
+
option_types.reject {|opt|
|
934
|
+
['cpuCount', 'memorySize', 'memory'].include?(opt['fieldName'])
|
935
|
+
}
|
936
|
+
end
|
860
937
|
|
861
|
-
|
862
|
-
|
863
|
-
|
938
|
+
def instance_context_options
|
939
|
+
[{'name' => 'Dev', 'value' => 'dev'}, {'name' => 'Test', 'value' => 'qa'}, {'name' => 'Staging', 'value' => 'staging'}, {'name' => 'Production', 'value' => 'production'}]
|
940
|
+
end
|
864
941
|
|
865
|
-
end
|
942
|
+
end
|