morpheus-cli 4.1.5 → 4.1.6
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/api_client.rb +4 -4
- data/lib/morpheus/api/network_subnets_interface.rb +1 -0
- data/lib/morpheus/api/security_groups_interface.rb +1 -1
- data/lib/morpheus/api/{network_subnet_types_interface.rb → subnet_types_interface.rb} +3 -3
- data/lib/morpheus/api/subnets_interface.rb +1 -1
- data/lib/morpheus/cli/appliance_settings_command.rb +1 -3
- data/lib/morpheus/cli/cli_command.rb +4 -0
- data/lib/morpheus/cli/credentials.rb +4 -5
- data/lib/morpheus/cli/error_handler.rb +8 -8
- data/lib/morpheus/cli/groups.rb +1 -1
- data/lib/morpheus/cli/license.rb +6 -12
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +375 -0
- data/lib/morpheus/cli/monitoring_alerts_command.rb +0 -2
- data/lib/morpheus/cli/network_groups_command.rb +116 -75
- data/lib/morpheus/cli/networks_command.rb +65 -767
- data/lib/morpheus/cli/remote.rb +1 -2
- data/lib/morpheus/cli/security_groups.rb +26 -33
- data/lib/morpheus/cli/shell.rb +12 -16
- data/lib/morpheus/cli/subnets_command.rb +708 -0
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +1 -3
- data/lib/morpheus/cli.rb +1 -0
- data/lib/morpheus/terminal.rb +1 -2
- metadata +4 -3
@@ -0,0 +1,708 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'optparse'
|
3
|
+
require 'filesize'
|
4
|
+
require 'morpheus/cli/cli_command'
|
5
|
+
require 'morpheus/cli/mixins/infrastructure_helper'
|
6
|
+
|
7
|
+
class Morpheus::Cli::SubnetsCommand
|
8
|
+
include Morpheus::Cli::CliCommand
|
9
|
+
include Morpheus::Cli::InfrastructureHelper
|
10
|
+
|
11
|
+
set_command_name :subnets
|
12
|
+
|
13
|
+
register_subcommands :list, :get, :add, :update, :remove
|
14
|
+
# register_subcommands :'types' => :list_subnet_types
|
15
|
+
register_subcommands :'types' => :list_subnet_types
|
16
|
+
register_subcommands :'get-type' => :get_subnet_type
|
17
|
+
|
18
|
+
# set_default_subcommand :list
|
19
|
+
|
20
|
+
def initialize()
|
21
|
+
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
22
|
+
end
|
23
|
+
|
24
|
+
def connect(opts)
|
25
|
+
@api_client = establish_remote_appliance_connection(opts)
|
26
|
+
@networks_interface = @api_client.networks
|
27
|
+
@network_types_interface = @api_client.network_types
|
28
|
+
@subnets_interface = @api_client.subnets
|
29
|
+
@subnet_types_interface = @api_client.subnet_types
|
30
|
+
@clouds_interface = @api_client.clouds
|
31
|
+
@options_interface = @api_client.options
|
32
|
+
end
|
33
|
+
|
34
|
+
def handle(args)
|
35
|
+
handle_subcommand(args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def list(args)
|
39
|
+
options = {}
|
40
|
+
params = {}
|
41
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
42
|
+
opts.banner = subcommand_usage("")
|
43
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
44
|
+
opts.on( '--network NETWORK', '--network NETWORK', "Filter results to a specific network" ) do |val|
|
45
|
+
options[:network] = val
|
46
|
+
end
|
47
|
+
opts.footer = "List subnets."
|
48
|
+
end
|
49
|
+
optparse.parse!(args)
|
50
|
+
if args.count > 0
|
51
|
+
raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
|
52
|
+
end
|
53
|
+
connect(options)
|
54
|
+
|
55
|
+
params.merge!(parse_list_options(options))
|
56
|
+
network = nil
|
57
|
+
if options[:network]
|
58
|
+
network = find_network_by_name_or_id(options[:network])
|
59
|
+
if network
|
60
|
+
params['networkId'] = network['id']
|
61
|
+
else
|
62
|
+
return 1, "Network not found"
|
63
|
+
end
|
64
|
+
# params['networksId'] = params.delete('networkId')
|
65
|
+
end
|
66
|
+
|
67
|
+
exit_code, err = 0, nil
|
68
|
+
|
69
|
+
@subnets_interface.setopts(options)
|
70
|
+
if options[:dry_run]
|
71
|
+
print_dry_run @subnets_interface.dry.list(params)
|
72
|
+
return exit_code, err
|
73
|
+
end
|
74
|
+
json_response = @subnets_interface.list(params)
|
75
|
+
subnets = json_response["subnets"]
|
76
|
+
|
77
|
+
render_result = render_with_format(json_response, options, 'subnets')
|
78
|
+
return exit_code, err if render_result
|
79
|
+
|
80
|
+
title = "Morpheus Subnets"
|
81
|
+
subtitles = []
|
82
|
+
if network
|
83
|
+
subtitles << "Network: #{network['name']}"
|
84
|
+
end
|
85
|
+
subtitles += parse_list_subtitles(options)
|
86
|
+
print_h1 title, subtitles
|
87
|
+
|
88
|
+
if subnets.empty?
|
89
|
+
print cyan,"No subnets found.",reset,"\n"
|
90
|
+
else
|
91
|
+
subnet_columns = {
|
92
|
+
"ID" => 'id',
|
93
|
+
"Name" => 'name',
|
94
|
+
#"Description" => 'description',
|
95
|
+
"Network" => lambda {|it| it['network']['name'] rescue it['network'] },
|
96
|
+
"Type" => lambda {|it| it['type']['name'] rescue it['type'] },
|
97
|
+
"Cloud" => lambda {|it| it['zone']['name'] rescue it['zone'] },
|
98
|
+
"CIDR" => lambda {|it| it['cidr'] },
|
99
|
+
"DHCP" => lambda {|it| format_boolean(it['dhcpServer']) },
|
100
|
+
"Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
|
101
|
+
"Tenants" => lambda {|it| it['tenants'] ? it['tenants'].collect {|it| it['name'] }.uniq.join(', ') : '' }
|
102
|
+
}
|
103
|
+
print cyan
|
104
|
+
print as_pretty_table(subnets, subnet_columns)
|
105
|
+
print_results_pagination(json_response, {:label => "subnet", :n_label => "subnets"})
|
106
|
+
end
|
107
|
+
print reset,"\n"
|
108
|
+
return exit_code, err
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
def get(args)
|
114
|
+
options = {}
|
115
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
116
|
+
opts.banner = subcommand_usage("[network] [subnet]")
|
117
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
118
|
+
opts.footer = "Get details about a subnet." + "\n" +
|
119
|
+
"[subnet] is required. This is the name or id of a subnet."
|
120
|
+
end
|
121
|
+
optparse.parse!(args)
|
122
|
+
if args.count != 1
|
123
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
|
124
|
+
end
|
125
|
+
connect(options)
|
126
|
+
begin
|
127
|
+
subnet_id = nil
|
128
|
+
if args[0].to_s =~ /\A\d{1,}\Z/
|
129
|
+
subnet_id = args[0].to_i
|
130
|
+
else
|
131
|
+
subnet = find_subnet_by_name(args[0])
|
132
|
+
return 1, "Security Group not found" if subnet.nil?
|
133
|
+
subnet_id = subnet['id']
|
134
|
+
end
|
135
|
+
@subnets_interface.setopts(options)
|
136
|
+
if options[:dry_run]
|
137
|
+
print_dry_run @subnets_interface.dry.get(subnet_id)
|
138
|
+
return exit_code, err
|
139
|
+
end
|
140
|
+
json_response = @subnets_interface.get(subnet_id)
|
141
|
+
render_result = render_with_format(json_response, options, 'subnet')
|
142
|
+
return exit_code, err if render_result
|
143
|
+
|
144
|
+
subnet = json_response['subnet']
|
145
|
+
if options[:json]
|
146
|
+
puts as_json(json_response, options, "subnet")
|
147
|
+
return 0
|
148
|
+
elsif options[:yaml]
|
149
|
+
puts as_yaml(json_response, options, "subnet")
|
150
|
+
return 0
|
151
|
+
elsif options[:csv]
|
152
|
+
puts records_as_csv([subnet], options)
|
153
|
+
return 0
|
154
|
+
end
|
155
|
+
print_h1 "Subnet Details", [], options
|
156
|
+
print cyan
|
157
|
+
description_cols = {
|
158
|
+
"ID" => 'id',
|
159
|
+
"Name" => 'name',
|
160
|
+
"Description" => 'description',
|
161
|
+
"Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
|
162
|
+
"Network" => lambda {|it| subnet['network']['name'] rescue subnet['network'] },
|
163
|
+
"Cloud" => lambda {|it| subnet['zone']['name'] rescue subnet['zone'] },
|
164
|
+
"CIDR" => 'cidr',
|
165
|
+
"Gateway" => 'gateway',
|
166
|
+
"Netmask" => 'netmask',
|
167
|
+
"Subnet" => 'subnetAddress',
|
168
|
+
"Primary DNS" => 'dnsPrimary',
|
169
|
+
"Secondary DNS" => 'dnsSecondary',
|
170
|
+
"Pool" => lambda {|it| it['pool'] ? it['pool']['name'] : '' },
|
171
|
+
"DHCP" => lambda {|it| format_boolean it['dhcpServer'] },
|
172
|
+
#"Allow IP Override" => lambda {|it| it['allowStaticOverride'] ? 'Yes' : 'No' },
|
173
|
+
"Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
|
174
|
+
"Tenants" => lambda {|it| it['tenants'] ? it['tenants'].collect {|it| it['name'] }.uniq.join(', ') : '' },
|
175
|
+
# "Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
|
176
|
+
}
|
177
|
+
print_description_list(description_cols, subnet)
|
178
|
+
|
179
|
+
if subnet['resourcePermission'].nil?
|
180
|
+
print "\n", "No group access found", "\n"
|
181
|
+
else
|
182
|
+
print_h2 "Group Access"
|
183
|
+
rows = []
|
184
|
+
if subnet['resourcePermission']['all']
|
185
|
+
rows.push({"name" => 'All'})
|
186
|
+
end
|
187
|
+
if subnet['resourcePermission']['sites']
|
188
|
+
subnet['resourcePermission']['sites'].each do |site|
|
189
|
+
rows.push(site)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
rows = rows.collect do |site|
|
193
|
+
{group: site['name'], default: site['default'] ? 'Yes' : ''}
|
194
|
+
end
|
195
|
+
columns = [:group, :default]
|
196
|
+
print cyan
|
197
|
+
print as_pretty_table(rows, columns)
|
198
|
+
end
|
199
|
+
|
200
|
+
print reset,"\n"
|
201
|
+
return 0
|
202
|
+
rescue RestClient::Exception => e
|
203
|
+
print_rest_exception(e, options)
|
204
|
+
return 1
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def add(args)
|
209
|
+
options = {}
|
210
|
+
network_id = nil
|
211
|
+
subnet_type_id = nil
|
212
|
+
tenants = nil
|
213
|
+
group_access_all = nil
|
214
|
+
group_access_list = nil
|
215
|
+
group_defaults_list = nil
|
216
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
217
|
+
opts.banner = subcommand_usage("[name] --network NETWORK")
|
218
|
+
opts.on('--network NETWORK', String, "Network name or ID that this subnet will be a part of.") do |val|
|
219
|
+
network_id = val
|
220
|
+
end
|
221
|
+
opts.on('-t', '--type ID', "Subnet Type Name or ID") do |val|
|
222
|
+
subnet_type_id = val
|
223
|
+
end
|
224
|
+
opts.on('--name VALUE', String, "Name for this subnet") do |val|
|
225
|
+
options[:options]['name'] = val
|
226
|
+
# fill in silly names that vary by type
|
227
|
+
options[:options].deep_merge!({'config' => {'subnetName' => val}})
|
228
|
+
end
|
229
|
+
opts.on('--cidr VALUE', String, "Name for this subnet") do |val|
|
230
|
+
options[:options]['cidr'] = val
|
231
|
+
# fill in silly names that vary by type
|
232
|
+
options[:options].deep_merge!({'config' => {'subnetCidr' => val}})
|
233
|
+
end
|
234
|
+
opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
|
235
|
+
group_access_all = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
236
|
+
end
|
237
|
+
opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
|
238
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
239
|
+
group_access_list = []
|
240
|
+
else
|
241
|
+
group_access_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
242
|
+
end
|
243
|
+
end
|
244
|
+
opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
|
245
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
246
|
+
group_defaults_list = []
|
247
|
+
else
|
248
|
+
group_defaults_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
249
|
+
end
|
250
|
+
end
|
251
|
+
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
252
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
253
|
+
options['tenants'] = []
|
254
|
+
else
|
255
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
256
|
+
end
|
257
|
+
end
|
258
|
+
opts.on('--accounts LIST', Array, "alias for --tenants") do |list|
|
259
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
260
|
+
options['tenants'] = []
|
261
|
+
else
|
262
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
263
|
+
end
|
264
|
+
end
|
265
|
+
opts.on('--visibility [private|public]', String, "Visibility") do |val|
|
266
|
+
options['visibility'] = val
|
267
|
+
end
|
268
|
+
# opts.on('--active [on|off]', String, "Can be used to disable a subnet") do |val|
|
269
|
+
# options['active'] = val.to_s == 'on' || val.to_s == 'true'
|
270
|
+
# end
|
271
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
272
|
+
opts.footer = "Create a new subnet." + "\n" +
|
273
|
+
"--network is required. This is the name or id of a network." #+ "\n" +
|
274
|
+
#"[name] is required and can be passed as --name instead."
|
275
|
+
end
|
276
|
+
optparse.parse!(args)
|
277
|
+
# if args.count < 1 || args.count > 2
|
278
|
+
if args.count > 1
|
279
|
+
raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args}\n#{optparse}"
|
280
|
+
end
|
281
|
+
if args[1]
|
282
|
+
options[:options]['name'] = args[1]
|
283
|
+
end
|
284
|
+
connect(options)
|
285
|
+
begin
|
286
|
+
passed_options = (options[:options] || {}).reject {|k,v| k.is_a?(Symbol) }
|
287
|
+
payload = nil
|
288
|
+
if options[:payload]
|
289
|
+
payload = options[:payload]
|
290
|
+
payload.deep_merge!({'subnet' => passed_options}) unless passed_options.empty?
|
291
|
+
|
292
|
+
else
|
293
|
+
payload = {'subnet' => {}}
|
294
|
+
payload.deep_merge!({'subnet' => passed_options}) unless passed_options.empty?
|
295
|
+
|
296
|
+
# Network
|
297
|
+
prompt_results = prompt_for_network(network_id, options)
|
298
|
+
if prompt_results[:success]
|
299
|
+
network = prompt_results[:network]
|
300
|
+
else
|
301
|
+
return 1, "Network prompt failed."
|
302
|
+
end
|
303
|
+
|
304
|
+
# Name
|
305
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Name for this subnet.'}], options[:options])
|
306
|
+
# payload['subnet']['name'] = v_prompt['name']
|
307
|
+
|
308
|
+
# Subnet Type
|
309
|
+
if !subnet_type_id
|
310
|
+
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']})
|
311
|
+
subnet_type_id = v_prompt['type']
|
312
|
+
end
|
313
|
+
subnet_type = find_subnet_type_by_name_or_id(subnet_type_id)
|
314
|
+
return 1 if subnet_type.nil?
|
315
|
+
payload['subnet']['type'] = {'id' => subnet_type['id'] }
|
316
|
+
#payload['subnet']['type'] = {'code' => subnet_type['code'] }
|
317
|
+
|
318
|
+
subnet_type_option_types = subnet_type['optionTypes']
|
319
|
+
if subnet_type_option_types && subnet_type_option_types.size > 0
|
320
|
+
# prompt for option types
|
321
|
+
subnet_type_params = Morpheus::Cli::OptionTypes.prompt(subnet_type_option_types,options[:options],@api_client, {networkId: network['id']})
|
322
|
+
payload['subnet'].deep_merge!(subnet_type_params)
|
323
|
+
|
324
|
+
else
|
325
|
+
# DEFAULT INPUTS
|
326
|
+
|
327
|
+
# CIDR
|
328
|
+
# if options['cidr']
|
329
|
+
# payload['subnet']['cidr'] = options['cidr']
|
330
|
+
# else
|
331
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cidr', 'fieldLabel' => 'CIDR', 'type' => 'text', 'required' => false, 'description' => ''}], options)
|
332
|
+
# payload['subnet']['cidr'] = v_prompt['cidr']
|
333
|
+
# end
|
334
|
+
|
335
|
+
end
|
336
|
+
|
337
|
+
# Group Access
|
338
|
+
# Group Access (default is All)
|
339
|
+
if group_access_all.nil?
|
340
|
+
if payload['resourcePermissions'].nil?
|
341
|
+
payload['resourcePermissions'] ||= {}
|
342
|
+
payload['resourcePermissions']['all'] = true
|
343
|
+
end
|
344
|
+
else
|
345
|
+
payload['resourcePermissions'] ||= {}
|
346
|
+
payload['resourcePermissions']['all'] = group_access_all
|
347
|
+
end
|
348
|
+
if group_access_list != nil
|
349
|
+
payload['resourcePermissions'] ||= {}
|
350
|
+
payload['resourcePermissions']['sites'] = group_access_list.collect do |site_id|
|
351
|
+
site = {"id" => site_id.to_i}
|
352
|
+
if group_defaults_list && group_defaults_list.include?(site_id)
|
353
|
+
site["default"] = true
|
354
|
+
end
|
355
|
+
site
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Tenants
|
360
|
+
if options['tenants']
|
361
|
+
payload['tenantPermissions'] = {}
|
362
|
+
payload['tenantPermissions']['accounts'] = options['tenants']
|
363
|
+
end
|
364
|
+
|
365
|
+
# Active
|
366
|
+
if options['active'] != nil
|
367
|
+
payload['subnet']['active'] = options['active']
|
368
|
+
end
|
369
|
+
|
370
|
+
# Visibility
|
371
|
+
if options['visibility'] != nil
|
372
|
+
payload['subnet']['visibility'] = options['visibility']
|
373
|
+
end
|
374
|
+
|
375
|
+
end
|
376
|
+
|
377
|
+
@subnets_interface.setopts(options)
|
378
|
+
if options[:dry_run]
|
379
|
+
print_dry_run @subnets_interface.dry.create(network['id'], payload)
|
380
|
+
return
|
381
|
+
end
|
382
|
+
json_response = @subnets_interface.create(network['id'], payload)
|
383
|
+
if options[:json]
|
384
|
+
puts as_json(json_response, options)
|
385
|
+
elsif !options[:quiet]
|
386
|
+
subnet = json_response['subnet']
|
387
|
+
print_green_success "Added subnet #{subnet['name']}"
|
388
|
+
get_args = [network['id'], subnet['id']] + (options[:remote] ? ["-r",options[:remote]] : [])
|
389
|
+
get(get_args)
|
390
|
+
end
|
391
|
+
return 0
|
392
|
+
rescue RestClient::Exception => e
|
393
|
+
print_rest_exception(e, options)
|
394
|
+
return 1
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
|
399
|
+
def update(args)
|
400
|
+
options = {}
|
401
|
+
tenants = nil
|
402
|
+
group_access_all = nil
|
403
|
+
group_access_list = nil
|
404
|
+
group_defaults_list = nil
|
405
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
406
|
+
opts.banner = subcommand_usage("[subnet]")
|
407
|
+
opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
|
408
|
+
group_access_all = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
409
|
+
end
|
410
|
+
opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
|
411
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
412
|
+
group_access_list = []
|
413
|
+
else
|
414
|
+
group_access_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
415
|
+
end
|
416
|
+
end
|
417
|
+
opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
|
418
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
419
|
+
group_defaults_list = []
|
420
|
+
else
|
421
|
+
group_defaults_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
422
|
+
end
|
423
|
+
end
|
424
|
+
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
425
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
426
|
+
options['tenants'] = []
|
427
|
+
else
|
428
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
429
|
+
end
|
430
|
+
end
|
431
|
+
opts.on('--accounts LIST', Array, "alias for --tenants") do |list|
|
432
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
433
|
+
options['tenants'] = []
|
434
|
+
else
|
435
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
436
|
+
end
|
437
|
+
end
|
438
|
+
opts.on('--visibility [private|public]', String, "Visibility") do |val|
|
439
|
+
options['visibility'] = val
|
440
|
+
end
|
441
|
+
# opts.on('--active [on|off]', String, "Can be used to disable a network") do |val|
|
442
|
+
# options['active'] = val.to_s == 'on' || val.to_s == 'true'
|
443
|
+
# end
|
444
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
445
|
+
opts.footer = "Update a subnet." + "\n" +
|
446
|
+
"[subnet] is required. This is the name or id of a subnet."
|
447
|
+
end
|
448
|
+
optparse.parse!(args)
|
449
|
+
if args.count != 1
|
450
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
|
451
|
+
end
|
452
|
+
connect(options)
|
453
|
+
begin
|
454
|
+
network = find_network_by_name_or_id(args[0])
|
455
|
+
return 1 if network.nil?
|
456
|
+
|
457
|
+
subnet = find_subnet_by_name_or_id(network['id'], args[1])
|
458
|
+
return 1 if subnet.nil?
|
459
|
+
|
460
|
+
# merge -O options into normally parsed options
|
461
|
+
options.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
462
|
+
|
463
|
+
# construct payload
|
464
|
+
payload = nil
|
465
|
+
if options[:payload]
|
466
|
+
payload = options[:payload]
|
467
|
+
else
|
468
|
+
# prompt for network options
|
469
|
+
payload = {
|
470
|
+
'subnet' => {
|
471
|
+
}
|
472
|
+
}
|
473
|
+
|
474
|
+
# allow arbitrary -O options
|
475
|
+
payload['subnet'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
476
|
+
|
477
|
+
# Group Access
|
478
|
+
if group_access_all != nil
|
479
|
+
payload['resourcePermissions'] ||= {}
|
480
|
+
payload['resourcePermissions']['all'] = group_access_all
|
481
|
+
end
|
482
|
+
if group_access_list != nil
|
483
|
+
payload['resourcePermissions'] ||= {}
|
484
|
+
payload['resourcePermissions']['sites'] = group_access_list.collect do |site_id|
|
485
|
+
site = {"id" => site_id.to_i}
|
486
|
+
if group_defaults_list && group_defaults_list.include?(site_id)
|
487
|
+
site["default"] = true
|
488
|
+
end
|
489
|
+
site
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
# Tenants
|
494
|
+
if options['tenants']
|
495
|
+
payload['tenantPermissions'] = {}
|
496
|
+
payload['tenantPermissions']['accounts'] = options['tenants']
|
497
|
+
end
|
498
|
+
|
499
|
+
# Active
|
500
|
+
if options['active'] != nil
|
501
|
+
payload['subnet']['active'] = options['active']
|
502
|
+
end
|
503
|
+
|
504
|
+
# Visibility
|
505
|
+
if options['visibility'] != nil
|
506
|
+
payload['subnet']['visibility'] = options['visibility']
|
507
|
+
end
|
508
|
+
|
509
|
+
end
|
510
|
+
|
511
|
+
@subnets_interface.setopts(options)
|
512
|
+
if options[:dry_run]
|
513
|
+
print_dry_run @subnets_interface.dry.update(network['id'], subnet['id'], payload)
|
514
|
+
return
|
515
|
+
end
|
516
|
+
json_response = @subnets_interface.update(network['id'], subnet['id'], payload)
|
517
|
+
if options[:json]
|
518
|
+
puts as_json(json_response, options)
|
519
|
+
elsif !options[:quiet]
|
520
|
+
subnet = json_response['subnet']
|
521
|
+
print_green_success "Updated subnet #{subnet['name']}"
|
522
|
+
get_args = [network['id'], subnet['id']] + (options[:remote] ? ["-r",options[:remote]] : [])
|
523
|
+
get(get_args)
|
524
|
+
end
|
525
|
+
return 0
|
526
|
+
rescue RestClient::Exception => e
|
527
|
+
print_rest_exception(e, options)
|
528
|
+
return 1
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
def remove(args)
|
533
|
+
options = {}
|
534
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
535
|
+
opts.banner = subcommand_usage("[subnet]")
|
536
|
+
build_common_options(opts, options, [:account, :auto_confirm, :json, :dry_run, :remote])
|
537
|
+
opts.footer = "Delete a subnet." + "\n" +
|
538
|
+
"[subnet] is required. This is the name or id of a subnet."
|
539
|
+
end
|
540
|
+
optparse.parse!(args)
|
541
|
+
if args.count != 1
|
542
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
|
543
|
+
end
|
544
|
+
connect(options)
|
545
|
+
begin
|
546
|
+
subnet = find_subnet_by_name_or_id(args[0])
|
547
|
+
return 1 if subnet.nil?
|
548
|
+
|
549
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the subnet: #{subnet['name']}?")
|
550
|
+
return 9, "aborted command"
|
551
|
+
end
|
552
|
+
@subnets_interface.setopts(options)
|
553
|
+
if options[:dry_run]
|
554
|
+
print_dry_run @subnets_interface.dry.destroy(subnet['id'])
|
555
|
+
return 0
|
556
|
+
end
|
557
|
+
json_response = @subnets_interface.destroy(subnet['id'])
|
558
|
+
if options[:json]
|
559
|
+
puts as_json(json_response, options)
|
560
|
+
else
|
561
|
+
print_green_success "Removed subnet #{subnet['name']}"
|
562
|
+
end
|
563
|
+
return 0
|
564
|
+
rescue RestClient::Exception => e
|
565
|
+
print_rest_exception(e, options)
|
566
|
+
return 1
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
def get_subnet_type(args)
|
571
|
+
options = {}
|
572
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
573
|
+
opts.banner = subcommand_usage("[type]")
|
574
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
575
|
+
opts.footer = "Get details about a subnet type.\n" +
|
576
|
+
"[type] is required. This is the id or name of a subnet type."
|
577
|
+
end
|
578
|
+
optparse.parse!(args)
|
579
|
+
connect(options)
|
580
|
+
begin
|
581
|
+
params = {}
|
582
|
+
@subnet_types_interface.setopts(options)
|
583
|
+
if options[:dry_run]
|
584
|
+
if args[0].to_s =~ /\A\d{1,}\Z/
|
585
|
+
print_dry_run @subnet_types_interface.dry.get(args[0].to_i)
|
586
|
+
else
|
587
|
+
print_dry_run @subnet_types_interface.dry.list({name:args[0]})
|
588
|
+
end
|
589
|
+
return
|
590
|
+
end
|
591
|
+
|
592
|
+
subnet_type = find_subnet_type_by_name_or_id(args[0])
|
593
|
+
return 1 if subnet_type.nil?
|
594
|
+
json_response = {'subnetType' => subnet_type} # skip redundant request
|
595
|
+
# json_response = @networks_interface.get(subnet_type['id'])
|
596
|
+
|
597
|
+
render_result = render_with_format(json_response, options, 'subnetType')
|
598
|
+
return 0 if render_result
|
599
|
+
|
600
|
+
subnet_type = json_response['subnetType']
|
601
|
+
|
602
|
+
title = "Morpheus Subnet Type"
|
603
|
+
|
604
|
+
print_h1 "Morpheus Subnet Type", [], options
|
605
|
+
|
606
|
+
print cyan
|
607
|
+
description_cols = {
|
608
|
+
"ID" => 'id',
|
609
|
+
"Name" => 'name',
|
610
|
+
"Code" => 'name',
|
611
|
+
"Description" => 'description',
|
612
|
+
"Createable" => lambda {|it| format_boolean(it['creatable']) },
|
613
|
+
"Deletable" => lambda {|it| format_boolean(it['deleteable']) },
|
614
|
+
}
|
615
|
+
print_description_list(description_cols, subnet_type)
|
616
|
+
|
617
|
+
|
618
|
+
|
619
|
+
option_types = subnet_type['optionTypes'] || []
|
620
|
+
option_types = option_types.sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
621
|
+
if !option_types.empty?
|
622
|
+
print_h2 "Config Option Types", [], options
|
623
|
+
option_type_cols = {
|
624
|
+
"Name" => lambda {|it| it['fieldContext'].to_s != '' ? "#{it['fieldContext']}.#{it['fieldName']}" : it['fieldName'] },
|
625
|
+
"Label" => lambda {|it| it['fieldLabel'] },
|
626
|
+
"Type" => lambda {|it| it['type'] },
|
627
|
+
}
|
628
|
+
print cyan
|
629
|
+
print as_pretty_table(option_types, option_type_cols)
|
630
|
+
end
|
631
|
+
|
632
|
+
print reset,"\n"
|
633
|
+
return 0
|
634
|
+
rescue RestClient::Exception => e
|
635
|
+
print_rest_exception(e, options)
|
636
|
+
exit 1
|
637
|
+
end
|
638
|
+
end
|
639
|
+
|
640
|
+
def list_subnet_types(args)
|
641
|
+
options = {}
|
642
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
643
|
+
opts.banner = subcommand_usage()
|
644
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
|
645
|
+
options[:cloud] = val
|
646
|
+
end
|
647
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
648
|
+
opts.footer = "List subnet types."
|
649
|
+
end
|
650
|
+
optparse.parse!(args)
|
651
|
+
connect(options)
|
652
|
+
begin
|
653
|
+
params = {}
|
654
|
+
params.merge!(parse_list_options(options))
|
655
|
+
if options[:cloud]
|
656
|
+
#return network_types_for_cloud(options[:cloud], options)
|
657
|
+
zone = find_zone_by_name_or_id(nil, options[:cloud])
|
658
|
+
#params["zoneTypeId"] = zone['zoneTypeId']
|
659
|
+
params["zoneId"] = zone['id']
|
660
|
+
params["creatable"] = true
|
661
|
+
end
|
662
|
+
@subnet_types_interface.setopts(options)
|
663
|
+
if options[:dry_run]
|
664
|
+
print_dry_run @subnet_types_interface.dry.list(params)
|
665
|
+
return
|
666
|
+
end
|
667
|
+
json_response = @subnet_types_interface.list(params)
|
668
|
+
|
669
|
+
render_result = render_with_format(json_response, options, 'subnetTypes')
|
670
|
+
return 0 if render_result
|
671
|
+
|
672
|
+
subnet_types = json_response['subnetTypes']
|
673
|
+
|
674
|
+
title = "Morpheus Subnet Types"
|
675
|
+
subtitles = []
|
676
|
+
subtitles += parse_list_subtitles(options)
|
677
|
+
if options[:cloud]
|
678
|
+
subtitles << "Cloud: #{options[:cloud]}"
|
679
|
+
end
|
680
|
+
print_h1 title, subtitles
|
681
|
+
if subnet_types.empty?
|
682
|
+
print cyan,"No subnet types found.",reset,"\n"
|
683
|
+
else
|
684
|
+
rows = subnet_types.collect do |subnet_type|
|
685
|
+
{
|
686
|
+
id: subnet_type['id'],
|
687
|
+
code: subnet_type['code'],
|
688
|
+
name: subnet_type['name']
|
689
|
+
}
|
690
|
+
end
|
691
|
+
columns = [:id, :name, :code]
|
692
|
+
print cyan
|
693
|
+
print as_pretty_table(rows, columns, options)
|
694
|
+
print reset
|
695
|
+
print_results_pagination(json_response)
|
696
|
+
end
|
697
|
+
print reset,"\n"
|
698
|
+
return 0
|
699
|
+
|
700
|
+
rescue RestClient::Exception => e
|
701
|
+
print_rest_exception(e, options)
|
702
|
+
exit 1
|
703
|
+
end
|
704
|
+
end
|
705
|
+
|
706
|
+
private
|
707
|
+
|
708
|
+
end
|