morpheus-cli 3.6.28 → 3.6.29
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 +16 -0
- data/lib/morpheus/api/cloud_folders_interface.rb +47 -0
- data/lib/morpheus/api/cloud_resource_pools_interface.rb +47 -0
- data/lib/morpheus/api/network_types_interface.rb +26 -0
- data/lib/morpheus/api/reports_interface.rb +77 -0
- data/lib/morpheus/api/security_group_rules_interface.rb +6 -0
- data/lib/morpheus/api/security_groups_interface.rb +21 -15
- data/lib/morpheus/cli.rb +3 -0
- data/lib/morpheus/cli/accounts.rb +1 -1
- data/lib/morpheus/cli/apps.rb +2 -2
- data/lib/morpheus/cli/archives_command.rb +18 -18
- data/lib/morpheus/cli/blueprints_command.rb +1 -1
- data/lib/morpheus/cli/boot_scripts_command.rb +6 -6
- data/lib/morpheus/cli/cli_command.rb +4 -0
- data/lib/morpheus/cli/cloud_datastores_command.rb +58 -20
- data/lib/morpheus/cli/cloud_folders_command.rb +463 -0
- data/lib/morpheus/cli/cloud_resource_pools_command.rb +707 -0
- data/lib/morpheus/cli/clouds.rb +2 -0
- data/lib/morpheus/cli/hosts.rb +33 -8
- data/lib/morpheus/cli/instances.rb +79 -54
- data/lib/morpheus/cli/library_option_lists_command.rb +1 -1
- data/lib/morpheus/cli/library_option_types_command.rb +1 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +11 -2
- data/lib/morpheus/cli/monitoring_contacts_command.rb +1 -1
- data/lib/morpheus/cli/monitoring_incidents_command.rb +1 -1
- data/lib/morpheus/cli/network_services_command.rb +7 -3
- data/lib/morpheus/cli/networks_command.rb +164 -63
- data/lib/morpheus/cli/option_types.rb +16 -15
- data/lib/morpheus/cli/policies_command.rb +76 -9
- data/lib/morpheus/cli/preseed_scripts_command.rb +2 -2
- data/lib/morpheus/cli/remote.rb +26 -28
- data/lib/morpheus/cli/reports_command.rb +594 -0
- data/lib/morpheus/cli/security_group_rules.rb +5 -1
- data/lib/morpheus/cli/security_groups.rb +882 -45
- data/lib/morpheus/cli/tasks.rb +158 -23
- data/lib/morpheus/cli/tenants_command.rb +1 -1
- data/lib/morpheus/cli/users.rb +1 -1
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +9 -2
@@ -0,0 +1,707 @@
|
|
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::CloudResourcePoolsCommand
|
8
|
+
include Morpheus::Cli::CliCommand
|
9
|
+
include Morpheus::Cli::InfrastructureHelper
|
10
|
+
|
11
|
+
#set_command_name :'cloud-resource-pools'
|
12
|
+
set_command_name :'resource-pools'
|
13
|
+
|
14
|
+
register_subcommands :list, :get, :add, :update, :remove
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect(opts)
|
21
|
+
@api_client = establish_remote_appliance_connection(opts)
|
22
|
+
@cloud_resource_pools_interface = @api_client.cloud_resource_pools
|
23
|
+
@clouds_interface = @api_client.clouds
|
24
|
+
@options_interface = @api_client.options
|
25
|
+
end
|
26
|
+
|
27
|
+
def handle(args)
|
28
|
+
handle_subcommand(args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def list(args)
|
32
|
+
cloud_id = nil
|
33
|
+
options = {}
|
34
|
+
params = {}
|
35
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
36
|
+
opts.banner = subcommand_usage("[cloud]")
|
37
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
|
38
|
+
cloud_id = val
|
39
|
+
end
|
40
|
+
opts.add_hidden_option('-c') # prefer args[0] for [cloud]
|
41
|
+
build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
42
|
+
opts.footer = "List resource pools for a cloud." + "\n" +
|
43
|
+
"[cloud] is required. This is the name or id of the cloud."
|
44
|
+
end
|
45
|
+
optparse.parse!(args)
|
46
|
+
if args.count == 1
|
47
|
+
cloud_id = args[0]
|
48
|
+
elsif args.count == 0 && cloud_id
|
49
|
+
# support -c
|
50
|
+
else
|
51
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
52
|
+
end
|
53
|
+
connect(options)
|
54
|
+
begin
|
55
|
+
# load cloud
|
56
|
+
if cloud_id.nil?
|
57
|
+
puts_error "#{Morpheus::Terminal.angry_prompt}missing required option: [cloud]\n#{optparse}"
|
58
|
+
return 1
|
59
|
+
end
|
60
|
+
cloud = find_cloud_by_name_or_id(cloud_id)
|
61
|
+
return 1 if cloud.nil?
|
62
|
+
|
63
|
+
params.merge!(parse_list_options(options))
|
64
|
+
@cloud_resource_pools_interface.setopts(options)
|
65
|
+
if options[:dry_run]
|
66
|
+
print_dry_run @cloud_resource_pools_interface.dry.list(cloud['id'], params)
|
67
|
+
return
|
68
|
+
end
|
69
|
+
json_response = @cloud_resource_pools_interface.list(cloud['id'], params)
|
70
|
+
resource_pools = json_response["resourcePools"]
|
71
|
+
if options[:json]
|
72
|
+
puts as_json(json_response, options, "resourcePools")
|
73
|
+
return 0
|
74
|
+
elsif options[:yaml]
|
75
|
+
puts as_yaml(json_response, options, "resourcePools")
|
76
|
+
return 0
|
77
|
+
elsif options[:csv]
|
78
|
+
puts records_as_csv(resource_pools, options)
|
79
|
+
return 0
|
80
|
+
end
|
81
|
+
title = "Morpheus Resource Pools - Cloud: #{cloud['name']}"
|
82
|
+
subtitles = []
|
83
|
+
subtitles += parse_list_subtitles(options)
|
84
|
+
print_h1 title, subtitles
|
85
|
+
if resource_pools.empty?
|
86
|
+
print cyan,"No resource pools found.",reset,"\n"
|
87
|
+
else
|
88
|
+
rows = resource_pools.collect {|resource_pool|
|
89
|
+
formatted_name = (resource_pool['depth'] && resource_pool['depth'] > 0) ? ((' ' * resource_pool['depth'].to_i) + resource_pool['name'].to_s) : resource_pool['name'].to_s
|
90
|
+
row = {
|
91
|
+
id: resource_pool['id'],
|
92
|
+
# name: resource_pool['name'],
|
93
|
+
name: formatted_name,
|
94
|
+
type: resource_pool['type'].to_s.capitalize,
|
95
|
+
description: resource_pool['description'],
|
96
|
+
active: format_boolean(resource_pool['active']),
|
97
|
+
status: resource_pool['status'].to_s.upcase,
|
98
|
+
visibility: resource_pool['visibility'].to_s.capitalize,
|
99
|
+
default: format_boolean(resource_pool['defaultPool']),
|
100
|
+
tenants: resource_pool['tenants'] ? resource_pool['tenants'].collect {|it| it['name'] }.uniq.join(', ') : ''
|
101
|
+
# owner: resource_pool['owner'] ? resource_pool['owner']['name'] : ''
|
102
|
+
}
|
103
|
+
row
|
104
|
+
}
|
105
|
+
columns = [:id, :name, :description, :active, :default, :visibility, :tenants]
|
106
|
+
if options[:include_fields]
|
107
|
+
columns = options[:include_fields]
|
108
|
+
end
|
109
|
+
print cyan
|
110
|
+
print as_pretty_table(rows, columns, options)
|
111
|
+
print reset
|
112
|
+
print_results_pagination(json_response)
|
113
|
+
end
|
114
|
+
print reset,"\n"
|
115
|
+
return 0
|
116
|
+
rescue RestClient::Exception => e
|
117
|
+
print_rest_exception(e, options)
|
118
|
+
exit 1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def get(args)
|
123
|
+
resource_pool_id = nil
|
124
|
+
cloud_id = nil
|
125
|
+
options = {}
|
126
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
127
|
+
opts.banner = subcommand_usage("[cloud] [pool]")
|
128
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
|
129
|
+
cloud_id = val
|
130
|
+
end
|
131
|
+
opts.add_hidden_option('-c') # prefer args[0] for [cloud]
|
132
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
133
|
+
opts.footer = "Get details about a resource pool." + "\n" +
|
134
|
+
"[cloud] is required. This is the name or id of the cloud." + "\n"
|
135
|
+
"[pool] is required. This is the name or id of a resource pool."
|
136
|
+
end
|
137
|
+
optparse.parse!(args)
|
138
|
+
if args.count == 2
|
139
|
+
cloud_id = args[0]
|
140
|
+
resource_pool_id = args[1]
|
141
|
+
elsif args.count == 1 && cloud_id
|
142
|
+
resource_pool_id = args[0]
|
143
|
+
else
|
144
|
+
raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
145
|
+
end
|
146
|
+
connect(options)
|
147
|
+
begin
|
148
|
+
# load cloud
|
149
|
+
if cloud_id.nil?
|
150
|
+
puts_error "#{Morpheus::Terminal.angry_prompt}missing required option: [cloud]\n#{optparse}"
|
151
|
+
return 1
|
152
|
+
end
|
153
|
+
cloud = find_cloud_by_name_or_id(cloud_id)
|
154
|
+
return 1 if cloud.nil?
|
155
|
+
@cloud_resource_pools_interface.setopts(options)
|
156
|
+
if options[:dry_run]
|
157
|
+
if args[0].to_s =~ /\A\d{1,}\Z/
|
158
|
+
print_dry_run @cloud_resource_pools_interface.dry.get(cloud['id'], resource_pool_id.to_i)
|
159
|
+
else
|
160
|
+
print_dry_run @cloud_resource_pools_interface.dry.list(cloud['id'], {name:resource_pool_id})
|
161
|
+
end
|
162
|
+
return
|
163
|
+
end
|
164
|
+
resource_pool = find_resource_pool_by_name_or_id(cloud['id'], resource_pool_id)
|
165
|
+
return 1 if resource_pool.nil?
|
166
|
+
json_response = {'resourcePool' => resource_pool} # skip redundant request
|
167
|
+
# json_response = @resource_pools_interface.get(resource_pool['id'])
|
168
|
+
resource_pool = json_response['resourcePool']
|
169
|
+
if options[:json]
|
170
|
+
puts as_json(json_response, options, "resourcePool")
|
171
|
+
return 0
|
172
|
+
elsif options[:yaml]
|
173
|
+
puts as_yaml(json_response, options, "resourcePool")
|
174
|
+
return 0
|
175
|
+
elsif options[:csv]
|
176
|
+
puts records_as_csv([resource_pool], options)
|
177
|
+
return 0
|
178
|
+
end
|
179
|
+
|
180
|
+
print_h1 "Resource Pool Details"
|
181
|
+
print cyan
|
182
|
+
description_cols = {
|
183
|
+
"ID" => 'id',
|
184
|
+
"Name" => 'name',
|
185
|
+
"Description" => 'description',
|
186
|
+
#"Type" => lambda {|it| it['type'].to_s.capitalize },
|
187
|
+
"Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
|
188
|
+
"Active" => lambda {|it| format_boolean(it['active']) },
|
189
|
+
"Default" => lambda {|it| format_boolean(it['defaultPool']) },
|
190
|
+
"Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
|
191
|
+
"Status" => lambda {|it| it['status'].to_s.capitalize },
|
192
|
+
"Tenants" => lambda {|it| it['tenants'] ? it['tenants'].collect {|it| it['name'] }.uniq.join(', ') : '' }
|
193
|
+
}
|
194
|
+
print_description_list(description_cols, resource_pool)
|
195
|
+
|
196
|
+
if resource_pool['resourcePermission'].nil?
|
197
|
+
#print "\n", "No group access found", "\n"
|
198
|
+
else
|
199
|
+
print_h2 "Group Access"
|
200
|
+
rows = []
|
201
|
+
if resource_pool['resourcePermission']['all']
|
202
|
+
rows.push({"name" => 'All'})
|
203
|
+
end
|
204
|
+
if resource_pool['resourcePermission']['sites']
|
205
|
+
resource_pool['resourcePermission']['sites'].each do |site|
|
206
|
+
rows.push(site)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
group_columns = {
|
210
|
+
"GROUP" => 'name',
|
211
|
+
"DEFAULT" => lambda {|it| it['default'].nil? ? '' : format_boolean(it['default']) }
|
212
|
+
}
|
213
|
+
print cyan
|
214
|
+
print as_pretty_table(rows, group_columns)
|
215
|
+
end
|
216
|
+
|
217
|
+
if resource_pool['resourcePermission'] && resource_pool['resourcePermission']['plans'] && resource_pool['resourcePermission']['plans'].size > 0
|
218
|
+
print_h2 "Service Plan Access"
|
219
|
+
rows = []
|
220
|
+
if resource_pool['resourcePermission']['allPlans']
|
221
|
+
rows.push({"name" => 'All'})
|
222
|
+
end
|
223
|
+
if resource_pool['resourcePermission']['plans']
|
224
|
+
resource_pool['resourcePermission']['plans'].each do |plan|
|
225
|
+
rows.push(plan)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
# rows = rows.collect do |site|
|
229
|
+
# {plan: site['name'], default: site['default'] ? 'Yes' : ''}
|
230
|
+
# #{group: site['name']}
|
231
|
+
# end
|
232
|
+
plan_columns = {
|
233
|
+
"PLAN" => 'name',
|
234
|
+
"DEFAULT" => lambda {|it| it['default'].nil? ? '' : format_boolean(it['default']) }
|
235
|
+
}
|
236
|
+
print cyan
|
237
|
+
print as_pretty_table(rows, plan_columns)
|
238
|
+
end
|
239
|
+
|
240
|
+
if resource_pool['tenants'].nil? || resource_pool['tenants'].empty?
|
241
|
+
#print "\n", "No tenant permissions found", "\n"
|
242
|
+
else
|
243
|
+
print_h2 "Tenant Permissions"
|
244
|
+
rows = []
|
245
|
+
rows = resource_pool['tenants'] || []
|
246
|
+
tenant_columns = {
|
247
|
+
"TENANT" => 'name',
|
248
|
+
"DEFAULT" => lambda {|it| format_boolean(it['defaultTarget']) },
|
249
|
+
"IMAGE TARGET" => lambda {|it| format_boolean(it['defaultStore']) }
|
250
|
+
}
|
251
|
+
print cyan
|
252
|
+
print as_pretty_table(rows, tenant_columns)
|
253
|
+
end
|
254
|
+
|
255
|
+
print reset,"\n"
|
256
|
+
return 0
|
257
|
+
rescue RestClient::Exception => e
|
258
|
+
print_rest_exception(e, options)
|
259
|
+
return 1
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def add(args)
|
264
|
+
options = {}
|
265
|
+
cloud_id = nil
|
266
|
+
tenants = nil
|
267
|
+
group_access_all = nil
|
268
|
+
group_access_list = nil
|
269
|
+
group_defaults_list = nil
|
270
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
271
|
+
opts.banner = subcommand_usage("[cloud] [pool] [options]")
|
272
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
|
273
|
+
cloud_id = val
|
274
|
+
end
|
275
|
+
opts.add_hidden_option('-c') # prefer args[0] for [cloud]
|
276
|
+
opts.on( '--name VALUE', String, "Name" ) do |val|
|
277
|
+
options['name'] = val
|
278
|
+
end
|
279
|
+
opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
|
280
|
+
group_access_all = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
281
|
+
end
|
282
|
+
opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
|
283
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
284
|
+
group_access_list = []
|
285
|
+
else
|
286
|
+
group_access_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
287
|
+
end
|
288
|
+
end
|
289
|
+
# opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
|
290
|
+
# if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
291
|
+
# group_defaults_list = []
|
292
|
+
# else
|
293
|
+
# group_defaults_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
294
|
+
# end
|
295
|
+
# end
|
296
|
+
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
297
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
298
|
+
options['tenants'] = []
|
299
|
+
else
|
300
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
301
|
+
end
|
302
|
+
end
|
303
|
+
opts.on('--visibility [private|public]', String, "Visibility") do |val|
|
304
|
+
options['visibility'] = val
|
305
|
+
end
|
306
|
+
opts.on('--active [on|off]', String, "Can be used to disable a resource pool") do |val|
|
307
|
+
options['active'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
308
|
+
end
|
309
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
310
|
+
opts.footer = "Update a resource pool." + "\n" +
|
311
|
+
"[cloud] is required. This is the name or id of the cloud."
|
312
|
+
end
|
313
|
+
optparse.parse!(args)
|
314
|
+
if args.count == 2
|
315
|
+
cloud_id = args[0]
|
316
|
+
options['name'] = args[1]
|
317
|
+
elsif args.count == 1 # && cloud_id
|
318
|
+
if cloud_id
|
319
|
+
options['name'] = args[0]
|
320
|
+
else
|
321
|
+
cloud_id = args[0]
|
322
|
+
end
|
323
|
+
else
|
324
|
+
raise_command_error "wrong number of arguments, expected 1-2 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
325
|
+
end
|
326
|
+
|
327
|
+
connect(options)
|
328
|
+
|
329
|
+
begin
|
330
|
+
# load cloud
|
331
|
+
if cloud_id.nil?
|
332
|
+
puts_error "#{Morpheus::Terminal.angry_prompt}missing required option: [cloud]\n#{optparse}"
|
333
|
+
return 1
|
334
|
+
end
|
335
|
+
cloud = find_cloud_by_name_or_id(cloud_id)
|
336
|
+
return 1 if cloud.nil?
|
337
|
+
|
338
|
+
# merge -O options into normally parsed options
|
339
|
+
options.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
340
|
+
|
341
|
+
# construct payload
|
342
|
+
payload = nil
|
343
|
+
if options[:payload]
|
344
|
+
payload = options[:payload]
|
345
|
+
else
|
346
|
+
# prompt for resource pool options
|
347
|
+
payload = {
|
348
|
+
'resourcePool' => {
|
349
|
+
}
|
350
|
+
}
|
351
|
+
|
352
|
+
# allow arbitrary -O options
|
353
|
+
payload['resourcePool'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
354
|
+
|
355
|
+
|
356
|
+
# Name
|
357
|
+
if options['name']
|
358
|
+
payload['resourcePool']['name'] = options['name']
|
359
|
+
else
|
360
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Name'}], options)
|
361
|
+
payload['resourcePool']['name'] = v_prompt['name']
|
362
|
+
end
|
363
|
+
|
364
|
+
# Group Access
|
365
|
+
if group_access_all != nil
|
366
|
+
payload['resourcePermissions'] ||= {}
|
367
|
+
payload['resourcePermissions']['all'] = group_access_all
|
368
|
+
end
|
369
|
+
if group_access_list != nil
|
370
|
+
payload['resourcePermissions'] ||= {}
|
371
|
+
payload['resourcePermissions']['sites'] = group_access_list.collect do |site_id|
|
372
|
+
site = {"id" => site_id.to_i}
|
373
|
+
if group_defaults_list && group_defaults_list.include?(site_id)
|
374
|
+
site["default"] = true
|
375
|
+
end
|
376
|
+
site
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Tenants
|
381
|
+
if options['tenants']
|
382
|
+
payload['tenantPermissions'] = {}
|
383
|
+
payload['tenantPermissions']['accounts'] = options['tenants']
|
384
|
+
end
|
385
|
+
|
386
|
+
# Active
|
387
|
+
if options['active'] != nil
|
388
|
+
payload['resourcePool']['active'] = options['active']
|
389
|
+
else
|
390
|
+
payload['resourcePool']['active'] = true
|
391
|
+
end
|
392
|
+
|
393
|
+
# Visibility
|
394
|
+
if options['visibility'] != nil
|
395
|
+
payload['resourcePool']['visibility'] = options['visibility']
|
396
|
+
else
|
397
|
+
payload['resourcePool']['visibility'] = 'private'
|
398
|
+
end
|
399
|
+
|
400
|
+
|
401
|
+
# Config options depend on type (until api returns these as optionTypes)
|
402
|
+
zone_type = cloud['zoneType'] ? cloud['zoneType']['code'] : ''
|
403
|
+
if zone_type == 'amazon'
|
404
|
+
payload['resourcePool']['config'] ||= {}
|
405
|
+
# CIDR
|
406
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'config', 'fieldName' => 'cidrBlock', 'fieldLabel' => 'CIDR', 'type' => 'text', 'required' => true, 'description' => 'Provide the base CIDR Block to use for this VPC (must be between a /16 and /28 Block)'}], options)
|
407
|
+
payload['resourcePool']['config']['cidrBlock'] = v_prompt['config']['cidrBlock']
|
408
|
+
# Tenancy
|
409
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'config', 'fieldName' => 'tenancy', 'fieldLabel' => 'Tenancy', 'type' => 'select', 'selectOptions' => [{'name' => 'Default', 'value' => 'default'}, {'name' => 'Dedicated', 'value' => 'dedicated'}], 'defaultValue' => 'default'}], options)
|
410
|
+
payload['resourcePool']['config']['tenancy'] = v_prompt['config']['tenancy']
|
411
|
+
|
412
|
+
elsif zone_type == 'azure'
|
413
|
+
# no options
|
414
|
+
elsif zone_type == 'cloudFoundry' || zone_type == 'bluemixCloudFoundry'
|
415
|
+
|
416
|
+
elsif zone_type == 'standard'
|
417
|
+
# no options
|
418
|
+
else
|
419
|
+
#raise_command_error "Cloud type '#{zone_type}' does not allow creating resource pools"
|
420
|
+
end
|
421
|
+
|
422
|
+
end
|
423
|
+
@cloud_resource_pools_interface.setopts(options)
|
424
|
+
if options[:dry_run]
|
425
|
+
print_dry_run @cloud_resource_pools_interface.dry.create(cloud['id'], payload)
|
426
|
+
return
|
427
|
+
end
|
428
|
+
json_response = @cloud_resource_pools_interface.create(cloud['id'], payload)
|
429
|
+
if options[:json]
|
430
|
+
puts as_json(json_response)
|
431
|
+
else
|
432
|
+
resource_pool = json_response['resourcePool']
|
433
|
+
print_green_success "Created resource pool #{resource_pool['name']}"
|
434
|
+
get([cloud['id'].to_s, resource_pool['id'].to_s])
|
435
|
+
end
|
436
|
+
return 0
|
437
|
+
rescue RestClient::Exception => e
|
438
|
+
print_rest_exception(e, options)
|
439
|
+
return 1
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
def update(args)
|
444
|
+
options = {}
|
445
|
+
cloud_id = nil
|
446
|
+
resource_pool_id = nil
|
447
|
+
tenants = nil
|
448
|
+
group_access_all = nil
|
449
|
+
group_access_list = nil
|
450
|
+
group_defaults_list = nil
|
451
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
452
|
+
opts.banner = subcommand_usage("[cloud] [pool] [options]")
|
453
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
|
454
|
+
cloud_id = val
|
455
|
+
end
|
456
|
+
opts.add_hidden_option('-c') # prefer args[0] for [cloud]
|
457
|
+
opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
|
458
|
+
group_access_all = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
459
|
+
end
|
460
|
+
opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
|
461
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
462
|
+
group_access_list = []
|
463
|
+
else
|
464
|
+
group_access_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
465
|
+
end
|
466
|
+
end
|
467
|
+
# opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
|
468
|
+
# if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
469
|
+
# group_defaults_list = []
|
470
|
+
# else
|
471
|
+
# group_defaults_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
472
|
+
# end
|
473
|
+
# end
|
474
|
+
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
475
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
476
|
+
options['tenants'] = []
|
477
|
+
else
|
478
|
+
options['tenants'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
479
|
+
end
|
480
|
+
end
|
481
|
+
opts.on('--visibility [private|public]', String, "Visibility") do |val|
|
482
|
+
options['visibility'] = val
|
483
|
+
end
|
484
|
+
opts.on('--active [on|off]', String, "Can be used to disable a resource pool") do |val|
|
485
|
+
options['active'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
486
|
+
end
|
487
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
488
|
+
opts.footer = "Update a resource pool." + "\n" +
|
489
|
+
"[cloud] is required. This is the name or id of the cloud." + "\n"
|
490
|
+
"[pool] is required. This is the name or id of a resource pool."
|
491
|
+
end
|
492
|
+
optparse.parse!(args)
|
493
|
+
if args.count == 2
|
494
|
+
cloud_id = args[0]
|
495
|
+
resource_pool_id = args[1]
|
496
|
+
elsif args.count == 1 && cloud_id
|
497
|
+
resource_pool_id = args[0]
|
498
|
+
else
|
499
|
+
raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
500
|
+
end
|
501
|
+
|
502
|
+
connect(options)
|
503
|
+
|
504
|
+
begin
|
505
|
+
# load cloud
|
506
|
+
if cloud_id.nil?
|
507
|
+
puts_error "#{Morpheus::Terminal.angry_prompt}missing required option: [cloud]\n#{optparse}"
|
508
|
+
return 1
|
509
|
+
end
|
510
|
+
cloud = find_cloud_by_name_or_id(cloud_id)
|
511
|
+
return 1 if cloud.nil?
|
512
|
+
|
513
|
+
resource_pool = find_resource_pool_by_name_or_id(cloud['id'], resource_pool_id)
|
514
|
+
return 1 if resource_pool.nil?
|
515
|
+
|
516
|
+
# merge -O options into normally parsed options
|
517
|
+
options.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
518
|
+
|
519
|
+
# construct payload
|
520
|
+
payload = nil
|
521
|
+
if options[:payload]
|
522
|
+
payload = options[:payload]
|
523
|
+
else
|
524
|
+
# prompt for resource pool options
|
525
|
+
payload = {
|
526
|
+
'resourcePool' => {
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
# allow arbitrary -O options
|
531
|
+
payload['resourcePool'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
532
|
+
|
533
|
+
|
534
|
+
# Group Access
|
535
|
+
if group_access_all != nil
|
536
|
+
payload['resourcePermissions'] ||= {}
|
537
|
+
payload['resourcePermissions']['all'] = group_access_all
|
538
|
+
end
|
539
|
+
if group_access_list != nil
|
540
|
+
payload['resourcePermissions'] ||= {}
|
541
|
+
payload['resourcePermissions']['sites'] = group_access_list.collect do |site_id|
|
542
|
+
site = {"id" => site_id.to_i}
|
543
|
+
if group_defaults_list && group_defaults_list.include?(site_id)
|
544
|
+
site["default"] = true
|
545
|
+
end
|
546
|
+
site
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
# Tenants
|
551
|
+
if options['tenants']
|
552
|
+
payload['tenantPermissions'] = {}
|
553
|
+
payload['tenantPermissions']['accounts'] = options['tenants']
|
554
|
+
end
|
555
|
+
|
556
|
+
# Active
|
557
|
+
if options['active'] != nil
|
558
|
+
payload['resourcePool']['active'] = options['active']
|
559
|
+
end
|
560
|
+
|
561
|
+
# Visibility
|
562
|
+
if options['visibility'] != nil
|
563
|
+
payload['resourcePool']['visibility'] = options['visibility']
|
564
|
+
end
|
565
|
+
|
566
|
+
if payload['resourcePool'].empty? && payload['resourcePermissions'].nil? && payload['tenantPermissions'].nil?
|
567
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
568
|
+
end
|
569
|
+
|
570
|
+
end
|
571
|
+
@cloud_resource_pools_interface.setopts(options)
|
572
|
+
if options[:dry_run]
|
573
|
+
print_dry_run @cloud_resource_pools_interface.dry.update(cloud['id'], resource_pool["id"], payload)
|
574
|
+
return
|
575
|
+
end
|
576
|
+
json_response = @cloud_resource_pools_interface.update(cloud['id'], resource_pool["id"], payload)
|
577
|
+
if options[:json]
|
578
|
+
puts as_json(json_response)
|
579
|
+
else
|
580
|
+
resource_pool = json_response['resourcePool']
|
581
|
+
print_green_success "Updated resource pool #{resource_pool['name']}"
|
582
|
+
get([cloud['id'].to_s, resource_pool['id'].to_s])
|
583
|
+
end
|
584
|
+
return 0
|
585
|
+
rescue RestClient::Exception => e
|
586
|
+
print_rest_exception(e, options)
|
587
|
+
return 1
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
def remove(args)
|
592
|
+
cloud_id = nil
|
593
|
+
resource_pool_id = nil
|
594
|
+
options = {}
|
595
|
+
params = {}
|
596
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
597
|
+
opts.banner = subcommand_usage("[cloud] [pool]")
|
598
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
599
|
+
opts.footer = "Delete a resource pool." + "\n" +
|
600
|
+
"[cloud] is required. This is the name or id of the cloud." + "\n"
|
601
|
+
"[pool] is required. This is the name or id of a resource pool."
|
602
|
+
end
|
603
|
+
optparse.parse!(args)
|
604
|
+
|
605
|
+
if args.count == 2
|
606
|
+
cloud_id = args[0]
|
607
|
+
resource_pool_id = args[1]
|
608
|
+
elsif args.count == 1 && cloud_id
|
609
|
+
resource_pool_id = args[0]
|
610
|
+
else
|
611
|
+
raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
612
|
+
end
|
613
|
+
|
614
|
+
connect(options)
|
615
|
+
begin
|
616
|
+
# load cloud
|
617
|
+
if cloud_id.nil?
|
618
|
+
puts_error "#{Morpheus::Terminal.angry_prompt}missing required option: [cloud]\n#{optparse}"
|
619
|
+
return 1
|
620
|
+
end
|
621
|
+
cloud = find_cloud_by_name_or_id(cloud_id)
|
622
|
+
return 1 if cloud.nil?
|
623
|
+
|
624
|
+
resource_pool = find_resource_pool_by_name_or_id(cloud['id'], resource_pool_id)
|
625
|
+
return 1 if resource_pool.nil?
|
626
|
+
|
627
|
+
zone_type = cloud['zoneType'] ? cloud['zoneType']['code'] : ''
|
628
|
+
if zone_type == ['amazon','azure','cloudFoundry','bluemixCloudFoundry','standard'].include?(zone_type)
|
629
|
+
else
|
630
|
+
#raise_command_error "Cloud type '#{zone_type}' does not allow deleting resource pools"
|
631
|
+
end
|
632
|
+
|
633
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the resource pool: #{resource_pool['name']}?")
|
634
|
+
return 9, "aborted command"
|
635
|
+
end
|
636
|
+
@cloud_resource_pools_interface.setopts(options)
|
637
|
+
if options[:dry_run]
|
638
|
+
print_dry_run @cloud_resource_pools_interface.dry.destroy(cloud['id'], resource_pool["id"], params)
|
639
|
+
return
|
640
|
+
end
|
641
|
+
json_response = @cloud_resource_pools_interface.destroy(cloud['id'], resource_pool["id"], params)
|
642
|
+
if options[:json]
|
643
|
+
puts as_json(json_response, options)
|
644
|
+
else
|
645
|
+
print_green_success "Removed resource pool #{resource_pool['name']}"
|
646
|
+
end
|
647
|
+
return 0
|
648
|
+
rescue RestClient::Exception => e
|
649
|
+
print_rest_exception(e, options)
|
650
|
+
return 1
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
private
|
655
|
+
|
656
|
+
|
657
|
+
def find_resource_pool_by_name_or_id(cloud_id, val)
|
658
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
659
|
+
return find_resource_pool_by_id(cloud_id, val)
|
660
|
+
else
|
661
|
+
return find_resource_pool_by_name(cloud_id, val)
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
def find_resource_pool_by_id(cloud_id, id)
|
666
|
+
begin
|
667
|
+
json_response = @cloud_resource_pools_interface.get(cloud_id, id.to_i)
|
668
|
+
return json_response['resourcePool']
|
669
|
+
rescue RestClient::Exception => e
|
670
|
+
if e.response && e.response.code == 404
|
671
|
+
print_red_alert "Resource Pool not found by id #{id}"
|
672
|
+
return nil
|
673
|
+
else
|
674
|
+
raise e
|
675
|
+
end
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
def find_resource_pool_by_name(cloud_id, name)
|
680
|
+
json_response = @cloud_resource_pools_interface.list(cloud_id, {name: name.to_s})
|
681
|
+
resource_pools = json_response['resourcePools']
|
682
|
+
if resource_pools.empty?
|
683
|
+
print_red_alert "Resource Pool not found by name #{name}"
|
684
|
+
return nil
|
685
|
+
elsif resource_pools.size > 1
|
686
|
+
matching_resource_pools = folders.select { |it| name && (it['name'] == name || it['externalId'] == name) }
|
687
|
+
if matching_resource_pools.size == 1
|
688
|
+
return matching_resource_pools[0]
|
689
|
+
end
|
690
|
+
print_red_alert "#{resource_pools.size} resource pools found by name #{name}"
|
691
|
+
rows = resource_pools.collect do |it|
|
692
|
+
{id: it['id'], name: it['name']}
|
693
|
+
end
|
694
|
+
print "\n"
|
695
|
+
puts as_pretty_table(rows, [:id, :name], {color:red})
|
696
|
+
return nil
|
697
|
+
else
|
698
|
+
resource_pool = resource_pools[0]
|
699
|
+
# merge in tenants map
|
700
|
+
if json_response['tenants'] && json_response['tenants'][resource_pool['id']]
|
701
|
+
resource_pool['tenants'] = json_response['tenants'][resource_pool['id']]
|
702
|
+
end
|
703
|
+
return resource_pool
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
707
|
+
end
|