morpheus-cli 4.2.6 → 4.2.7
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/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +4 -0
- data/lib/morpheus/api/clouds_interface.rb +14 -0
- data/lib/morpheus/api/guidance_interface.rb +47 -0
- data/lib/morpheus/api/users_interface.rb +7 -0
- data/lib/morpheus/cli.rb +1 -0
- data/lib/morpheus/cli/account_groups_command.rb +1 -1
- data/lib/morpheus/cli/approvals_command.rb +2 -2
- data/lib/morpheus/cli/apps.rb +26 -30
- data/lib/morpheus/cli/blueprints_command.rb +1 -1
- data/lib/morpheus/cli/budgets_command.rb +2 -2
- data/lib/morpheus/cli/change_password_command.rb +0 -1
- data/lib/morpheus/cli/cli_command.rb +19 -9
- data/lib/morpheus/cli/clouds.rb +107 -10
- data/lib/morpheus/cli/clusters.rb +12 -12
- data/lib/morpheus/cli/commands/standard/curl_command.rb +7 -0
- data/lib/morpheus/cli/deployments.rb +2 -2
- data/lib/morpheus/cli/environments_command.rb +1 -1
- data/lib/morpheus/cli/execution_request_command.rb +1 -1
- data/lib/morpheus/cli/groups.rb +1 -1
- data/lib/morpheus/cli/guidance_command.rb +529 -0
- data/lib/morpheus/cli/hosts.rb +2 -10
- data/lib/morpheus/cli/instances.rb +31 -13
- data/lib/morpheus/cli/integrations_command.rb +1 -1
- data/lib/morpheus/cli/jobs_command.rb +2 -2
- data/lib/morpheus/cli/library_container_types_command.rb +4 -4
- data/lib/morpheus/cli/library_instance_types_command.rb +3 -3
- data/lib/morpheus/cli/library_spec_templates_command.rb +1 -1
- data/lib/morpheus/cli/load_balancers.rb +2 -2
- data/lib/morpheus/cli/mixins/print_helper.rb +43 -3
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +251 -165
- data/lib/morpheus/cli/network_routers_command.rb +1 -1
- data/lib/morpheus/cli/price_sets_command.rb +2 -2
- data/lib/morpheus/cli/provisioning_licenses_command.rb +1 -1
- data/lib/morpheus/cli/remote.rb +6 -1
- data/lib/morpheus/cli/reports_command.rb +1 -1
- data/lib/morpheus/cli/security_group_rules.rb +1 -1
- data/lib/morpheus/cli/security_groups.rb +13 -5
- data/lib/morpheus/cli/service_plans_command.rb +2 -2
- data/lib/morpheus/cli/user_groups_command.rb +2 -6
- data/lib/morpheus/cli/user_settings_command.rb +31 -5
- data/lib/morpheus/cli/user_sources_command.rb +3 -3
- data/lib/morpheus/cli/users.rb +117 -90
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +2 -2
- data/lib/morpheus/cli/whitelabel_settings_command.rb +95 -15
- data/lib/morpheus/cli/wiki_command.rb +2 -2
- data/lib/morpheus/cli/workflows.rb +2 -3
- data/lib/morpheus/formatters.rb +14 -5
- metadata +4 -2
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -203,7 +203,7 @@ class Morpheus::Cli::Hosts
|
|
203
203
|
subtitles += parse_list_subtitles(options)
|
204
204
|
print_h1 title, subtitles, options
|
205
205
|
if servers.empty?
|
206
|
-
print
|
206
|
+
print cyan,"No hosts found.",reset,"\n"
|
207
207
|
else
|
208
208
|
# print_servers_table(servers)
|
209
209
|
# server returns stats in a separate key stats => {"id" => {} }
|
@@ -762,14 +762,6 @@ class Morpheus::Cli::Hosts
|
|
762
762
|
})
|
763
763
|
|
764
764
|
option_type_list = server_type['optionTypes']
|
765
|
-
# remove volume options if volumes were configured
|
766
|
-
if !payload['volumes'].empty?
|
767
|
-
option_type_list = reject_volume_option_types(option_type_list)
|
768
|
-
end
|
769
|
-
# remove networkId option if networks were configured above
|
770
|
-
if !payload['networkInterfaces'].empty?
|
771
|
-
option_type_list = reject_networking_option_types(option_type_list)
|
772
|
-
end
|
773
765
|
|
774
766
|
# remove cpu and memory option types, which now come from the plan
|
775
767
|
option_type_list = reject_service_plan_option_types(option_type_list)
|
@@ -1466,7 +1458,7 @@ class Morpheus::Cli::Hosts
|
|
1466
1458
|
else
|
1467
1459
|
print_h1 "Morpheus Server Types - Cloud: #{zone['name']}", [], options
|
1468
1460
|
if cloud_server_types.nil? || cloud_server_types.empty?
|
1469
|
-
print
|
1461
|
+
print cyan,"No server types found for the selected cloud",reset,"\n"
|
1470
1462
|
else
|
1471
1463
|
cloud_server_types.each do |server_type|
|
1472
1464
|
print cyan, "[#{server_type['code']}]".ljust(20), " - ", "#{server_type['name']}", "\n"
|
@@ -158,7 +158,7 @@ class Morpheus::Cli::Instances
|
|
158
158
|
subtitles += parse_list_subtitles(options)
|
159
159
|
print_h1 title, subtitles, options
|
160
160
|
if instances.empty?
|
161
|
-
print
|
161
|
+
print cyan,"No instances found.",reset,"\n"
|
162
162
|
else
|
163
163
|
# print_instances_table(instances)
|
164
164
|
# server returns stats in a separate key stats => {"id" => {} }
|
@@ -208,10 +208,11 @@ class Morpheus::Cli::Instances
|
|
208
208
|
:type, :version, :environment,
|
209
209
|
{:user => {:display_name => "CREATED BY", :max_width => 20}},
|
210
210
|
:nodes, {:connection => {:max_width => 30}}, :status, :cpu, :memory, :storage]
|
211
|
-
# custom pretty table columns ...
|
212
|
-
|
213
|
-
|
214
|
-
|
211
|
+
# custom pretty table columns ... this is handled in as_pretty_table now(),
|
212
|
+
# todo: remove all these.. and try to always pass rows as the json data itself..
|
213
|
+
# if options[:include_fields]
|
214
|
+
# columns = options[:include_fields]
|
215
|
+
# end
|
215
216
|
print cyan
|
216
217
|
print as_pretty_table(rows, columns, options)
|
217
218
|
print reset
|
@@ -319,6 +320,18 @@ class Morpheus::Cli::Instances
|
|
319
320
|
opts.on("--environment ENV", String, "Environment code") do |val|
|
320
321
|
options[:environment] = val.to_s
|
321
322
|
end
|
323
|
+
opts.on('--metadata LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
|
324
|
+
options[:metadata] = val
|
325
|
+
end
|
326
|
+
opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
327
|
+
#options[:tags] = val
|
328
|
+
options[:tags] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
329
|
+
end
|
330
|
+
opts.on('--tags LIST', String, "Tags") do |val|
|
331
|
+
#options[:tags] = val
|
332
|
+
options[:tags] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
333
|
+
end
|
334
|
+
opts.add_hidden_option('--tags')
|
322
335
|
opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
|
323
336
|
options[:copies] = val.to_i
|
324
337
|
end
|
@@ -361,7 +374,7 @@ class Morpheus::Cli::Instances
|
|
361
374
|
opts.on("--create-backup [on|off]", String, "Automation: Create Backups.") do |val|
|
362
375
|
options[:create_backup] = ['on','true','1',''].include?(val.to_s.downcase) ? 'on' : 'off'
|
363
376
|
end
|
364
|
-
opts.on("--security-groups LIST",
|
377
|
+
opts.on("--security-groups LIST", String, "Security Groups, comma sepearated list of security group IDs") do |val|
|
365
378
|
options[:security_groups] = val.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
|
366
379
|
end
|
367
380
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
@@ -490,13 +503,18 @@ class Morpheus::Cli::Instances
|
|
490
503
|
opts.on('--group GROUP', String, "Group Name or ID") do |val|
|
491
504
|
options[:group] = val
|
492
505
|
end
|
493
|
-
opts.on('--metadata LIST', String, "Metadata in the format 'name:value, name:value'") do |val|
|
506
|
+
opts.on('--metadata LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
|
494
507
|
options[:metadata] = val
|
495
508
|
end
|
509
|
+
opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
510
|
+
#params['tags'] = val
|
511
|
+
params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
512
|
+
end
|
496
513
|
opts.on('--tags LIST', String, "Tags") do |val|
|
497
|
-
params['tags'] = val
|
498
|
-
|
514
|
+
#params['tags'] = val
|
515
|
+
params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
499
516
|
end
|
517
|
+
opts.add_hidden_option('--tags')
|
500
518
|
opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
|
501
519
|
params['powerScheduleType'] = val == "null" ? nil : val
|
502
520
|
end
|
@@ -1286,7 +1304,7 @@ class Morpheus::Cli::Instances
|
|
1286
1304
|
"Version" => lambda {|it| it['instanceVersion'] },
|
1287
1305
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
1288
1306
|
"Environment" => 'instanceContext',
|
1289
|
-
"
|
1307
|
+
"Labels" => lambda {|it| it['tags'] ? it['tags'].join(',') : '' },
|
1290
1308
|
"Metadata" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
1291
1309
|
"Power Schedule" => lambda {|it| (it['powerSchedule'] && it['powerSchedule']['type']) ? it['powerSchedule']['type']['name'] : '' },
|
1292
1310
|
"Created By" => lambda {|it| it['createdBy'] ? (it['createdBy']['username'] || it['createdBy']['id']) : '' },
|
@@ -1399,7 +1417,7 @@ class Morpheus::Cli::Instances
|
|
1399
1417
|
if options[:include_scaling]
|
1400
1418
|
print_h2 "Instance Scaling", options
|
1401
1419
|
if instance_threshold.nil? || instance_threshold.empty?
|
1402
|
-
print
|
1420
|
+
print cyan,"No scaling settings applied to this instance.",reset,"\n"
|
1403
1421
|
else
|
1404
1422
|
print cyan
|
1405
1423
|
print_instance_threshold_description_list(instance_threshold)
|
@@ -1476,7 +1494,7 @@ class Morpheus::Cli::Instances
|
|
1476
1494
|
title = "Instance Containers: #{instance['name']} (#{instance['instanceType']['name']})"
|
1477
1495
|
print_h1 title, [], options
|
1478
1496
|
if containers.empty?
|
1479
|
-
print
|
1497
|
+
print cyan,"No containers found for instance.",reset,"\n"
|
1480
1498
|
else
|
1481
1499
|
|
1482
1500
|
rows = containers.collect {|container|
|
@@ -3008,7 +3026,7 @@ class Morpheus::Cli::Instances
|
|
3008
3026
|
title = "Instance Scaling: [#{instance['id']}] #{instance['name']} (#{instance['instanceType']['name']})"
|
3009
3027
|
print_h1 title, [], options
|
3010
3028
|
if instance_threshold.empty?
|
3011
|
-
print
|
3029
|
+
print cyan,"No scaling settings applied to this instance.",reset,"\n"
|
3012
3030
|
else
|
3013
3031
|
# print_h1 "Threshold Settings", [], options
|
3014
3032
|
print cyan
|
@@ -53,7 +53,7 @@ class Morpheus::Cli::IntegrationsCommand
|
|
53
53
|
integrations = json_response['integrations']
|
54
54
|
|
55
55
|
if integrations.empty?
|
56
|
-
print
|
56
|
+
print cyan,"No integrations found.",reset,"\n"
|
57
57
|
else
|
58
58
|
rows = integrations.collect do |it|
|
59
59
|
{
|
@@ -79,7 +79,7 @@ class Morpheus::Cli::JobsCommand
|
|
79
79
|
jobs = json_response['jobs']
|
80
80
|
|
81
81
|
if jobs.empty?
|
82
|
-
print
|
82
|
+
print cyan,"No jobs found.",reset,"\n"
|
83
83
|
else
|
84
84
|
rows = jobs.collect do |job|
|
85
85
|
{
|
@@ -944,7 +944,7 @@ class Morpheus::Cli::JobsCommand
|
|
944
944
|
|
945
945
|
def print_job_executions(execs, options={})
|
946
946
|
if execs.empty?
|
947
|
-
print
|
947
|
+
print cyan,"No job executions found.",reset,"\n"
|
948
948
|
else
|
949
949
|
rows = execs.collect do |ex|
|
950
950
|
{
|
@@ -189,7 +189,7 @@ class Morpheus::Cli::LibraryContainerTypesCommand
|
|
189
189
|
]
|
190
190
|
print as_pretty_table(evars, evar_columns)
|
191
191
|
else
|
192
|
-
# print
|
192
|
+
# print cyan,"No environment variables found for this node type.","\n",reset
|
193
193
|
end
|
194
194
|
|
195
195
|
exposed_ports = container_type['containerPorts']
|
@@ -203,7 +203,7 @@ class Morpheus::Cli::LibraryContainerTypesCommand
|
|
203
203
|
]
|
204
204
|
print as_pretty_table(exposed_ports, columns)
|
205
205
|
else
|
206
|
-
# print
|
206
|
+
# print cyan,"No exposed ports found for this node type.","\n",reset
|
207
207
|
end
|
208
208
|
|
209
209
|
container_scripts = container_type['containerScripts'] || container_type['scripts']
|
@@ -215,7 +215,7 @@ class Morpheus::Cli::LibraryContainerTypesCommand
|
|
215
215
|
]
|
216
216
|
print as_pretty_table(container_scripts, columns)
|
217
217
|
else
|
218
|
-
# print
|
218
|
+
# print cyan,"No scripts found for this node type.","\n",reset
|
219
219
|
end
|
220
220
|
|
221
221
|
container_file_templates = container_type['containerTemplates'] || container_type['templates']
|
@@ -227,7 +227,7 @@ class Morpheus::Cli::LibraryContainerTypesCommand
|
|
227
227
|
]
|
228
228
|
print as_pretty_table(container_file_templates, columns)
|
229
229
|
else
|
230
|
-
# print
|
230
|
+
# print cyan,"No scripts found for this node type.","\n",reset
|
231
231
|
end
|
232
232
|
|
233
233
|
print reset,"\n"
|
@@ -178,7 +178,7 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
|
|
178
178
|
]
|
179
179
|
print as_pretty_table(instance_type_option_types, columns)
|
180
180
|
else
|
181
|
-
# print
|
181
|
+
# print cyan,"No option types found for this layout.","\n",reset
|
182
182
|
end
|
183
183
|
|
184
184
|
instance_type_evars = instance_type['environmentVariables']
|
@@ -193,7 +193,7 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
|
|
193
193
|
]
|
194
194
|
print as_pretty_table(instance_type_evars, evar_columns)
|
195
195
|
else
|
196
|
-
# print
|
196
|
+
# print cyan,"No environment variables found for this instance type.","\n",reset
|
197
197
|
end
|
198
198
|
|
199
199
|
print_h2 "Layouts"
|
@@ -229,7 +229,7 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
|
|
229
229
|
]
|
230
230
|
print as_pretty_table(instance_type_layouts, layout_columns)
|
231
231
|
else
|
232
|
-
print
|
232
|
+
print cyan,"No layouts found for this instance type.","\n",reset
|
233
233
|
end
|
234
234
|
|
235
235
|
print reset,"\n"
|
@@ -56,7 +56,7 @@ class Morpheus::Cli::LoadBalancers
|
|
56
56
|
lbs = json_response['loadBalancers']
|
57
57
|
print_h1 "Morpheus Load Balancers"
|
58
58
|
if lbs.empty?
|
59
|
-
print
|
59
|
+
print cyan,"No load balancers found.",reset,"\n"
|
60
60
|
else
|
61
61
|
columns = [
|
62
62
|
{"ID" => 'id'},
|
@@ -243,7 +243,7 @@ class Morpheus::Cli::LoadBalancers
|
|
243
243
|
lb_types = json_response['loadBalancerTypes']
|
244
244
|
print_h1 "Morpheus Load Balancer Types"
|
245
245
|
if lb_types.nil? || lb_types.empty?
|
246
|
-
print
|
246
|
+
print cyan,"No load balancer types found.",reset,"\n"
|
247
247
|
else
|
248
248
|
print cyan
|
249
249
|
lb_table_data = lb_types.collect do |lb_type|
|
@@ -538,7 +538,7 @@ module Morpheus::Cli::PrintHelper
|
|
538
538
|
value = value.to_s
|
539
539
|
if do_wrap && value && Morpheus::Cli::PrintHelper.terminal_width
|
540
540
|
value_width = Morpheus::Cli::PrintHelper.terminal_width - label_width
|
541
|
-
if value_width > 0 && value.to_s.size > value_width
|
541
|
+
if value_width > 0 && value.gsub(/\e\[(\d+)m/, '').to_s.size > value_width
|
542
542
|
wrap_indent = label_width + 1 # plus 1 needs to go away
|
543
543
|
value = wrap(value, value_width, wrap_indent)
|
544
544
|
end
|
@@ -628,6 +628,44 @@ module Morpheus::Cli::PrintHelper
|
|
628
628
|
#
|
629
629
|
def as_pretty_table(data, columns, options={})
|
630
630
|
data = [data].flatten
|
631
|
+
|
632
|
+
# support --fields x,y,z and --all-fields or --fields all
|
633
|
+
all_fields = data.first ? data.first.keys : []
|
634
|
+
|
635
|
+
if options[:include_fields]
|
636
|
+
if (options[:include_fields].is_a?(Array) && options[:include_fields].size == 1 && options[:include_fields][0] == 'all') || options[:include_fields] == 'all'
|
637
|
+
columns = all_fields
|
638
|
+
else
|
639
|
+
# so let's use the passed in column definitions instead of the raw data properties
|
640
|
+
# columns = options[:include_fields]
|
641
|
+
new_columns = []
|
642
|
+
options[:include_fields].each do |f|
|
643
|
+
matching_column = nil
|
644
|
+
# column definitions vary right now, array of symbols/strings/hashes or perhaps a single hash
|
645
|
+
if columns.is_a?(Array) && columns[0] && columns[0].is_a?(Hash)
|
646
|
+
matching_column = columns.find {|c|
|
647
|
+
if c.is_a?(Hash)
|
648
|
+
c.keys[0].to_s.downcase == f.to_s.downcase
|
649
|
+
else
|
650
|
+
c && c.to_s.downcase == f.to_s.downcase
|
651
|
+
end
|
652
|
+
}
|
653
|
+
elsif columns.is_a?(Hash)
|
654
|
+
matching_key = columns.keys.find {|k| k.to_s.downcase == f.to_s.downcase }
|
655
|
+
if matching_key
|
656
|
+
matching_column = columns[matching_key]
|
657
|
+
end
|
658
|
+
end
|
659
|
+
new_columns << (matching_column ? matching_column : f)
|
660
|
+
end
|
661
|
+
columns = new_columns
|
662
|
+
end
|
663
|
+
elsif options[:all_fields]
|
664
|
+
columns = all_fields
|
665
|
+
else
|
666
|
+
columns = columns
|
667
|
+
end
|
668
|
+
|
631
669
|
columns = build_column_definitions(columns)
|
632
670
|
|
633
671
|
table_color = options[:color] || cyan
|
@@ -690,7 +728,7 @@ module Morpheus::Cli::PrintHelper
|
|
690
728
|
# could use some options[:preferred_columns] logic here to throw away in some specified order
|
691
729
|
# --all fields disables this
|
692
730
|
trimmed_columns = []
|
693
|
-
if options[:responsive_table] != false && options[:include_fields].nil? && options[:all_fields] != true
|
731
|
+
if options[:responsive_table] != false # && options[:include_fields].nil? && options[:all_fields] != true
|
694
732
|
|
695
733
|
begin
|
696
734
|
term_width = current_terminal_width()
|
@@ -1027,11 +1065,13 @@ module Morpheus::Cli::PrintHelper
|
|
1027
1065
|
cols = []
|
1028
1066
|
all_fields = records.first ? records.first.keys : []
|
1029
1067
|
if options[:include_fields]
|
1030
|
-
if options[:include_fields] == 'all' || options[:include_fields]
|
1068
|
+
if (options[:include_fields].is_a?(Array) && options[:include_fields].size == 1 && options[:include_fields][0] == 'all') || options[:include_fields] == 'all'
|
1031
1069
|
cols = all_fields
|
1032
1070
|
else
|
1033
1071
|
cols = options[:include_fields]
|
1034
1072
|
end
|
1073
|
+
elsif options[:all_fields]
|
1074
|
+
cols = all_fields
|
1035
1075
|
elsif default_columns
|
1036
1076
|
cols = default_columns
|
1037
1077
|
else
|
@@ -298,10 +298,12 @@ module Morpheus::Cli::ProvisioningHelper
|
|
298
298
|
# prompts user for all the configuartion options for a particular instance
|
299
299
|
# returns payload of data for a new instance
|
300
300
|
def prompt_new_instance(options={})
|
301
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
301
302
|
#puts "prompt_new_instance() #{options}"
|
302
303
|
print reset # clear colors
|
303
304
|
options[:options] ||= {}
|
304
|
-
|
305
|
+
# provisioning with blueprint can lock fields
|
306
|
+
locked_fields = options[:locked_fields] || []
|
305
307
|
# Group
|
306
308
|
default_group = find_group_by_name_or_id_for_provisioning(options[:default_group] || @active_group_id) if options[:default_group] || @active_group_id
|
307
309
|
|
@@ -365,7 +367,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
365
367
|
instance_name = name_prompt['name']
|
366
368
|
else
|
367
369
|
print_red_alert "Name must be unique"
|
368
|
-
|
370
|
+
exit 1 if no_prompt
|
369
371
|
if options[:default_name] == name_prompt['name']
|
370
372
|
options[:default_name] += '-2'
|
371
373
|
end
|
@@ -421,6 +423,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
421
423
|
arbitrary_options.delete('environment')
|
422
424
|
arbitrary_options.delete('instanceContext')
|
423
425
|
arbitrary_options.delete('tags')
|
426
|
+
arbitrary_options.delete('lockedFields')
|
424
427
|
# arbitrary_options.delete('ports')
|
425
428
|
payload.deep_merge!(arbitrary_options)
|
426
429
|
end
|
@@ -441,68 +444,85 @@ module Morpheus::Cli::ProvisioningHelper
|
|
441
444
|
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => get_available_environments()}], options[:options])
|
442
445
|
payload['instance']['instanceContext'] = v_prompt['environment'] if !v_prompt['environment'].empty?
|
443
446
|
|
444
|
-
#
|
445
|
-
|
446
|
-
|
447
|
+
# Labels (tags)
|
448
|
+
if options[:tags]
|
449
|
+
payload['instance']['tags'] = options[:tags].is_a?(Array) ? options[:tags] : options[:tags].to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq
|
450
|
+
else
|
451
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'tags', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false}], options[:options])
|
452
|
+
payload['instance']['tags'] = v_prompt['tags'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['tags'].empty?
|
453
|
+
end
|
447
454
|
|
448
455
|
# Version and Layout
|
449
|
-
|
450
|
-
|
456
|
+
layout_id = nil
|
457
|
+
if locked_fields.include?('instance.layout.id')
|
458
|
+
layout_id = options[:options]['instance']['layout'] rescue options[:options]['layout']
|
459
|
+
if layout_id.is_a?(Hash)
|
460
|
+
layout_id = layout_id['id'] || layout_id['code'] || layout_id['name']
|
461
|
+
end
|
451
462
|
else
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
463
|
+
layout_id = nil
|
464
|
+
if options[:layout]
|
465
|
+
layout_id = options[:layout]
|
466
|
+
end
|
467
|
+
if layout_id.is_a?(Hash)
|
468
|
+
layout_id = layout_id['id'] || layout_id['code'] || layout_id['name']
|
469
|
+
end
|
470
|
+
if layout_id.nil?
|
471
|
+
version_value = nil
|
472
|
+
default_layout_value = nil
|
473
|
+
if options[:version]
|
474
|
+
version_value = options[:version]
|
475
|
+
else
|
476
|
+
available_versions = options_interface.options_for_source('instanceVersions',{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})['data']
|
477
|
+
default_version_value = payload['instance']['version'] ? payload['instance']['version'] : payload['version']
|
478
|
+
#default_layout_value = options[:layout]
|
479
|
+
if default_layout_value.nil?
|
480
|
+
default_layout_value = payload['instance']['layout'] ? payload['instance']['layout'] : payload['layout']
|
481
|
+
end
|
482
|
+
if default_layout_value && default_layout_value.is_a?(Hash)
|
483
|
+
default_layout_value = default_layout_value['id']
|
484
|
+
end
|
485
|
+
# JD: version is always nil because it is not stored in the blueprint or config !!
|
486
|
+
# so for now, infer the version from the layout
|
487
|
+
# requires api 3.6.2 to get "layouts" from /options/versions
|
488
|
+
if default_layout_value && default_version_value.to_s.empty?
|
489
|
+
available_versions.each do |available_version|
|
490
|
+
if available_version["layouts"]
|
491
|
+
selected_layout = available_version["layouts"].find {|it| it["value"].to_s == default_layout_value.to_s || it["id"].to_s == default_layout_value.to_s || it["code"].to_s == default_layout_value.to_s }
|
492
|
+
if selected_layout
|
493
|
+
default_version_value = available_version["value"]
|
494
|
+
break
|
495
|
+
end
|
496
|
+
end
|
468
497
|
end
|
469
498
|
end
|
499
|
+
|
500
|
+
# do not require version if a layout is passed
|
501
|
+
version_value = default_version_value
|
502
|
+
version_is_required = default_layout_value.nil?
|
503
|
+
if default_layout_value.nil? && options[:options]["layout"].nil? && options[:always_prompt] != true
|
504
|
+
#version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'optionSource' => 'instanceVersions', 'required' => true, 'skipSingleOption' => true, 'autoPickOption' => true, 'description' => 'Select which version of the instance type to be provisioned.', 'defaultValue' => default_version_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
|
505
|
+
version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'selectOptions' => available_versions, 'required' => version_is_required, 'skipSingleOption' => true, 'autoPickOption' => true, 'description' => 'Select which version of the instance type to be provisioned.', 'defaultValue' => default_version_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
|
506
|
+
version_value = version_prompt['version']
|
507
|
+
end
|
470
508
|
end
|
471
|
-
end
|
472
509
|
|
473
|
-
|
474
|
-
version_value = default_version_value
|
475
|
-
version_is_required = default_layout_value.nil?
|
476
|
-
if default_layout_value.nil? && options[:options]["layout"].nil? && options[:always_prompt] != true
|
477
|
-
#version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'optionSource' => 'instanceVersions', 'required' => true, 'skipSingleOption' => true, 'autoPickOption' => true, 'description' => 'Select which version of the instance type to be provisioned.', 'defaultValue' => default_version_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
|
478
|
-
version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'selectOptions' => available_versions, 'required' => version_is_required, 'skipSingleOption' => true, 'autoPickOption' => true, 'description' => 'Select which version of the instance type to be provisioned.', 'defaultValue' => default_version_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
|
479
|
-
version_value = version_prompt['version']
|
510
|
+
layout_id = 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.', 'defaultValue' => default_layout_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], version: version_value, creatable: true})['layout']
|
480
511
|
end
|
481
512
|
end
|
482
513
|
|
483
|
-
# JD: there is a bug here, the version needs to be passed perhaps? or the optionSource methods need updating...
|
484
|
-
# could just allow for now ...
|
485
|
-
# if options[:options]["layout"]
|
486
|
-
# layout_id = options[:options]["layout"]
|
487
|
-
# ...
|
488
|
-
# end
|
489
|
-
layout_id = options[:layout].to_i if options[:layout]
|
490
|
-
|
491
514
|
# determine layout and provision_type
|
492
|
-
# provision_type = (layout && provision_type ? provision_type : nil) || get_provision_type_for_zone_type(cloud['zoneType']['id'])
|
493
|
-
# need to GET layout and provision type by ID in order to get optionTypes, and other settings...
|
494
|
-
|
495
|
-
if !layout_id
|
496
|
-
layout_id = 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.', 'defaultValue' => default_layout_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], version: version_value, creatable: true})['layout']
|
497
|
-
end
|
498
515
|
|
499
516
|
# layout = find_instance_type_layout_by_id(instance_type['id'], layout_id.to_i)
|
500
|
-
layout = (instance_type['instanceTypeLayouts'] || []).find {|it|
|
517
|
+
layout = (instance_type['instanceTypeLayouts'] || []).find {|it|
|
518
|
+
it['id'].to_s == layout_id.to_s || it['code'].to_s == layout_id.to_s || it['name'].to_s == layout_id.to_s
|
519
|
+
}
|
501
520
|
if !layout
|
502
521
|
print_red_alert "Layout not found by id #{layout_id}"
|
503
522
|
exit 1
|
504
523
|
end
|
505
|
-
|
524
|
+
layout_id = layout['id']
|
525
|
+
payload['instance']['layout'] = {'id' => layout['id'], 'code' => layout['code']}
|
506
526
|
|
507
527
|
# need to GET provision type for optionTypes, and other settings...
|
508
528
|
provision_type_code = layout['provisionTypeCode'] || layout['provisionType']['code']
|
@@ -518,37 +538,47 @@ module Morpheus::Cli::ProvisioningHelper
|
|
518
538
|
end
|
519
539
|
|
520
540
|
# prompt for service plan
|
541
|
+
plan_id = nil
|
542
|
+
service_plan = nil
|
521
543
|
service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
|
522
544
|
service_plans = service_plans_json["plans"]
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
default_plan = nil
|
528
|
-
if payload['plan']
|
529
|
-
default_plan = payload['plan']
|
530
|
-
elsif payload['instance'] && payload['instance']['plan']
|
531
|
-
default_plan = payload['instance']['plan']
|
545
|
+
if locked_fields.include?('plan.id')
|
546
|
+
plan_id = options[:options]['plan']['id'] rescue nil
|
547
|
+
if plan_id.nil?
|
548
|
+
plan_id = options[:options]['instance']['plan']['id'] rescue nil
|
532
549
|
end
|
550
|
+
service_plan = service_plans.find {|sp| sp['id'] == plan_id }
|
551
|
+
else
|
552
|
+
service_plan = service_plans.find {|sp| sp['id'] == options[:service_plan].to_i} if options[:service_plan]
|
533
553
|
|
534
|
-
if options[:default_plan] && service_plans_dropdown.find {|sp| [sp["name"], sp["value"].to_s, sp["code"]].include?(options[:default_plan].to_s)}
|
535
|
-
default_plan_value = options[:default_plan]
|
536
|
-
else
|
537
|
-
default_plan_value = options[:default_plan] || (default_plan.is_a?(Hash) ? default_plan['id'] : default_plan)
|
538
|
-
end
|
539
|
-
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', 'defaultValue' => default_plan_value}],options[:options])
|
540
|
-
plan_id = plan_prompt['servicePlan']
|
541
|
-
service_plan = service_plans.find {|sp| sp["id"] == plan_id.to_i }
|
542
554
|
if !service_plan
|
543
|
-
|
544
|
-
|
555
|
+
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"], 'code' => sp['code']} } # already sorted
|
556
|
+
default_plan = nil
|
557
|
+
if payload['plan']
|
558
|
+
default_plan = payload['plan']
|
559
|
+
elsif payload['instance'] && payload['instance']['plan']
|
560
|
+
default_plan = payload['instance']['plan']
|
561
|
+
end
|
562
|
+
|
563
|
+
if options[:default_plan] && service_plans_dropdown.find {|sp| [sp["name"], sp["value"].to_s, sp["code"]].include?(options[:default_plan].to_s)}
|
564
|
+
default_plan_value = options[:default_plan]
|
565
|
+
else
|
566
|
+
default_plan_value = options[:default_plan] || (default_plan.is_a?(Hash) ? default_plan['id'] : default_plan)
|
567
|
+
end
|
568
|
+
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', 'defaultValue' => default_plan_value}],options[:options])
|
569
|
+
plan_id = plan_prompt['servicePlan']
|
570
|
+
service_plan = service_plans.find {|sp| sp["id"] == plan_id.to_i }
|
571
|
+
if !service_plan
|
572
|
+
print_red_alert "Plan not found by id #{plan_id}"
|
573
|
+
exit 1
|
574
|
+
end
|
545
575
|
end
|
576
|
+
#todo: consolidate these, instances api looks for instance.plan.id and apps looks for plan.id
|
577
|
+
payload['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
|
578
|
+
payload['instance']['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
|
546
579
|
end
|
547
|
-
#todo: consolidate these, instances api looks for instance.plan.id and apps looks for plan.id
|
548
|
-
payload['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
|
549
|
-
payload['instance']['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
|
550
580
|
|
551
|
-
# build option types
|
581
|
+
# build config option types
|
552
582
|
option_type_list = []
|
553
583
|
if !layout['optionTypes'].nil? && !layout['optionTypes'].empty?
|
554
584
|
option_type_list += layout['optionTypes']
|
@@ -559,42 +589,43 @@ module Morpheus::Cli::ProvisioningHelper
|
|
559
589
|
if !provision_type.nil? && !provision_type['optionTypes'].nil? && !provision_type['optionTypes'].empty?
|
560
590
|
option_type_list += provision_type['optionTypes']
|
561
591
|
end
|
562
|
-
if !payload['volumes'].empty?
|
563
|
-
option_type_list = reject_volume_option_types(option_type_list)
|
564
|
-
end
|
565
|
-
# remove networkId option if networks were configured above
|
566
|
-
if !payload['networkInterfaces'].empty?
|
567
|
-
option_type_list = reject_networking_option_types(option_type_list)
|
568
|
-
end
|
569
592
|
|
570
593
|
# prompt for resource pool
|
571
594
|
pool_id = nil
|
572
595
|
resource_pool = nil
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
if
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
+
if locked_fields.include?('config.resourcePoolId')
|
597
|
+
pool_id = payload['config']['resourcePoolId'] rescue nil
|
598
|
+
elsif locked_fields.include?('config.resourcePool')
|
599
|
+
pool_id = payload['config']['resourcePool'] rescue nil
|
600
|
+
elsif locked_fields.include?('config.azureResourceGroupId')
|
601
|
+
pool_id = payload['config']['azureResourceGroupId'] rescue nil
|
602
|
+
else
|
603
|
+
has_zone_pools = provision_type && provision_type["id"] && provision_type["hasZonePools"]
|
604
|
+
if has_zone_pools
|
605
|
+
# pluck out the resourcePoolId option type to prompt for
|
606
|
+
resource_pool_option_type = option_type_list.find {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
607
|
+
option_type_list = option_type_list.reject {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
608
|
+
resource_pool_options = @options_interface.options_for_source('zonePools', {groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], planId: service_plan["id"], layoutId: layout["id"]})['data']
|
609
|
+
resource_pool = resource_pool_options.find {|opt| opt['id'] == options[:resource_pool].to_i} if options[:resource_pool]
|
610
|
+
|
611
|
+
if resource_pool
|
612
|
+
pool_id = resource_pool['id']
|
613
|
+
else
|
614
|
+
if options[:default_resource_pool]
|
615
|
+
default_resource_pool = resource_pool_options.find {|rp| rp['id'] == options[:default_resource_pool]}
|
616
|
+
end
|
617
|
+
resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.', 'defaultValue' => default_resource_pool ? default_resource_pool['name'] : nil}
|
618
|
+
resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{})
|
619
|
+
resource_pool_prompt.deep_compact!
|
620
|
+
payload.deep_merge!(resource_pool_prompt)
|
621
|
+
resource_pool = Morpheus::Cli::OptionTypes.get_last_select()
|
622
|
+
if resource_pool_option_type['fieldContext'] && resource_pool_prompt[resource_pool_option_type['fieldContext']]
|
623
|
+
pool_id = resource_pool_prompt[resource_pool_option_type['fieldContext']][resource_pool_option_type['fieldName']]
|
624
|
+
elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
|
625
|
+
pool_id = resource_pool_prompt[resource_pool_option_type['fieldName']]
|
626
|
+
end
|
627
|
+
resource_pool ||= resource_pool_options.find {|it| it['id'] == pool_id}
|
596
628
|
end
|
597
|
-
resource_pool ||= resource_pool_options.find {|it| it['id'] == pool_id}
|
598
629
|
end
|
599
630
|
end
|
600
631
|
|
@@ -652,43 +683,81 @@ module Morpheus::Cli::ProvisioningHelper
|
|
652
683
|
end
|
653
684
|
|
654
685
|
# prompt for volumes
|
655
|
-
|
656
|
-
|
657
|
-
|
686
|
+
if locked_fields.include?('volumes')
|
687
|
+
payload['volumes'] = options[:options]['volumes'] if options[:options]['volumes']
|
688
|
+
else
|
689
|
+
volumes = prompt_volumes(service_plan, options, api_client, {zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
|
690
|
+
if !volumes.empty?
|
691
|
+
payload['volumes'] = volumes
|
692
|
+
end
|
658
693
|
end
|
659
694
|
|
660
695
|
# prompt networks
|
661
|
-
if
|
662
|
-
#
|
663
|
-
|
664
|
-
|
665
|
-
if
|
666
|
-
|
696
|
+
if locked_fields.include?('networks')
|
697
|
+
# payload['networkInterfaces'] = options[:options]['networkInterfaces'] if options[:options]['networkInterfaces']
|
698
|
+
else
|
699
|
+
if provision_type && provision_type["hasNetworks"]
|
700
|
+
# prompt for network interfaces (if supported)
|
701
|
+
begin
|
702
|
+
network_interfaces = prompt_network_interfaces(cloud_id, provision_type["id"], pool_id, options)
|
703
|
+
if !network_interfaces.empty?
|
704
|
+
payload['networkInterfaces'] = network_interfaces
|
705
|
+
end
|
706
|
+
rescue RestClient::Exception => e
|
707
|
+
print yellow,"Unable to load network options. Proceeding...",reset,"\n"
|
708
|
+
print_rest_exception(e, options) if Morpheus::Logging.debug?
|
667
709
|
end
|
668
|
-
rescue RestClient::Exception => e
|
669
|
-
print yellow,"Unable to load network options. Proceeding...",reset,"\n"
|
670
|
-
print_rest_exception(e, options) if Morpheus::Logging.debug?
|
671
710
|
end
|
672
711
|
end
|
673
|
-
# end
|
674
712
|
|
675
713
|
# Security Groups
|
676
|
-
#
|
714
|
+
# look for securityGroups option type... this is old and goofy
|
677
715
|
sg_option_type = option_type_list.find {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['name'] == 'securityId')) }
|
678
716
|
option_type_list = option_type_list.reject {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['name'] == 'securityId')) }
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
717
|
+
if locked_fields.include?('securityGroups')
|
718
|
+
# payload['securityGroups'] = options[:options]['securityGroups'] if options[:options]['securityGroups']
|
719
|
+
else
|
720
|
+
# prompt for multiple security groups
|
721
|
+
# ok.. seed data has changed and serverTypes do not have this optionType anymore...
|
722
|
+
if sg_option_type.nil?
|
723
|
+
if provision_type && (provision_type["code"] == 'amazon')
|
724
|
+
sg_option_type = {'fieldContext' => 'config', 'fieldName' => 'securityId', 'type' => 'select', 'fieldLabel' => 'Security Group', 'optionSource' => 'amazonSecurityGroup', 'required' => true, 'description' => 'Select security group.', 'defaultValue' => options[:default_security_group]}
|
725
|
+
end
|
683
726
|
end
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
727
|
+
sg_api_params = {zoneId: cloud_id, poolId: pool_id}
|
728
|
+
has_security_groups = !!sg_option_type
|
729
|
+
available_security_groups = []
|
730
|
+
if sg_option_type && sg_option_type['type'] == 'select' && sg_option_type['optionSource']
|
731
|
+
sg_option_results = options_interface.options_for_source(sg_option_type['optionSource'], sg_api_params)
|
732
|
+
available_security_groups = sg_option_results['data'].collect do |it|
|
733
|
+
{"id" => it["value"] || it["id"], "name" => it["name"], "value" => it["value"] || it["id"]}
|
734
|
+
end
|
735
|
+
end
|
736
|
+
if options[:security_groups]
|
737
|
+
# work with id or names, API expects ids though.
|
738
|
+
payload['securityGroups'] = options[:security_groups].collect {|sg_id|
|
739
|
+
found_sg = available_security_groups.find {|it| sg_id && (sg_id.to_s == it['id'].to_s || sg_id.to_s == it['name'].to_s) }
|
740
|
+
if found_sg.nil?
|
741
|
+
print_red_alert "Security group not found by name or id '#{sg_id}'"
|
742
|
+
exit 1
|
743
|
+
end
|
744
|
+
{'id' => found_sg['id']}
|
745
|
+
}
|
746
|
+
|
747
|
+
elsif has_security_groups
|
748
|
+
do_prompt_sg = true
|
749
|
+
if options[:default_security_groups]
|
750
|
+
payload['securityGroups'] = options[:default_security_groups]
|
751
|
+
security_groups_value = options[:default_security_groups].collect {|sg| sg['id'] }.join(',') rescue options[:default_security_groups]
|
752
|
+
# do_prompt_sg = (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Modify security groups? (#{security_groups_value})", {:default => false}))
|
753
|
+
do_prompt_sg = (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Modify security groups?", {:default => false}))
|
754
|
+
end
|
755
|
+
if do_prompt_sg
|
756
|
+
security_groups_array = prompt_security_groups(sg_option_type, sg_api_params, options)
|
757
|
+
if !security_groups_array.empty?
|
758
|
+
payload['securityGroups'] = security_groups_array.collect {|sg_id| {'id' => sg_id} }
|
759
|
+
end
|
760
|
+
end
|
692
761
|
end
|
693
762
|
end
|
694
763
|
|
@@ -732,10 +801,35 @@ module Morpheus::Cli::ProvisioningHelper
|
|
732
801
|
payload['evars'] = evars
|
733
802
|
end
|
734
803
|
|
735
|
-
#
|
736
|
-
metadata
|
737
|
-
|
738
|
-
|
804
|
+
# metadata tags
|
805
|
+
if options[:options]['metadata'].is_a?(Array) && !options[:metadata]
|
806
|
+
options[:metadata] = options[:options]['metadata']
|
807
|
+
end
|
808
|
+
if options[:metadata]
|
809
|
+
if options[:metadata] == "[]" || options[:metadata] == "null"
|
810
|
+
payload['metadata'] = []
|
811
|
+
elsif options[:metadata].is_a?(Array)
|
812
|
+
payload['metadata'] = options[:metadata]
|
813
|
+
else
|
814
|
+
# parse string into format name:value, name:value
|
815
|
+
# merge IDs from current metadata
|
816
|
+
# todo: should allow quoted semicolons..
|
817
|
+
metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
|
818
|
+
metadata_list = metadata_list.collect do |it|
|
819
|
+
metadata_pair = it.split(":")
|
820
|
+
row = {}
|
821
|
+
row['name'] = metadata_pair[0].to_s.strip
|
822
|
+
row['value'] = metadata_pair[1].to_s.strip
|
823
|
+
row
|
824
|
+
end
|
825
|
+
payload['metadata'] = metadata_list
|
826
|
+
end
|
827
|
+
else
|
828
|
+
# prompt for metadata tags
|
829
|
+
metadata = prompt_metadata(options)
|
830
|
+
if !metadata.empty?
|
831
|
+
payload['metadata'] = metadata
|
832
|
+
end
|
739
833
|
end
|
740
834
|
|
741
835
|
return payload
|
@@ -1293,6 +1387,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1293
1387
|
# end
|
1294
1388
|
# end
|
1295
1389
|
|
1390
|
+
# networkInterfaces may be passed as objects from blueprints or via -O networkInterfaces='[]'
|
1296
1391
|
field_context = interface_index == 0 ? "networkInterface" : "networkInterface#{interface_index+1}"
|
1297
1392
|
network_interface = {}
|
1298
1393
|
if options[:options] && options[:options]['networkInterfaces'] && options[:options]['networkInterfaces'][interface_index]
|
@@ -1300,14 +1395,20 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1300
1395
|
end
|
1301
1396
|
|
1302
1397
|
default_network_id = network_interface['networkId'] || network_interface['id']
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1398
|
+
if default_network_id.nil? && network_interface['network'].is_a?(Hash) && network_interface['network']['id']
|
1399
|
+
default_network_id = network_interface['network']['id']
|
1400
|
+
end
|
1401
|
+
# JD: this for cluster or server prompting perhaps?
|
1402
|
+
# because zoneNetworkOptions already returns foramt like "id": "network-1"
|
1403
|
+
if !default_network_id || !default_network_id.to_s.include?("-")
|
1404
|
+
if network_interface['network'] && network_interface['network']['id']
|
1405
|
+
if network_interface['network']['subnet']
|
1406
|
+
default_network_id = "subnet-#{network_interface['network']['subnet']}"
|
1407
|
+
elsif network_interface['network']['group']
|
1408
|
+
default_network_id = "networkGroup-#{network_interface['network']['group']}"
|
1409
|
+
else
|
1410
|
+
default_network_id = "network-#{network_interface['network']['id']}"
|
1411
|
+
end
|
1311
1412
|
end
|
1312
1413
|
end
|
1313
1414
|
|
@@ -1318,7 +1419,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1318
1419
|
network_interface['network'] = {}
|
1319
1420
|
network_interface['network']['id'] = v_prompt[field_context]['networkId'].to_s
|
1320
1421
|
selected_network = networks.find {|it| it["id"].to_s == network_interface['network']['id'] }
|
1321
|
-
network_options.reject! {|it| it['value'] == v_prompt[field_context]['networkId']}
|
1422
|
+
#network_options.reject! {|it| it['value'] == v_prompt[field_context]['networkId']}
|
1322
1423
|
|
1323
1424
|
if !selected_network
|
1324
1425
|
print_red_alert "Network not found by id #{network_interface['network']['id']}!"
|
@@ -1332,10 +1433,13 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1332
1433
|
network_interface['networkInterfaceTypeId'] = v_prompt[field_context]['networkInterfaceTypeId'].to_i
|
1333
1434
|
end
|
1334
1435
|
|
1335
|
-
# choose IP
|
1436
|
+
# choose IP if network allows it
|
1437
|
+
# allowStaticOverride is only returned in 4.2.1+, so treat null as true for now..
|
1438
|
+
ip_available = selected_network['allowStaticOverride'] == true || selected_network['allowStaticOverride'].nil?
|
1336
1439
|
ip_required = true
|
1337
1440
|
if selected_network['id'].to_s.include?('networkGroup')
|
1338
1441
|
#puts "IP Address: Using network group." if !no_prompt
|
1442
|
+
ip_available = false
|
1339
1443
|
ip_required = false
|
1340
1444
|
elsif selected_network['pool']
|
1341
1445
|
#puts "IP Address: Using pool '#{selected_network['pool']['name']}'" if !no_prompt
|
@@ -1344,9 +1448,12 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1344
1448
|
#puts "IP Address: Using DHCP" if !no_prompt
|
1345
1449
|
ip_required = false
|
1346
1450
|
end
|
1347
|
-
|
1348
|
-
if
|
1349
|
-
|
1451
|
+
|
1452
|
+
if ip_available
|
1453
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'ipAddress', 'type' => 'text', 'fieldLabel' => "IP Address", 'required' => ip_required, 'description' => 'Enter an IP for this network interface. x.x.x.x', 'defaultValue' => network_interface['ipAddress']}], options[:options])
|
1454
|
+
if v_prompt[field_context] && !v_prompt[field_context]['ipAddress'].to_s.empty?
|
1455
|
+
network_interface['ipAddress'] = v_prompt[field_context]['ipAddress']
|
1456
|
+
end
|
1350
1457
|
end
|
1351
1458
|
|
1352
1459
|
network_interfaces << network_interface
|
@@ -1493,27 +1600,6 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1493
1600
|
return payload
|
1494
1601
|
end
|
1495
1602
|
|
1496
|
-
# reject old volume option types
|
1497
|
-
# these will eventually get removed from the associated optionTypes
|
1498
|
-
def reject_volume_option_types(option_types)
|
1499
|
-
option_types.reject {|opt|
|
1500
|
-
['osDiskSize', 'osDiskType',
|
1501
|
-
'diskSize', 'diskType',
|
1502
|
-
'datastoreId', 'storagePodId'
|
1503
|
-
].include?(opt['fieldName'])
|
1504
|
-
}
|
1505
|
-
end
|
1506
|
-
|
1507
|
-
# reject old networking option types
|
1508
|
-
# these will eventually get removed from the associated optionTypes
|
1509
|
-
def reject_networking_option_types(option_types)
|
1510
|
-
option_types.reject {|opt|
|
1511
|
-
['networkId', 'networkType', 'ipAddress', 'netmask', 'gateway', 'nameservers',
|
1512
|
-
'vmwareNetworkType', 'vmwareIpAddress', 'vmwareNetmask', 'vmwareGateway', 'vmwareNameservers',
|
1513
|
-
'subnetId'
|
1514
|
-
].include?(opt['fieldName'])
|
1515
|
-
}
|
1516
|
-
end
|
1517
1603
|
|
1518
1604
|
# reject old option types that now come from the selected service plan
|
1519
1605
|
# these will eventually get removed from the associated optionTypes
|