morpheus-cli 2.10.0 → 2.10.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|