morpheus-cli 4.0.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/morpheus/api.rb +10 -0
- data/lib/morpheus/api/api_client.rb +24 -3
- data/lib/morpheus/api/clouds_interface.rb +15 -0
- data/lib/morpheus/api/clusters_interface.rb +276 -0
- data/lib/morpheus/api/library_compute_type_layouts_interface.rb +26 -0
- data/lib/morpheus/api/logs_interface.rb +6 -0
- data/lib/morpheus/api/network_subnet_types_interface.rb +26 -0
- data/lib/morpheus/api/network_subnets_interface.rb +47 -0
- data/lib/morpheus/api/provision_types_interface.rb +6 -0
- data/lib/morpheus/api/security_groups_interface.rb +12 -3
- data/lib/morpheus/api/servers_interface.rb +15 -0
- data/lib/morpheus/api/service_plans_interface.rb +30 -0
- data/lib/morpheus/api/subnets_interface.rb +47 -0
- data/lib/morpheus/cli.rb +1 -0
- data/lib/morpheus/cli/apps.rb +20 -18
- data/lib/morpheus/cli/cli_command.rb +5 -1
- data/lib/morpheus/cli/clusters.rb +3952 -0
- data/lib/morpheus/cli/containers_command.rb +70 -2
- data/lib/morpheus/cli/hosts.rb +69 -53
- data/lib/morpheus/cli/instances.rb +33 -33
- data/lib/morpheus/cli/library_container_types_command.rb +2 -1
- data/lib/morpheus/cli/library_option_lists_command.rb +13 -8
- data/lib/morpheus/cli/mixins/accounts_helper.rb +43 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +10 -2
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +53 -3
- data/lib/morpheus/cli/networks_command.rb +883 -36
- data/lib/morpheus/cli/option_types.rb +37 -14
- data/lib/morpheus/cli/roles.rb +78 -77
- data/lib/morpheus/cli/user_settings_command.rb +34 -5
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +10 -2
@@ -21,6 +21,12 @@ module Morpheus::Cli::AccountsHelper
|
|
21
21
|
@users_interface
|
22
22
|
end
|
23
23
|
|
24
|
+
def user_groups_interface
|
25
|
+
# @api_client.users
|
26
|
+
raise "#{self.class} has not defined @user_groups_interface" if @user_groups_interface.nil?
|
27
|
+
@user_groups_interface
|
28
|
+
end
|
29
|
+
|
24
30
|
def roles_interface
|
25
31
|
# @api_client.roles
|
26
32
|
raise "#{self.class} has not defined @roles_interface" if @roles_interface.nil?
|
@@ -179,6 +185,43 @@ module Morpheus::Cli::AccountsHelper
|
|
179
185
|
user_ids
|
180
186
|
end
|
181
187
|
|
188
|
+
def find_user_group_by_name_or_id(account_id, val)
|
189
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
190
|
+
return find_user_group_by_id(account_id, val)
|
191
|
+
else
|
192
|
+
return find_user_group_by_name(account_id, val)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def find_user_group_by_id(account_id, id)
|
197
|
+
begin
|
198
|
+
json_response = @user_groups_interface.get(account_id, id.to_i)
|
199
|
+
return json_response['userGroup']
|
200
|
+
rescue RestClient::Exception => e
|
201
|
+
if e.response && e.response.code == 404
|
202
|
+
print_red_alert "User Group not found by id #{id}"
|
203
|
+
else
|
204
|
+
raise e
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def find_user_group_by_name(account_id, name)
|
210
|
+
user_groups = @user_groups_interface.list(account_id, {name: name.to_s})['userGroups']
|
211
|
+
if user_groups.empty?
|
212
|
+
print_red_alert "User Group not found by name #{name}"
|
213
|
+
return nil
|
214
|
+
elsif user_groups.size > 1
|
215
|
+
print_red_alert "#{user_groups.size} user groups found by name #{name}"
|
216
|
+
print_user_groups_table(user_groups, {color: red})
|
217
|
+
print_red_alert "Try using ID instead"
|
218
|
+
print reset,"\n"
|
219
|
+
return nil
|
220
|
+
else
|
221
|
+
return user_groups[0]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
182
225
|
def print_accounts_table(accounts, options={})
|
183
226
|
table_color = options.key?(:color) ? options[:color] : cyan
|
184
227
|
rows = accounts.collect do |account|
|
@@ -475,9 +475,17 @@ module Morpheus::Cli::PrintHelper
|
|
475
475
|
print out
|
476
476
|
return
|
477
477
|
end
|
478
|
-
opts[:include] ||= [:
|
478
|
+
opts[:include] ||= [:cpu, :memory, :storage]
|
479
|
+
if opts[:include].include?(:max_cpu)
|
480
|
+
cpu_usage = stats['cpuUsagePeak']
|
481
|
+
out << cyan + "Max CPU".rjust(label_width, ' ') + ": " + generate_usage_bar(cpu_usage.to_f, 100) + "\n"
|
482
|
+
end
|
483
|
+
if opts[:include].include?(:avg_cpu)
|
484
|
+
cpu_usage = stats['cpuUsageAvg']
|
485
|
+
out << cyan + "Avg. CPU".rjust(label_width, ' ') + ": " + generate_usage_bar(cpu_usage.to_f, 100) + "\n"
|
486
|
+
end
|
479
487
|
if opts[:include].include?(:cpu)
|
480
|
-
cpu_usage =
|
488
|
+
cpu_usage = stats['cpuUsage'] || stats['usedCpu']
|
481
489
|
out << cyan + "CPU".rjust(label_width, ' ') + ": " + generate_usage_bar(cpu_usage.to_f, 100) + "\n"
|
482
490
|
end
|
483
491
|
if opts[:include].include?(:memory)
|
@@ -208,6 +208,46 @@ module Morpheus::Cli::ProvisioningHelper
|
|
208
208
|
return instance
|
209
209
|
end
|
210
210
|
|
211
|
+
def find_workflow_by_name_or_id(val)
|
212
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
213
|
+
return find_workflow_by_id(val)
|
214
|
+
else
|
215
|
+
return find_workflow_by_name(val)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def find_workflow_by_id(id)
|
220
|
+
begin
|
221
|
+
json_response = @task_sets_interface.get(id.to_i)
|
222
|
+
return json_response['taskSet']
|
223
|
+
rescue RestClient::Exception => e
|
224
|
+
if e.response && e.response.code == 404
|
225
|
+
print_red_alert "Workflow not found by id #{id}"
|
226
|
+
else
|
227
|
+
raise e
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def find_workflow_by_name(name)
|
233
|
+
workflows = @task_sets_interface.get({name: name.to_s})['taskSets']
|
234
|
+
if workflows.empty?
|
235
|
+
print_red_alert "Workflow not found by name #{name}"
|
236
|
+
return nil
|
237
|
+
elsif workflows.size > 1
|
238
|
+
print_red_alert "#{workflows.size} workflows by name #{name}"
|
239
|
+
print_workflows_table(workflows, {color: red})
|
240
|
+
print reset,"\n\n"
|
241
|
+
return nil
|
242
|
+
else
|
243
|
+
return workflows[0]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def get_provision_type_for_zone_type(zone_type_id)
|
248
|
+
@clouds_interface.cloud_type(zone_type_id)['zoneType']['provisionTypes'].first rescue nil
|
249
|
+
end
|
250
|
+
|
211
251
|
# prompts user for all the configuartion options for a particular instance
|
212
252
|
# returns payload of data for a new instance
|
213
253
|
def prompt_new_instance(options={})
|
@@ -387,7 +427,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
387
427
|
payload['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
|
388
428
|
payload['instance']['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
|
389
429
|
|
390
|
-
|
430
|
+
# determine provision_type
|
431
|
+
# provision_type = (layout && layout['provisionType'] ? layout['provisionType'] : nil) || get_provision_type_for_zone_type(cloud['zoneType']['id'])
|
391
432
|
|
392
433
|
# build option types
|
393
434
|
option_type_list = []
|
@@ -410,15 +451,17 @@ module Morpheus::Cli::ProvisioningHelper
|
|
410
451
|
|
411
452
|
# prompt for resource pool
|
412
453
|
pool_id = nil
|
454
|
+
resource_pool = nil
|
413
455
|
has_zone_pools = layout["provisionType"] && layout["provisionType"]["id"] && layout["provisionType"]["hasZonePools"]
|
414
456
|
if has_zone_pools
|
415
|
-
# pluck out the resourcePoolId option type to prompt for
|
457
|
+
# pluck out the resourcePoolId option type to prompt for
|
416
458
|
resource_pool_option_type = option_type_list.find {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
417
459
|
option_type_list = option_type_list.reject {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
418
460
|
resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'optionSource' => 'zonePools', 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.'}
|
419
461
|
resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], planId: service_plan["id"], layoutId: layout["id"]})
|
420
462
|
resource_pool_prompt.deep_compact!
|
421
463
|
payload.deep_merge!(resource_pool_prompt)
|
464
|
+
resource_pool = Morpheus::Cli::OptionTypes.get_last_select()
|
422
465
|
if resource_pool_option_type['fieldContext'] && resource_pool_prompt[resource_pool_option_type['fieldContext']]
|
423
466
|
pool_id = resource_pool_prompt[resource_pool_option_type['fieldContext']][resource_pool_option_type['fieldName']]
|
424
467
|
elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
|
@@ -426,6 +469,13 @@ module Morpheus::Cli::ProvisioningHelper
|
|
426
469
|
end
|
427
470
|
end
|
428
471
|
|
472
|
+
# remove host selection for kubernetes
|
473
|
+
if resource_pool && resource_pool['providerType'] == 'kubernetes'
|
474
|
+
option_type_list = option_type_list.reject {|opt|
|
475
|
+
['provisionServerId'].include?(opt['fieldName'])
|
476
|
+
}
|
477
|
+
end
|
478
|
+
|
429
479
|
# plan_info has this property already..
|
430
480
|
# has_datastore = layout["provisionType"] && layout["provisionType"]["id"] && layout["provisionType"]["hasDatastore"]
|
431
481
|
# service_plan['hasDatastore'] = has_datastore
|
@@ -628,7 +678,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
628
678
|
if plan_info['addVolumes']
|
629
679
|
volume_index = 1
|
630
680
|
has_another_volume = (options[:options] && options[:options]["dataVolume#{volume_index}"]) || (options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index])
|
631
|
-
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?", {:default =>
|
681
|
+
add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?", {:default => (options[:defaultAddFirstDataVolume] == true && volume_index == 1)}))
|
632
682
|
while add_another_volume do
|
633
683
|
#puts "Configure Data #{volume_index} Volume"
|
634
684
|
|
@@ -12,6 +12,11 @@ class Morpheus::Cli::NetworksCommand
|
|
12
12
|
|
13
13
|
register_subcommands :list, :get, :add, :update, :remove #, :generate_pool
|
14
14
|
register_subcommands :'types' => :list_types
|
15
|
+
register_subcommands :'get-type' => :get_type
|
16
|
+
|
17
|
+
register_subcommands :list_subnets, :get_subnet, :add_subnet, :update_subnet, :remove_subnet
|
18
|
+
register_subcommands :'subnet-types' => :list_subnet_types
|
19
|
+
register_subcommands :'get-subnet-type' => :get_subnet_type
|
15
20
|
|
16
21
|
# set_default_subcommand :list
|
17
22
|
|
@@ -23,6 +28,8 @@ class Morpheus::Cli::NetworksCommand
|
|
23
28
|
@api_client = establish_remote_appliance_connection(opts)
|
24
29
|
@networks_interface = @api_client.networks
|
25
30
|
@network_types_interface = @api_client.network_types
|
31
|
+
@network_subnets_interface = @api_client.network_subnets
|
32
|
+
@network_subnet_types_interface = @api_client.network_subnet_types
|
26
33
|
@clouds_interface = @api_client.clouds
|
27
34
|
@options_interface = @api_client.options
|
28
35
|
end
|
@@ -571,7 +578,8 @@ class Morpheus::Cli::NetworksCommand
|
|
571
578
|
elsif !options[:quiet]
|
572
579
|
network = json_response['network']
|
573
580
|
print_green_success "Added network #{network['name']}"
|
574
|
-
|
581
|
+
get_args = [network['id']] + (options[:remote] ? ["-r",options[:remote]] : [])
|
582
|
+
get(get_args)
|
575
583
|
end
|
576
584
|
return 0
|
577
585
|
rescue RestClient::Exception => e
|
@@ -903,7 +911,8 @@ class Morpheus::Cli::NetworksCommand
|
|
903
911
|
else
|
904
912
|
network = json_response['network']
|
905
913
|
print_green_success "Updated network #{network['name']}"
|
906
|
-
|
914
|
+
get_args = [network['id']] + (options[:remote] ? ["-r",options[:remote]] : [])
|
915
|
+
get(get_args)
|
907
916
|
end
|
908
917
|
return 0
|
909
918
|
rescue RestClient::Exception => e
|
@@ -964,7 +973,7 @@ class Morpheus::Cli::NetworksCommand
|
|
964
973
|
options[:cloud] = val
|
965
974
|
end
|
966
975
|
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
967
|
-
opts.footer = "List
|
976
|
+
opts.footer = "List network types."
|
968
977
|
end
|
969
978
|
optparse.parse!(args)
|
970
979
|
connect(options)
|
@@ -990,7 +999,7 @@ class Morpheus::Cli::NetworksCommand
|
|
990
999
|
|
991
1000
|
network_types = json_response['networkTypes']
|
992
1001
|
|
993
|
-
title = "Morpheus
|
1002
|
+
title = "Morpheus Network Types"
|
994
1003
|
subtitles = []
|
995
1004
|
subtitles += parse_list_subtitles(options)
|
996
1005
|
if options[:cloud]
|
@@ -1022,52 +1031,890 @@ class Morpheus::Cli::NetworksCommand
|
|
1022
1031
|
end
|
1023
1032
|
end
|
1024
1033
|
|
1025
|
-
|
1034
|
+
def get_type(args)
|
1035
|
+
options = {}
|
1036
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1037
|
+
opts.banner = subcommand_usage("[type]")
|
1038
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
1039
|
+
opts.footer = "Get details about a network type.\n" +
|
1040
|
+
"[type] is required. This is the id or name of a network type."
|
1041
|
+
end
|
1042
|
+
optparse.parse!(args)
|
1043
|
+
connect(options)
|
1044
|
+
begin
|
1045
|
+
params = {}
|
1046
|
+
@network_types_interface.setopts(options)
|
1047
|
+
if options[:dry_run]
|
1048
|
+
if args[0].to_s =~ /\A\d{1,}\Z/
|
1049
|
+
print_dry_run @network_types_interface.dry.get(args[0].to_i)
|
1050
|
+
else
|
1051
|
+
print_dry_run @network_types_interface.dry.list({name:args[0]})
|
1052
|
+
end
|
1053
|
+
return
|
1054
|
+
end
|
1026
1055
|
|
1056
|
+
network_type = find_network_type_by_name_or_id(args[0])
|
1057
|
+
return 1 if network_type.nil?
|
1058
|
+
json_response = {'networkType' => network_type} # skip redundant request
|
1059
|
+
# json_response = @networks_interface.get(network_type['id'])
|
1060
|
+
|
1061
|
+
render_result = render_with_format(json_response, options, 'networkType')
|
1062
|
+
return 0 if render_result
|
1027
1063
|
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1064
|
+
network_type = json_response['networkType']
|
1065
|
+
|
1066
|
+
title = "Morpheus Network Type"
|
1067
|
+
|
1068
|
+
print_h1 "Morpheus Network Type", [], options
|
1069
|
+
|
1070
|
+
print cyan
|
1071
|
+
description_cols = {
|
1072
|
+
"ID" => 'id',
|
1073
|
+
"Name" => 'name',
|
1074
|
+
"Code" => 'name',
|
1075
|
+
"Description" => 'description',
|
1076
|
+
# lots more here
|
1077
|
+
"Createable" => lambda {|it| format_boolean(it['creatable']) },
|
1078
|
+
"Deletable" => lambda {|it| format_boolean(it['deleteable']) },
|
1079
|
+
}
|
1080
|
+
print_description_list(description_cols, network_type)
|
1081
|
+
|
1082
|
+
|
1083
|
+
option_types = network_type['optionTypes'] || []
|
1084
|
+
option_types = option_types.sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
1085
|
+
if !option_types.empty?
|
1086
|
+
print_h2 "Config Option Types", [], options
|
1087
|
+
option_type_cols = {
|
1088
|
+
"Name" => lambda {|it| it['fieldContext'].to_s != '' ? "#{it['fieldContext']}.#{it['fieldName']}" : it['fieldName'] },
|
1089
|
+
"Label" => lambda {|it| it['fieldLabel'] },
|
1090
|
+
"Type" => lambda {|it| it['type'] },
|
1091
|
+
}
|
1092
|
+
print cyan
|
1093
|
+
print as_pretty_table(option_types, option_type_cols)
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
print reset,"\n"
|
1097
|
+
return 0
|
1098
|
+
rescue RestClient::Exception => e
|
1099
|
+
print_rest_exception(e, options)
|
1100
|
+
exit 1
|
1033
1101
|
end
|
1034
1102
|
end
|
1035
1103
|
|
1036
|
-
def
|
1104
|
+
def list_subnet_types(args)
|
1105
|
+
options = {}
|
1106
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1107
|
+
opts.banner = subcommand_usage()
|
1108
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
|
1109
|
+
options[:cloud] = val
|
1110
|
+
end
|
1111
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
1112
|
+
opts.footer = "List subnet types."
|
1113
|
+
end
|
1114
|
+
optparse.parse!(args)
|
1115
|
+
connect(options)
|
1037
1116
|
begin
|
1038
|
-
|
1039
|
-
|
1117
|
+
params = {}
|
1118
|
+
params.merge!(parse_list_options(options))
|
1119
|
+
if options[:cloud]
|
1120
|
+
#return network_types_for_cloud(options[:cloud], options)
|
1121
|
+
zone = find_zone_by_name_or_id(nil, options[:cloud])
|
1122
|
+
#params["zoneTypeId"] = zone['zoneTypeId']
|
1123
|
+
params["zoneId"] = zone['id']
|
1124
|
+
params["creatable"] = true
|
1125
|
+
end
|
1126
|
+
@network_subnet_types_interface.setopts(options)
|
1127
|
+
if options[:dry_run]
|
1128
|
+
print_dry_run @network_subnet_types_interface.dry.list(params)
|
1129
|
+
return
|
1130
|
+
end
|
1131
|
+
json_response = @network_subnet_types_interface.list(params)
|
1132
|
+
|
1133
|
+
render_result = render_with_format(json_response, options, 'subnetTypes')
|
1134
|
+
return 0 if render_result
|
1135
|
+
|
1136
|
+
subnet_types = json_response['subnetTypes']
|
1137
|
+
|
1138
|
+
title = "Morpheus Subnet Types"
|
1139
|
+
subtitles = []
|
1140
|
+
subtitles += parse_list_subtitles(options)
|
1141
|
+
if options[:cloud]
|
1142
|
+
subtitles << "Cloud: #{options[:cloud]}"
|
1143
|
+
end
|
1144
|
+
print_h1 title, subtitles
|
1145
|
+
if subnet_types.empty?
|
1146
|
+
print cyan,"No subnet types found.",reset,"\n"
|
1147
|
+
else
|
1148
|
+
rows = subnet_types.collect do |subnet_type|
|
1149
|
+
{
|
1150
|
+
id: subnet_type['id'],
|
1151
|
+
code: subnet_type['code'],
|
1152
|
+
name: subnet_type['name']
|
1153
|
+
}
|
1154
|
+
end
|
1155
|
+
columns = [:id, :name, :code]
|
1156
|
+
print cyan
|
1157
|
+
print as_pretty_table(rows, columns, options)
|
1158
|
+
print reset
|
1159
|
+
print_results_pagination(json_response)
|
1160
|
+
end
|
1161
|
+
print reset,"\n"
|
1162
|
+
return 0
|
1163
|
+
|
1040
1164
|
rescue RestClient::Exception => e
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1165
|
+
print_rest_exception(e, options)
|
1166
|
+
exit 1
|
1167
|
+
end
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
def get_subnet_type(args)
|
1171
|
+
options = {}
|
1172
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1173
|
+
opts.banner = subcommand_usage("[type]")
|
1174
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
1175
|
+
opts.footer = "Get details about a subnet type.\n" +
|
1176
|
+
"[type] is required. This is the id or name of a subnet type."
|
1177
|
+
end
|
1178
|
+
optparse.parse!(args)
|
1179
|
+
connect(options)
|
1180
|
+
begin
|
1181
|
+
params = {}
|
1182
|
+
@network_subnet_types_interface.setopts(options)
|
1183
|
+
if options[:dry_run]
|
1184
|
+
if args[0].to_s =~ /\A\d{1,}\Z/
|
1185
|
+
print_dry_run @network_subnet_types_interface.dry.get(args[0].to_i)
|
1186
|
+
else
|
1187
|
+
print_dry_run @network_subnet_types_interface.dry.list({name:args[0]})
|
1188
|
+
end
|
1189
|
+
return
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
subnet_type = find_subnet_type_by_name_or_id(args[0])
|
1193
|
+
return 1 if subnet_type.nil?
|
1194
|
+
json_response = {'subnetType' => subnet_type} # skip redundant request
|
1195
|
+
# json_response = @networks_interface.get(subnet_type['id'])
|
1196
|
+
|
1197
|
+
render_result = render_with_format(json_response, options, 'subnetType')
|
1198
|
+
return 0 if render_result
|
1199
|
+
|
1200
|
+
subnet_type = json_response['subnetType']
|
1201
|
+
|
1202
|
+
title = "Morpheus Subnet Type"
|
1203
|
+
|
1204
|
+
print_h1 "Morpheus Subnet Type", [], options
|
1205
|
+
|
1206
|
+
print cyan
|
1207
|
+
description_cols = {
|
1208
|
+
"ID" => 'id',
|
1209
|
+
"Name" => 'name',
|
1210
|
+
"Code" => 'name',
|
1211
|
+
"Description" => 'description',
|
1212
|
+
"Createable" => lambda {|it| format_boolean(it['creatable']) },
|
1213
|
+
"Deletable" => lambda {|it| format_boolean(it['deleteable']) },
|
1214
|
+
}
|
1215
|
+
print_description_list(description_cols, subnet_type)
|
1216
|
+
|
1217
|
+
|
1218
|
+
|
1219
|
+
option_types = subnet_type['optionTypes'] || []
|
1220
|
+
option_types = option_types.sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
1221
|
+
if !option_types.empty?
|
1222
|
+
print_h2 "Config Option Types", [], options
|
1223
|
+
option_type_cols = {
|
1224
|
+
"Name" => lambda {|it| it['fieldContext'].to_s != '' ? "#{it['fieldContext']}.#{it['fieldName']}" : it['fieldName'] },
|
1225
|
+
"Label" => lambda {|it| it['fieldLabel'] },
|
1226
|
+
"Type" => lambda {|it| it['type'] },
|
1227
|
+
}
|
1228
|
+
print cyan
|
1229
|
+
print as_pretty_table(option_types, option_type_cols)
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
print reset,"\n"
|
1233
|
+
return 0
|
1234
|
+
rescue RestClient::Exception => e
|
1235
|
+
print_rest_exception(e, options)
|
1236
|
+
exit 1
|
1237
|
+
end
|
1238
|
+
end
|
1239
|
+
|
1240
|
+
|
1241
|
+
def list_subnets(args)
|
1242
|
+
options = {}
|
1243
|
+
params = {}
|
1244
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1245
|
+
opts.banner = subcommand_usage("[network] [subnet]")
|
1246
|
+
build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
1247
|
+
opts.footer = "Get details about a network." + "\n" +
|
1248
|
+
"[network] is required. This is the name or id of a network."
|
1249
|
+
end
|
1250
|
+
optparse.parse!(args)
|
1251
|
+
if args.count != 1
|
1252
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
|
1253
|
+
end
|
1254
|
+
connect(options)
|
1255
|
+
begin
|
1256
|
+
network = find_network_by_name_or_id(args[0])
|
1257
|
+
return 1 if network.nil?
|
1258
|
+
|
1259
|
+
params.merge!(parse_list_options(options))
|
1260
|
+
@network_subnets_interface.setopts(options)
|
1261
|
+
if options[:dry_run]
|
1262
|
+
print_dry_run @network_subnets_interface.dry.list(network['id'], params)
|
1263
|
+
return
|
1264
|
+
end
|
1265
|
+
json_response = @network_subnets_interface.list(network['id'], params)
|
1266
|
+
subnets = json_response["subnets"]
|
1267
|
+
if options[:json]
|
1268
|
+
puts as_json(json_response, options, "subnets")
|
1269
|
+
return 0
|
1270
|
+
elsif options[:yaml]
|
1271
|
+
puts as_yaml(json_response, options, "subnets")
|
1272
|
+
return 0
|
1273
|
+
elsif options[:csv]
|
1274
|
+
puts records_as_csv(subnets, options)
|
1275
|
+
return 0
|
1276
|
+
end
|
1277
|
+
title = "Morpheus Subnets"
|
1278
|
+
subtitles = []
|
1279
|
+
subtitles << "Network: #{network['name']}"
|
1280
|
+
subtitles += parse_list_subtitles(options)
|
1281
|
+
print_h1 title, subtitles
|
1282
|
+
|
1283
|
+
if subnets.empty?
|
1284
|
+
print cyan,"No subnets found.",reset,"\n"
|
1044
1285
|
else
|
1045
|
-
|
1286
|
+
subnet_columns = {
|
1287
|
+
"ID" => 'id',
|
1288
|
+
"Name" => 'name',
|
1289
|
+
#"Description" => 'description',
|
1290
|
+
"Type" => lambda {|it| it['type']['name'] rescue it['type'] },
|
1291
|
+
"CIDR" => lambda {|it| it['cidr'] },
|
1292
|
+
"Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
|
1293
|
+
"Tenants" => lambda {|it| it['tenants'] ? it['tenants'].collect {|it| it['name'] }.uniq.join(', ') : '' }
|
1294
|
+
}
|
1295
|
+
print cyan
|
1296
|
+
print as_pretty_table(subnets, subnet_columns)
|
1046
1297
|
end
|
1298
|
+
print reset,"\n"
|
1299
|
+
return 0
|
1300
|
+
|
1301
|
+
rescue RestClient::Exception => e
|
1302
|
+
print_rest_exception(e, options)
|
1303
|
+
return 1
|
1047
1304
|
end
|
1048
1305
|
end
|
1049
1306
|
|
1050
|
-
def
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1307
|
+
def get_subnet(args)
|
1308
|
+
options = {}
|
1309
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1310
|
+
opts.banner = subcommand_usage("[network] [subnet]")
|
1311
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
1312
|
+
opts.footer = "Get details about a subnet." + "\n" +
|
1313
|
+
"[network] is required. This is the name or id of a network." + "\n" +
|
1314
|
+
"[subnet] is required. This is the name or id of a subnet."
|
1315
|
+
end
|
1316
|
+
optparse.parse!(args)
|
1317
|
+
if args.count != 2
|
1318
|
+
raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
|
1319
|
+
end
|
1320
|
+
connect(options)
|
1321
|
+
begin
|
1322
|
+
network = find_network_by_name_or_id(args[0])
|
1323
|
+
return 1 if network.nil?
|
1324
|
+
|
1325
|
+
@network_subnets_interface.setopts(options)
|
1326
|
+
if options[:dry_run]
|
1327
|
+
if args[1].to_s =~ /\A\d{1,}\Z/
|
1328
|
+
print_dry_run @network_subnets_interface.dry.get(network['id'], args[1].to_i)
|
1329
|
+
else
|
1330
|
+
print_dry_run @network_subnets_interface.dry.list(network['id'], {name:args[1]})
|
1331
|
+
end
|
1332
|
+
return
|
1061
1333
|
end
|
1062
|
-
|
1063
|
-
return nil
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
if
|
1068
|
-
|
1334
|
+
subnet = find_subnet_by_name_or_id(network['id'], args[1])
|
1335
|
+
return 1 if subnet.nil?
|
1336
|
+
json_response = {'subnet' => subnet} # skip redundant request
|
1337
|
+
# json_response = @network_subnets_interface.get(network['id'], subnet['id'])
|
1338
|
+
subnet = json_response['subnet']
|
1339
|
+
if options[:json]
|
1340
|
+
puts as_json(json_response, options, "subnet")
|
1341
|
+
return 0
|
1342
|
+
elsif options[:yaml]
|
1343
|
+
puts as_yaml(json_response, options, "subnet")
|
1344
|
+
return 0
|
1345
|
+
elsif options[:csv]
|
1346
|
+
puts records_as_csv([subnet], options)
|
1347
|
+
return 0
|
1069
1348
|
end
|
1070
|
-
|
1349
|
+
print_h1 "Subnet Details", [], options
|
1350
|
+
print cyan
|
1351
|
+
description_cols = {
|
1352
|
+
"ID" => 'id',
|
1353
|
+
"Name" => 'name',
|
1354
|
+
"Description" => 'description',
|
1355
|
+
"Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
|
1356
|
+
"Network" => lambda {|it| network['name'] },
|
1357
|
+
"Cloud" => lambda {|it| network['zone'] ? network['zone']['name'] : '' },
|
1358
|
+
"CIDR" => 'cidr',
|
1359
|
+
"Gateway" => 'gateway',
|
1360
|
+
"Netmask" => 'netmask',
|
1361
|
+
"Subnet" => 'subnetAddress',
|
1362
|
+
"Primary DNS" => 'dnsPrimary',
|
1363
|
+
"Secondary DNS" => 'dnsSecondary',
|
1364
|
+
"Pool" => lambda {|it| it['pool'] ? it['pool']['name'] : '' },
|
1365
|
+
"DHCP" => lambda {|it| format_boolean it['dhcpServer'] },
|
1366
|
+
#"Allow IP Override" => lambda {|it| it['allowStaticOverride'] ? 'Yes' : 'No' },
|
1367
|
+
"Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
|
1368
|
+
"Tenants" => lambda {|it| it['tenants'] ? it['tenants'].collect {|it| it['name'] }.uniq.join(', ') : '' },
|
1369
|
+
# "Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
|
1370
|
+
}
|
1371
|
+
print_description_list(description_cols, subnet)
|
1372
|
+
|
1373
|
+
if subnet['resourcePermission'].nil?
|
1374
|
+
print "\n", "No group access found", "\n"
|
1375
|
+
else
|
1376
|
+
print_h2 "Group Access"
|
1377
|
+
rows = []
|
1378
|
+
if subnet['resourcePermission']['all']
|
1379
|
+
rows.push({"name" => 'All'})
|
1380
|
+
end
|
1381
|
+
if subnet['resourcePermission']['sites']
|
1382
|
+
subnet['resourcePermission']['sites'].each do |site|
|
1383
|
+
rows.push(site)
|
1384
|
+
end
|
1385
|
+
end
|
1386
|
+
rows = rows.collect do |site|
|
1387
|
+
{group: site['name'], default: site['default'] ? 'Yes' : ''}
|
1388
|
+
end
|
1389
|
+
columns = [:group, :default]
|
1390
|
+
print cyan
|
1391
|
+
print as_pretty_table(rows, columns)
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
print reset,"\n"
|
1395
|
+
return 0
|
1396
|
+
rescue RestClient::Exception => e
|
1397
|
+
print_rest_exception(e, options)
|
1398
|
+
return 1
|
1399
|
+
end
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
def add_subnet(args)
|
1403
|
+
options = {}
|
1404
|
+
subnet_type_id = nil
|
1405
|
+
tenants = nil
|
1406
|
+
group_access_all = nil
|
1407
|
+
group_access_list = nil
|
1408
|
+
group_defaults_list = nil
|
1409
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1410
|
+
opts.banner = subcommand_usage("[network]")
|
1411
|
+
opts.on('-t', '--type ID', "Subnet Type Name or ID") do |val|
|
1412
|
+
subnet_type_id = val
|
1413
|
+
end
|
1414
|
+
opts.on('--name VALUE', String, "Name for this subnet") do |val|
|
1415
|
+
options[:options]['name'] = val
|
1416
|
+
end
|
1417
|
+
opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
|
1418
|
+
group_access_all = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
1419
|
+
end
|
1420
|
+
opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
|
1421
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
1422
|
+
group_access_list = []
|
1423
|
+
else
|
1424
|
+
group_access_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
1425
|
+
end
|
1426
|
+
end
|
1427
|
+
opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
|
1428
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
1429
|
+
group_defaults_list = []
|
1430
|
+
else
|
1431
|
+
group_defaults_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
1432
|
+
end
|
1433
|
+
end
|
1434
|
+
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
1435
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
1436
|
+
options['tenants'] = []
|
1437
|
+
else
|
1438
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
1439
|
+
end
|
1440
|
+
end
|
1441
|
+
opts.on('--accounts LIST', Array, "alias for --tenants") do |list|
|
1442
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
1443
|
+
options['tenants'] = []
|
1444
|
+
else
|
1445
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
1446
|
+
end
|
1447
|
+
end
|
1448
|
+
opts.on('--visibility [private|public]', String, "Visibility") do |val|
|
1449
|
+
options['visibility'] = val
|
1450
|
+
end
|
1451
|
+
# opts.on('--active [on|off]', String, "Can be used to disable a subnet") do |val|
|
1452
|
+
# options['active'] = val.to_s == 'on' || val.to_s == 'true'
|
1453
|
+
# end
|
1454
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
1455
|
+
opts.footer = "Create a new subnet." + "\n" +
|
1456
|
+
"[network] is required. This is the name or id of a network." #+ "\n" +
|
1457
|
+
#"[name] is required and can be passed as --name instead."
|
1458
|
+
end
|
1459
|
+
optparse.parse!(args)
|
1460
|
+
# if args.count < 1 || args.count > 2
|
1461
|
+
if args.count != 1
|
1462
|
+
raise_command_error "wrong number of arguments, expected 1-2 and got (#{args.count}) #{args}\n#{optparse}"
|
1463
|
+
end
|
1464
|
+
if args[1]
|
1465
|
+
options[:options]['name'] = args[1]
|
1466
|
+
end
|
1467
|
+
connect(options)
|
1468
|
+
begin
|
1469
|
+
network = find_network_by_name_or_id(args[0])
|
1470
|
+
return 1 if network.nil?
|
1471
|
+
|
1472
|
+
passed_options = (options[:options] || {}).reject {|k,v| k.is_a?(Symbol) }
|
1473
|
+
payload = nil
|
1474
|
+
if options[:payload]
|
1475
|
+
payload = options[:payload]
|
1476
|
+
payload.deep_merge!({'subnet' => passed_options}) unless passed_options.empty?
|
1477
|
+
|
1478
|
+
else
|
1479
|
+
payload = {'subnet' => {}}
|
1480
|
+
payload.deep_merge!({'subnet' => passed_options}) unless passed_options.empty?
|
1481
|
+
|
1482
|
+
# Name
|
1483
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Name for this subnet.'}], options[:options])
|
1484
|
+
# payload['subnet']['name'] = v_prompt['name']
|
1485
|
+
|
1486
|
+
# Subnet Type
|
1487
|
+
if !subnet_type_id
|
1488
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => 'Subnet Type', 'type' => 'select', 'optionSource' => 'subnetTypes', 'required' => true, 'description' => 'Choose a subnet type.'}], options[:options], @api_client, {networkId: network['id']})
|
1489
|
+
subnet_type_id = v_prompt['type']
|
1490
|
+
end
|
1491
|
+
subnet_type = find_subnet_type_by_name_or_id(subnet_type_id)
|
1492
|
+
return 1 if subnet_type.nil?
|
1493
|
+
payload['subnet']['type'] = {'id' => subnet_type['id'] }
|
1494
|
+
#payload['subnet']['type'] = {'code' => subnet_type['code'] }
|
1495
|
+
|
1496
|
+
subnet_type_option_types = subnet_type['optionTypes']
|
1497
|
+
if subnet_type_option_types && subnet_type_option_types.size > 0
|
1498
|
+
# prompt for option types
|
1499
|
+
subnet_type_params = Morpheus::Cli::OptionTypes.prompt(subnet_type_option_types,options[:options],@api_client, {networkId: network['id']})
|
1500
|
+
payload['subnet'].deep_merge!(subnet_type_params)
|
1501
|
+
|
1502
|
+
else
|
1503
|
+
# DEFAULT INPUTS
|
1504
|
+
|
1505
|
+
# CIDR
|
1506
|
+
# if options['cidr']
|
1507
|
+
# payload['subnet']['cidr'] = options['cidr']
|
1508
|
+
# else
|
1509
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cidr', 'fieldLabel' => 'CIDR', 'type' => 'text', 'required' => false, 'description' => ''}], options)
|
1510
|
+
# payload['subnet']['cidr'] = v_prompt['cidr']
|
1511
|
+
# end
|
1512
|
+
|
1513
|
+
end
|
1514
|
+
|
1515
|
+
# Group Access
|
1516
|
+
# Group Access (default is All)
|
1517
|
+
if group_access_all.nil?
|
1518
|
+
if payload['resourcePermissions'].nil?
|
1519
|
+
payload['resourcePermissions'] ||= {}
|
1520
|
+
payload['resourcePermissions']['all'] = true
|
1521
|
+
end
|
1522
|
+
else
|
1523
|
+
payload['resourcePermissions'] ||= {}
|
1524
|
+
payload['resourcePermissions']['all'] = group_access_all
|
1525
|
+
end
|
1526
|
+
if group_access_list != nil
|
1527
|
+
payload['resourcePermissions'] ||= {}
|
1528
|
+
payload['resourcePermissions']['sites'] = group_access_list.collect do |site_id|
|
1529
|
+
site = {"id" => site_id.to_i}
|
1530
|
+
if group_defaults_list && group_defaults_list.include?(site_id)
|
1531
|
+
site["default"] = true
|
1532
|
+
end
|
1533
|
+
site
|
1534
|
+
end
|
1535
|
+
end
|
1536
|
+
|
1537
|
+
# Tenants
|
1538
|
+
if options['tenants']
|
1539
|
+
payload['tenantPermissions'] = {}
|
1540
|
+
payload['tenantPermissions']['accounts'] = options['tenants']
|
1541
|
+
end
|
1542
|
+
|
1543
|
+
# Active
|
1544
|
+
if options['active'] != nil
|
1545
|
+
payload['subnet']['active'] = options['active']
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
# Visibility
|
1549
|
+
if options['visibility'] != nil
|
1550
|
+
payload['subnet']['visibility'] = options['visibility']
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
end
|
1554
|
+
|
1555
|
+
@network_subnets_interface.setopts(options)
|
1556
|
+
if options[:dry_run]
|
1557
|
+
print_dry_run @network_subnets_interface.dry.create(network['id'], payload)
|
1558
|
+
return
|
1559
|
+
end
|
1560
|
+
json_response = @network_subnets_interface.create(network['id'], payload)
|
1561
|
+
if options[:json]
|
1562
|
+
puts as_json(json_response, options)
|
1563
|
+
elsif !options[:quiet]
|
1564
|
+
subnet = json_response['subnet']
|
1565
|
+
print_green_success "Added subnet #{subnet['name']}"
|
1566
|
+
get_args = [network['id'], subnet['id']] + (options[:remote] ? ["-r",options[:remote]] : [])
|
1567
|
+
get_subnet(get_args)
|
1568
|
+
end
|
1569
|
+
return 0
|
1570
|
+
rescue RestClient::Exception => e
|
1571
|
+
print_rest_exception(e, options)
|
1572
|
+
return 1
|
1573
|
+
end
|
1574
|
+
end
|
1575
|
+
|
1576
|
+
|
1577
|
+
def update_subnet(args)
|
1578
|
+
options = {}
|
1579
|
+
tenants = nil
|
1580
|
+
group_access_all = nil
|
1581
|
+
group_access_list = nil
|
1582
|
+
group_defaults_list = nil
|
1583
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1584
|
+
opts.banner = subcommand_usage("[network] [subnet]")
|
1585
|
+
opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
|
1586
|
+
group_access_all = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
1587
|
+
end
|
1588
|
+
opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
|
1589
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
1590
|
+
group_access_list = []
|
1591
|
+
else
|
1592
|
+
group_access_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
1593
|
+
end
|
1594
|
+
end
|
1595
|
+
opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
|
1596
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
1597
|
+
group_defaults_list = []
|
1598
|
+
else
|
1599
|
+
group_defaults_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
1600
|
+
end
|
1601
|
+
end
|
1602
|
+
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
1603
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
1604
|
+
options['tenants'] = []
|
1605
|
+
else
|
1606
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
1607
|
+
end
|
1608
|
+
end
|
1609
|
+
opts.on('--accounts LIST', Array, "alias for --tenants") do |list|
|
1610
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
1611
|
+
options['tenants'] = []
|
1612
|
+
else
|
1613
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
1614
|
+
end
|
1615
|
+
end
|
1616
|
+
opts.on('--visibility [private|public]', String, "Visibility") do |val|
|
1617
|
+
options['visibility'] = val
|
1618
|
+
end
|
1619
|
+
# opts.on('--active [on|off]', String, "Can be used to disable a network") do |val|
|
1620
|
+
# options['active'] = val.to_s == 'on' || val.to_s == 'true'
|
1621
|
+
# end
|
1622
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
1623
|
+
opts.footer = "Update a subnet." + "\n" +
|
1624
|
+
"[network] is required. This is the name or id of a network." + "\n" +
|
1625
|
+
"[subnet] is required. This is the name or id of a subnet."
|
1626
|
+
end
|
1627
|
+
optparse.parse!(args)
|
1628
|
+
if args.count != 2
|
1629
|
+
raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
|
1630
|
+
end
|
1631
|
+
connect(options)
|
1632
|
+
begin
|
1633
|
+
network = find_network_by_name_or_id(args[0])
|
1634
|
+
return 1 if network.nil?
|
1635
|
+
|
1636
|
+
subnet = find_subnet_by_name_or_id(network['id'], args[1])
|
1637
|
+
return 1 if subnet.nil?
|
1638
|
+
|
1639
|
+
# merge -O options into normally parsed options
|
1640
|
+
options.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
1641
|
+
|
1642
|
+
# construct payload
|
1643
|
+
payload = nil
|
1644
|
+
if options[:payload]
|
1645
|
+
payload = options[:payload]
|
1646
|
+
else
|
1647
|
+
# prompt for network options
|
1648
|
+
payload = {
|
1649
|
+
'subnet' => {
|
1650
|
+
}
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
# allow arbitrary -O options
|
1654
|
+
payload['subnet'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
1655
|
+
|
1656
|
+
# Group Access
|
1657
|
+
if group_access_all != nil
|
1658
|
+
payload['resourcePermissions'] ||= {}
|
1659
|
+
payload['resourcePermissions']['all'] = group_access_all
|
1660
|
+
end
|
1661
|
+
if group_access_list != nil
|
1662
|
+
payload['resourcePermissions'] ||= {}
|
1663
|
+
payload['resourcePermissions']['sites'] = group_access_list.collect do |site_id|
|
1664
|
+
site = {"id" => site_id.to_i}
|
1665
|
+
if group_defaults_list && group_defaults_list.include?(site_id)
|
1666
|
+
site["default"] = true
|
1667
|
+
end
|
1668
|
+
site
|
1669
|
+
end
|
1670
|
+
end
|
1671
|
+
|
1672
|
+
# Tenants
|
1673
|
+
if options['tenants']
|
1674
|
+
payload['tenantPermissions'] = {}
|
1675
|
+
payload['tenantPermissions']['accounts'] = options['tenants']
|
1676
|
+
end
|
1677
|
+
|
1678
|
+
# Active
|
1679
|
+
if options['active'] != nil
|
1680
|
+
payload['subnet']['active'] = options['active']
|
1681
|
+
end
|
1682
|
+
|
1683
|
+
# Visibility
|
1684
|
+
if options['visibility'] != nil
|
1685
|
+
payload['subnet']['visibility'] = options['visibility']
|
1686
|
+
end
|
1687
|
+
|
1688
|
+
end
|
1689
|
+
|
1690
|
+
@network_subnets_interface.setopts(options)
|
1691
|
+
if options[:dry_run]
|
1692
|
+
print_dry_run @network_subnets_interface.dry.update(network['id'], subnet['id'], payload)
|
1693
|
+
return
|
1694
|
+
end
|
1695
|
+
json_response = @network_subnets_interface.update(network['id'], subnet['id'], payload)
|
1696
|
+
if options[:json]
|
1697
|
+
puts as_json(json_response, options)
|
1698
|
+
elsif !options[:quiet]
|
1699
|
+
subnet = json_response['subnet']
|
1700
|
+
print_green_success "Updated subnet #{subnet['name']}"
|
1701
|
+
get_args = [network['id'], subnet['id']] + (options[:remote] ? ["-r",options[:remote]] : [])
|
1702
|
+
get_subnet(get_args)
|
1703
|
+
end
|
1704
|
+
return 0
|
1705
|
+
rescue RestClient::Exception => e
|
1706
|
+
print_rest_exception(e, options)
|
1707
|
+
return 1
|
1708
|
+
end
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
def remove_subnet(args)
|
1712
|
+
options = {}
|
1713
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1714
|
+
opts.banner = subcommand_usage("[network] [subnet]")
|
1715
|
+
build_common_options(opts, options, [:account, :auto_confirm, :json, :dry_run, :remote])
|
1716
|
+
opts.footer = "Delete a subnet." + "\n" +
|
1717
|
+
"[network] is required. This is the name or id of a network." + "\n" +
|
1718
|
+
"[subnet] is required. This is the name or id of a subnet."
|
1719
|
+
end
|
1720
|
+
optparse.parse!(args)
|
1721
|
+
if args.count != 2
|
1722
|
+
raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
|
1723
|
+
end
|
1724
|
+
connect(options)
|
1725
|
+
begin
|
1726
|
+
network = find_network_by_name_or_id(args[0])
|
1727
|
+
return 1 if network.nil?
|
1728
|
+
|
1729
|
+
subnet = find_subnet_by_name_or_id(network['id'], args[1])
|
1730
|
+
return 1 if subnet.nil?
|
1731
|
+
|
1732
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the subnet: #{subnet['name']}?")
|
1733
|
+
return 9, "aborted command"
|
1734
|
+
end
|
1735
|
+
@network_subnets_interface.setopts(options)
|
1736
|
+
if options[:dry_run]
|
1737
|
+
print_dry_run @network_subnets_interface.dry.destroy(network['id'], subnet['id'])
|
1738
|
+
return 0
|
1739
|
+
end
|
1740
|
+
json_response = @network_subnets_interface.destroy(network['id'], subnet['id'])
|
1741
|
+
if options[:json]
|
1742
|
+
puts as_json(json_response, options)
|
1743
|
+
else
|
1744
|
+
print_green_success "Removed subnet #{subnet['name']}"
|
1745
|
+
end
|
1746
|
+
return 0
|
1747
|
+
rescue RestClient::Exception => e
|
1748
|
+
print_rest_exception(e, options)
|
1749
|
+
return 1
|
1750
|
+
end
|
1751
|
+
end
|
1752
|
+
|
1753
|
+
private
|
1754
|
+
|
1755
|
+
|
1756
|
+
def find_network_by_name_or_id(val)
|
1757
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
1758
|
+
return find_network_by_id(val)
|
1759
|
+
else
|
1760
|
+
return find_network_by_name(val)
|
1761
|
+
end
|
1762
|
+
end
|
1763
|
+
|
1764
|
+
def find_network_by_id(id)
|
1765
|
+
begin
|
1766
|
+
json_response = @networks_interface.get(id.to_i)
|
1767
|
+
return json_response['network']
|
1768
|
+
rescue RestClient::Exception => e
|
1769
|
+
if e.response && e.response.code == 404
|
1770
|
+
print_red_alert "Network not found by id #{id}"
|
1771
|
+
return nil
|
1772
|
+
else
|
1773
|
+
raise e
|
1774
|
+
end
|
1775
|
+
end
|
1776
|
+
end
|
1777
|
+
|
1778
|
+
def find_network_by_name(name)
|
1779
|
+
json_response = @networks_interface.list({name: name.to_s})
|
1780
|
+
networks = json_response['networks']
|
1781
|
+
if networks.empty?
|
1782
|
+
print_red_alert "Network not found by name #{name}"
|
1783
|
+
return nil
|
1784
|
+
elsif networks.size > 1
|
1785
|
+
print_red_alert "#{networks.size} networks found by name #{name}"
|
1786
|
+
rows = networks.collect do |it|
|
1787
|
+
{id: it['id'], name: it['name']}
|
1788
|
+
end
|
1789
|
+
puts as_pretty_table(rows, [:id, :name], {color:red})
|
1790
|
+
return nil
|
1791
|
+
else
|
1792
|
+
network = networks[0]
|
1793
|
+
# merge in tenants map
|
1794
|
+
if json_response['tenants'] && json_response['tenants'][network['id']]
|
1795
|
+
network['tenants'] = json_response['tenants'][network['id']]
|
1796
|
+
end
|
1797
|
+
return network
|
1798
|
+
end
|
1799
|
+
end
|
1800
|
+
|
1801
|
+
def find_network_type_by_name_or_id(val)
|
1802
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
1803
|
+
return find_network_type_by_id(val)
|
1804
|
+
else
|
1805
|
+
return find_network_type_by_name(val)
|
1806
|
+
end
|
1807
|
+
end
|
1808
|
+
|
1809
|
+
def find_network_type_by_id(id)
|
1810
|
+
begin
|
1811
|
+
json_response = @network_types_interface.get(id.to_i)
|
1812
|
+
return json_response['networkType']
|
1813
|
+
rescue RestClient::Exception => e
|
1814
|
+
if e.response && e.response.code == 404
|
1815
|
+
print_red_alert "Network Type not found by id #{id}"
|
1816
|
+
return nil
|
1817
|
+
else
|
1818
|
+
raise e
|
1819
|
+
end
|
1820
|
+
end
|
1821
|
+
end
|
1822
|
+
|
1823
|
+
def find_network_type_by_name(name)
|
1824
|
+
json_response = @network_types_interface.list({name: name.to_s})
|
1825
|
+
network_types = json_response['networkTypes']
|
1826
|
+
if network_types.empty?
|
1827
|
+
print_red_alert "Network Type not found by name #{name}"
|
1828
|
+
return network_types
|
1829
|
+
elsif network_types.size > 1
|
1830
|
+
print_red_alert "#{network_types.size} network types found by name #{name}"
|
1831
|
+
rows = network_types.collect do |it|
|
1832
|
+
{id: it['id'], name: it['name']}
|
1833
|
+
end
|
1834
|
+
puts as_pretty_table(rows, [:id, :name], {color:red})
|
1835
|
+
return nil
|
1836
|
+
else
|
1837
|
+
return network_types[0]
|
1838
|
+
end
|
1839
|
+
end
|
1840
|
+
|
1841
|
+
def find_subnet_by_name_or_id(network_id, val)
|
1842
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
1843
|
+
return find_subnet_by_id(network_id, val)
|
1844
|
+
else
|
1845
|
+
return find_subnet_by_name(network_id, val)
|
1846
|
+
end
|
1847
|
+
end
|
1848
|
+
|
1849
|
+
def find_subnet_by_id(network_id, id)
|
1850
|
+
begin
|
1851
|
+
json_response = @network_subnets_interface.get(network_id, id.to_i)
|
1852
|
+
return json_response['subnet']
|
1853
|
+
rescue RestClient::Exception => e
|
1854
|
+
if e.response && e.response.code == 404
|
1855
|
+
print_red_alert "Subnet not found by id #{id}"
|
1856
|
+
return nil
|
1857
|
+
else
|
1858
|
+
raise e
|
1859
|
+
end
|
1860
|
+
end
|
1861
|
+
end
|
1862
|
+
|
1863
|
+
def find_subnet_by_name(network_id, name)
|
1864
|
+
json_response = @network_subnets_interface.list(network_id, {name: name.to_s})
|
1865
|
+
subnets = json_response['subnets']
|
1866
|
+
if subnets.empty?
|
1867
|
+
print_red_alert "Subnet not found by name #{name}"
|
1868
|
+
return nil
|
1869
|
+
elsif subnets.size > 1
|
1870
|
+
print_red_alert "#{subnets.size} subnets found by name #{name}"
|
1871
|
+
rows = subnets.collect do |it|
|
1872
|
+
{id: it['id'], name: it['name']}
|
1873
|
+
end
|
1874
|
+
puts as_pretty_table(rows, [:id, :name], {color:red})
|
1875
|
+
return nil
|
1876
|
+
else
|
1877
|
+
return subnets[0]
|
1878
|
+
end
|
1879
|
+
end
|
1880
|
+
|
1881
|
+
def find_subnet_type_by_name_or_id(val)
|
1882
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
1883
|
+
return find_subnet_type_by_id(val)
|
1884
|
+
else
|
1885
|
+
return find_subnet_type_by_name(val)
|
1886
|
+
end
|
1887
|
+
end
|
1888
|
+
|
1889
|
+
def find_subnet_type_by_id(id)
|
1890
|
+
begin
|
1891
|
+
json_response = @network_subnet_types_interface.get(id.to_i)
|
1892
|
+
return json_response['subnetType']
|
1893
|
+
rescue RestClient::Exception => e
|
1894
|
+
if e.response && e.response.code == 404
|
1895
|
+
print_red_alert "Subnet Type not found by id #{id}"
|
1896
|
+
return nil
|
1897
|
+
else
|
1898
|
+
raise e
|
1899
|
+
end
|
1900
|
+
end
|
1901
|
+
end
|
1902
|
+
|
1903
|
+
def find_subnet_type_by_name(name)
|
1904
|
+
json_response = @network_subnet_types_interface.list({name: name.to_s})
|
1905
|
+
subnet_types = json_response['subnetTypes']
|
1906
|
+
if subnet_types.empty?
|
1907
|
+
print_red_alert "Subnet Type not found by name #{name}"
|
1908
|
+
return subnet_types
|
1909
|
+
elsif subnet_types.size > 1
|
1910
|
+
print_red_alert "#{subnet_types.size} subnet types found by name #{name}"
|
1911
|
+
rows = subnet_types.collect do |it|
|
1912
|
+
{id: it['id'], name: it['name']}
|
1913
|
+
end
|
1914
|
+
puts as_pretty_table(rows, [:id, :name], {color:red})
|
1915
|
+
return nil
|
1916
|
+
else
|
1917
|
+
return subnet_types[0]
|
1071
1918
|
end
|
1072
1919
|
end
|
1073
1920
|
|