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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api.rb +10 -0
  3. data/lib/morpheus/api/api_client.rb +24 -3
  4. data/lib/morpheus/api/clouds_interface.rb +15 -0
  5. data/lib/morpheus/api/clusters_interface.rb +276 -0
  6. data/lib/morpheus/api/library_compute_type_layouts_interface.rb +26 -0
  7. data/lib/morpheus/api/logs_interface.rb +6 -0
  8. data/lib/morpheus/api/network_subnet_types_interface.rb +26 -0
  9. data/lib/morpheus/api/network_subnets_interface.rb +47 -0
  10. data/lib/morpheus/api/provision_types_interface.rb +6 -0
  11. data/lib/morpheus/api/security_groups_interface.rb +12 -3
  12. data/lib/morpheus/api/servers_interface.rb +15 -0
  13. data/lib/morpheus/api/service_plans_interface.rb +30 -0
  14. data/lib/morpheus/api/subnets_interface.rb +47 -0
  15. data/lib/morpheus/cli.rb +1 -0
  16. data/lib/morpheus/cli/apps.rb +20 -18
  17. data/lib/morpheus/cli/cli_command.rb +5 -1
  18. data/lib/morpheus/cli/clusters.rb +3952 -0
  19. data/lib/morpheus/cli/containers_command.rb +70 -2
  20. data/lib/morpheus/cli/hosts.rb +69 -53
  21. data/lib/morpheus/cli/instances.rb +33 -33
  22. data/lib/morpheus/cli/library_container_types_command.rb +2 -1
  23. data/lib/morpheus/cli/library_option_lists_command.rb +13 -8
  24. data/lib/morpheus/cli/mixins/accounts_helper.rb +43 -0
  25. data/lib/morpheus/cli/mixins/print_helper.rb +10 -2
  26. data/lib/morpheus/cli/mixins/provisioning_helper.rb +53 -3
  27. data/lib/morpheus/cli/networks_command.rb +883 -36
  28. data/lib/morpheus/cli/option_types.rb +37 -14
  29. data/lib/morpheus/cli/roles.rb +78 -77
  30. data/lib/morpheus/cli/user_settings_command.rb +34 -5
  31. data/lib/morpheus/cli/version.rb +1 -1
  32. 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] ||= [:memory, :storage, :cpu]
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 = (stats['usedCpu'] || stats['cpuUsage'])
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..why the heck is this even needed?
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 => false}))
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
- get([network['id']])
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
- get([network['id']])
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 host types."
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 network Types"
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
- private
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
- def find_network_by_name_or_id(val)
1029
- if val.to_s =~ /\A\d{1,}\Z/
1030
- return find_network_by_id(val)
1031
- else
1032
- return find_network_by_name(val)
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 find_network_by_id(id)
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
- json_response = @networks_interface.get(id.to_i)
1039
- return json_response['network']
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
- if e.response && e.response.code == 404
1042
- print_red_alert "Network not found by id #{id}"
1043
- return nil
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
- raise e
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 find_network_by_name(name)
1051
- json_response = @networks_interface.list({name: name.to_s})
1052
- networks = json_response['networks']
1053
- if networks.empty?
1054
- print_red_alert "Network not found by name #{name}"
1055
- return nil
1056
- elsif networks.size > 1
1057
- print_red_alert "#{networks.size} networks found by name #{name}"
1058
- # print_networks_table(networks, {color: red})
1059
- rows = networks.collect do |it|
1060
- {id: it['id'], name: it['name']}
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
- puts as_pretty_table(rows, [:id, :name], {color:red})
1063
- return nil
1064
- else
1065
- network = networks[0]
1066
- # merge in tenants map
1067
- if json_response['tenants'] && json_response['tenants'][network['id']]
1068
- network['tenants'] = json_response['tenants'][network['id']]
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
- return network
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