morpheus-cli 5.4.0 → 5.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/account_users_interface.rb +68 -0
- data/lib/morpheus/api/api_client.rb +51 -9
- data/lib/morpheus/api/audit_interface.rb +9 -0
- data/lib/morpheus/api/instances_interface.rb +21 -0
- data/lib/morpheus/api/load_balancer_monitors_interface.rb +9 -0
- data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
- data/lib/morpheus/api/load_balancer_profiles_interface.rb +4 -5
- data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +13 -4
- data/lib/morpheus/api/load_balancers_interface.rb +5 -0
- data/lib/morpheus/api/network_routers_interface.rb +9 -0
- data/lib/morpheus/api/network_static_routes_interface.rb +36 -0
- data/lib/morpheus/api/read_interface.rb +4 -3
- data/lib/morpheus/api/rest_interface.rb +3 -3
- data/lib/morpheus/api/secondary_read_interface.rb +1 -1
- data/lib/morpheus/api/secondary_rest_interface.rb +19 -19
- data/lib/morpheus/api/storage_server_types_interface.rb +14 -0
- data/lib/morpheus/api/storage_servers_interface.rb +9 -0
- data/lib/morpheus/api/storage_volume_types_interface.rb +9 -0
- data/lib/morpheus/api/storage_volumes_interface.rb +9 -0
- data/lib/morpheus/api/users_interface.rb +16 -63
- data/lib/morpheus/cli/cli_command.rb +253 -5
- data/lib/morpheus/cli/cli_registry.rb +1 -1
- data/lib/morpheus/cli/commands/alias_command.rb +1 -1
- data/lib/morpheus/cli/commands/apps.rb +14 -78
- data/lib/morpheus/cli/commands/audit.rb +188 -0
- data/lib/morpheus/cli/commands/blueprints_command.rb +1 -1
- data/lib/morpheus/cli/commands/change_password_command.rb +4 -4
- data/lib/morpheus/cli/commands/clusters.rb +37 -12
- data/lib/morpheus/cli/commands/hosts.rb +15 -15
- data/lib/morpheus/cli/commands/instances.rb +109 -2
- data/lib/morpheus/cli/commands/load_balancer_monitors.rb +71 -0
- data/lib/morpheus/cli/commands/load_balancer_pools.rb +30 -50
- data/lib/morpheus/cli/commands/load_balancer_profiles.rb +65 -0
- data/lib/morpheus/cli/commands/load_balancer_types.rb +9 -4
- data/lib/morpheus/cli/commands/load_balancer_virtual_servers.rb +77 -57
- data/lib/morpheus/cli/commands/load_balancers.rb +93 -6
- data/lib/morpheus/cli/commands/network_firewalls_command.rb +22 -5
- data/lib/morpheus/cli/commands/network_routers_command.rb +96 -45
- data/lib/morpheus/cli/commands/network_static_routes_command.rb +446 -0
- data/lib/morpheus/cli/commands/network_transport_zones_command.rb +4 -4
- data/lib/morpheus/cli/commands/open_command.rb +30 -0
- data/lib/morpheus/cli/commands/options.rb +98 -0
- data/lib/morpheus/cli/commands/policies_command.rb +1 -1
- data/lib/morpheus/cli/commands/prices_command.rb +7 -7
- data/lib/morpheus/cli/commands/remote.rb +4 -2
- data/lib/morpheus/cli/commands/roles.rb +1 -1
- data/lib/morpheus/cli/commands/shell.rb +2 -2
- data/lib/morpheus/cli/commands/storage_server_types.rb +50 -0
- data/lib/morpheus/cli/commands/storage_servers.rb +122 -0
- data/lib/morpheus/cli/commands/storage_volume_types.rb +50 -0
- data/lib/morpheus/cli/commands/storage_volumes.rb +103 -0
- data/lib/morpheus/cli/commands/tenants_command.rb +1 -1
- data/lib/morpheus/cli/commands/user_groups_command.rb +1 -1
- data/lib/morpheus/cli/commands/user_settings_command.rb +2 -1
- data/lib/morpheus/cli/commands/user_sources_command.rb +1 -1
- data/lib/morpheus/cli/commands/users.rb +28 -28
- data/lib/morpheus/cli/commands/view.rb +102 -0
- data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -5
- data/lib/morpheus/cli/mixins/load_balancers_helper.rb +24 -4
- data/lib/morpheus/cli/mixins/print_helper.rb +50 -18
- data/lib/morpheus/cli/mixins/processes_helper.rb +1 -2
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +15 -5
- data/lib/morpheus/cli/mixins/rest_command.rb +145 -73
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +174 -81
- data/lib/morpheus/cli/mixins/storage_servers_helper.rb +156 -0
- data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +119 -0
- data/lib/morpheus/cli/option_types.rb +45 -24
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli.rb +1 -0
- data/lib/morpheus/ext/string.rb +29 -6
- data/lib/morpheus/routes.rb +238 -0
- data/lib/morpheus/util.rb +6 -1
- metadata +29 -8
@@ -85,6 +85,37 @@ module Morpheus::Cli::SecondaryRestCommand
|
|
85
85
|
|
86
86
|
alias :set_rest_parent_arg :rest_parent_arg=
|
87
87
|
|
88
|
+
def rest_parent_param
|
89
|
+
@rest_parent_param || default_rest_parent_param
|
90
|
+
end
|
91
|
+
|
92
|
+
def default_rest_parent_param
|
93
|
+
param = rest_parent_key.to_s.split('_').collect(&:capitalize).join
|
94
|
+
"#{param[0].downcase}#{param[1..-1]}Id"
|
95
|
+
end
|
96
|
+
|
97
|
+
def rest_parent_param=(v)
|
98
|
+
@rest_parent_param = v.to_s
|
99
|
+
end
|
100
|
+
|
101
|
+
alias :set_rest_parent_param :rest_parent_param=
|
102
|
+
|
103
|
+
# rest_parent_has_name indicates a resource has a name and can be retrieved by name or id
|
104
|
+
# true by default, set to false for lookups by only id
|
105
|
+
def rest_parent_has_name
|
106
|
+
@rest_parent_has_name != nil ? @rest_parent_has_name : default_rest_parent_has_name
|
107
|
+
end
|
108
|
+
|
109
|
+
def default_rest_parent_has_name
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
113
|
+
def rest_parent_has_name=(v)
|
114
|
+
@rest_parent_has_name = !!v
|
115
|
+
end
|
116
|
+
|
117
|
+
alias :set_rest_parent_has_name :rest_parent_has_name=
|
118
|
+
|
88
119
|
# rest_parent_label is the capitalized resource label eg. "Neat Thing"
|
89
120
|
def rest_parent_label
|
90
121
|
@rest_parent_label || default_rest_parent_label
|
@@ -147,6 +178,14 @@ module Morpheus::Cli::SecondaryRestCommand
|
|
147
178
|
self.class.rest_parent_arg
|
148
179
|
end
|
149
180
|
|
181
|
+
def rest_parent_param
|
182
|
+
self.class.rest_parent_param
|
183
|
+
end
|
184
|
+
|
185
|
+
def rest_parent_has_name
|
186
|
+
self.class.rest_parent_has_name
|
187
|
+
end
|
188
|
+
|
150
189
|
def rest_parent_label
|
151
190
|
self.class.rest_parent_label
|
152
191
|
end
|
@@ -164,23 +203,56 @@ module Morpheus::Cli::SecondaryRestCommand
|
|
164
203
|
end
|
165
204
|
|
166
205
|
def rest_parent_object_key
|
167
|
-
|
206
|
+
send("#{rest_parent_key}_object_key")
|
168
207
|
end
|
169
208
|
|
170
209
|
def rest_parent_list_key
|
171
|
-
|
210
|
+
send("#{rest_parent_key}_list_key")
|
172
211
|
end
|
173
212
|
|
174
|
-
def rest_parent_column_definitions
|
175
|
-
|
213
|
+
def rest_parent_column_definitions(options)
|
214
|
+
send("#{rest_parent_key}_column_definitions", options)
|
176
215
|
end
|
177
216
|
|
178
|
-
def rest_parent_list_column_definitions
|
179
|
-
|
217
|
+
def rest_parent_list_column_definitions(options)
|
218
|
+
send("#{rest_parent_key}_list_column_definitions", options)
|
219
|
+
end
|
220
|
+
|
221
|
+
def rest_parent_find_by_name_or_id(val)
|
222
|
+
# use explicitly defined finders
|
223
|
+
# else default to new generic CliCommand find_by methods
|
224
|
+
if rest_parent_has_name
|
225
|
+
if respond_to?("find_#{rest_parent_key}_by_name_or_id", true)
|
226
|
+
send("find_#{rest_parent_key}_by_name_or_id", val)
|
227
|
+
else
|
228
|
+
find_by_name_or_id(rest_parent_key, val)
|
229
|
+
end
|
230
|
+
else
|
231
|
+
if respond_to?("find_#{rest_parent_key}_by_id", true)
|
232
|
+
send("find_#{rest_parent_key}_by_id", val)
|
233
|
+
else
|
234
|
+
find_by_id(rest_parent_key, val)
|
235
|
+
end
|
236
|
+
end
|
180
237
|
end
|
181
238
|
|
182
|
-
|
183
|
-
|
239
|
+
# override RestCommand method to include parent_id parameter
|
240
|
+
def rest_find_by_name_or_id(parent_id, val)
|
241
|
+
# use explicitly defined finders
|
242
|
+
# else default to new generic CliCommand find_by methods
|
243
|
+
if rest_has_name
|
244
|
+
if respond_to?("find_#{rest_key}_by_name_or_id", true)
|
245
|
+
send("find_#{rest_key}_by_name_or_id", parent_id, val)
|
246
|
+
else
|
247
|
+
find_by_name_or_id(rest_key, parent_id, val)
|
248
|
+
end
|
249
|
+
else
|
250
|
+
if respond_to?("find_#{rest_key}_by_id", true)
|
251
|
+
send("find_#{rest_key}_by_id", parent_id, val)
|
252
|
+
else
|
253
|
+
find_by_id(rest_key, parent_id, val)
|
254
|
+
end
|
255
|
+
end
|
184
256
|
end
|
185
257
|
|
186
258
|
def registered_interfaces
|
@@ -193,29 +265,23 @@ module Morpheus::Cli::SecondaryRestCommand
|
|
193
265
|
options = {}
|
194
266
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
195
267
|
opts.banner = subcommand_usage("[#{rest_parent_arg}] [search]")
|
196
|
-
|
268
|
+
parse_list_options!(args, options, params)
|
197
269
|
opts.footer = <<-EOT
|
198
270
|
List #{rest_label_plural.downcase}.
|
199
|
-
[#{rest_parent_arg}] is required. This is the name or id of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
271
|
+
[#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
200
272
|
[search] is optional. This is a search phrase to filter the results.
|
201
273
|
EOT
|
202
274
|
end
|
203
275
|
optparse.parse!(args)
|
204
|
-
parent_id = args[0]
|
205
|
-
if args[1] # && rest_has_name
|
206
|
-
record_name = args[1]
|
207
|
-
end
|
208
276
|
verify_args!(args:args, optparse:optparse, min:1)
|
209
|
-
if args.count > 1
|
210
|
-
options[:phrase] = args[1..-1].join(" ")
|
211
|
-
end
|
212
277
|
connect(options)
|
278
|
+
parent_id = args[0]
|
213
279
|
parent_record = rest_parent_find_by_name_or_id(parent_id)
|
214
280
|
if parent_record.nil?
|
215
|
-
|
281
|
+
return 1, "#{rest_parent_label} not found for '#{parent_id}"
|
216
282
|
end
|
217
283
|
parent_id = parent_record['id']
|
218
|
-
|
284
|
+
parse_list_options!(args.count > 1 ? args[1..-1] : [], options, params)
|
219
285
|
rest_interface.setopts(options)
|
220
286
|
if options[:dry_run]
|
221
287
|
print_dry_run rest_interface.dry.list(parent_id, params)
|
@@ -228,7 +294,7 @@ EOT
|
|
228
294
|
if records.nil? || records.empty?
|
229
295
|
print cyan,"No #{rest_label_plural.downcase} found.",reset,"\n"
|
230
296
|
else
|
231
|
-
print as_pretty_table(records, rest_list_column_definitions.upcase_keys!, options)
|
297
|
+
print as_pretty_table(records, rest_list_column_definitions(options).upcase_keys!, options)
|
232
298
|
print_results_pagination(json_response) if json_response['meta']
|
233
299
|
end
|
234
300
|
print reset,"\n"
|
@@ -241,43 +307,41 @@ EOT
|
|
241
307
|
options = {}
|
242
308
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
243
309
|
opts.banner = subcommand_usage("[#{rest_parent_arg}] [#{rest_arg}]")
|
244
|
-
|
310
|
+
build_get_options(opts, options, params)
|
245
311
|
opts.footer = <<-EOT
|
246
312
|
Get details about #{a_or_an(rest_label)} #{rest_label.downcase}.
|
247
|
-
[#{rest_parent_arg}] is required. This is the name or id of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
248
|
-
[#{rest_arg}] is required. This is the name or id of #{a_or_an(rest_label)} #{rest_label.downcase}.
|
313
|
+
[#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
314
|
+
[#{rest_arg}] is required. This is the #{rest_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_label)} #{rest_label.downcase}.
|
249
315
|
EOT
|
250
316
|
end
|
251
317
|
optparse.parse!(args)
|
252
318
|
verify_args!(args:args, optparse:optparse, min:2)
|
253
319
|
connect(options)
|
320
|
+
parse_get_options!(args.count > 1 ? args[1..-1] : [], options, params)
|
254
321
|
parent_id = args[0]
|
255
322
|
parent_record = rest_parent_find_by_name_or_id(parent_id)
|
256
323
|
if parent_record.nil?
|
257
|
-
|
324
|
+
return 1, "#{rest_parent_label} not found for '#{parent_id}"
|
258
325
|
end
|
259
326
|
parent_id = parent_record['id']
|
260
|
-
|
261
|
-
|
262
|
-
return run_command_for_each_arg(id_list) do |arg|
|
263
|
-
_get(parent_id, arg, params, options)
|
264
|
-
end
|
327
|
+
id = args[1..-1].join(" ")
|
328
|
+
_get(parent_id, id, params, options)
|
265
329
|
end
|
266
330
|
|
267
331
|
def _get(parent_id, id, params, options)
|
268
332
|
if id !~ /\A\d{1,}\Z/
|
269
|
-
record = rest_find_by_name_or_id(id)
|
333
|
+
record = rest_find_by_name_or_id(parent_id, id)
|
270
334
|
if record.nil?
|
271
|
-
|
335
|
+
return 1, "#{rest_label} not found for '#{id}"
|
272
336
|
end
|
273
337
|
id = record['id']
|
274
338
|
end
|
275
339
|
rest_interface.setopts(options)
|
276
340
|
if options[:dry_run]
|
277
|
-
print_dry_run rest_interface.dry.get(id, params)
|
341
|
+
print_dry_run rest_interface.dry.get(parent_id, id, params)
|
278
342
|
return
|
279
343
|
end
|
280
|
-
json_response = rest_interface.get(id, params)
|
344
|
+
json_response = rest_interface.get(parent_id, id, params)
|
281
345
|
render_response_for_get(json_response, options)
|
282
346
|
return 0, nil
|
283
347
|
end
|
@@ -287,7 +351,7 @@ EOT
|
|
287
351
|
record = json_response[rest_object_key]
|
288
352
|
print_h1 rest_label, [], options
|
289
353
|
print cyan
|
290
|
-
print_description_list(rest_column_definitions, record, options)
|
354
|
+
print_description_list(rest_column_definitions(options), record, options)
|
291
355
|
# show config settings...
|
292
356
|
if record['optionTypes'] && record['optionTypes'].size > 0
|
293
357
|
print_h2 "Option Types", options
|
@@ -301,22 +365,22 @@ EOT
|
|
301
365
|
parent_id, parent_record = nil, nil
|
302
366
|
record_type_id = nil
|
303
367
|
options = {}
|
368
|
+
option_types = respond_to?("add_#{rest_key}_option_types", true) ? send("add_#{rest_key}_option_types") : []
|
369
|
+
advanced_option_types = respond_to?("add_#{rest_key}_advanced_option_types", true) ? send("add_#{rest_key}_advanced_option_types") : []
|
370
|
+
type_option_type = option_types.find {|it| it['fieldName'] == 'type'}
|
304
371
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
305
|
-
|
372
|
+
opts.banner = subcommand_usage("[#{rest_parent_arg}] [#{rest_arg}]")
|
373
|
+
if rest_has_type && type_option_type.nil?
|
306
374
|
opts.on( '-t', "--#{rest_type_arg} TYPE", "#{rest_type_label}" ) do |val|
|
307
375
|
record_type_id = val
|
308
376
|
end
|
309
377
|
end
|
310
|
-
|
311
|
-
|
312
|
-
end
|
313
|
-
if self.class.method_defined?("add_#{rest_key}_advanced_option_types")
|
314
|
-
build_option_type_options(opts, options, self.send("add_#{rest_key}_advanced_option_types"))
|
315
|
-
end
|
378
|
+
build_option_type_options(opts, options, option_types)
|
379
|
+
build_option_type_options(opts, options, advanced_option_types)
|
316
380
|
build_standard_add_options(opts, options)
|
317
381
|
opts.footer = <<-EOT
|
318
382
|
Create a new #{rest_label.downcase}.
|
319
|
-
[#{rest_parent_arg}] is required. This is the name or id of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
383
|
+
[#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
320
384
|
[#{rest_arg}] is required. This is the name of the new #{rest_label.downcase}.
|
321
385
|
EOT
|
322
386
|
end
|
@@ -326,31 +390,39 @@ EOT
|
|
326
390
|
# for now args[0] is assumed to be the 'name'
|
327
391
|
record_name = nil
|
328
392
|
parent_id = args[0]
|
329
|
-
if
|
330
|
-
|
393
|
+
if rest_has_name
|
394
|
+
if args[1]
|
395
|
+
record_name = args[1]
|
396
|
+
end
|
397
|
+
verify_args!(args:args, optparse:optparse, min:1, max: 2)
|
398
|
+
else
|
399
|
+
verify_args!(args:args, optparse:optparse, count: 1)
|
331
400
|
end
|
332
401
|
connect(options)
|
333
402
|
# load parent record
|
334
403
|
# todo: prompt instead of error
|
335
404
|
parent_record = rest_parent_find_by_name_or_id(parent_id)
|
336
405
|
if parent_record.nil?
|
337
|
-
|
406
|
+
return 1, "#{rest_parent_label} not found for '#{parent_id}"
|
338
407
|
end
|
339
408
|
parent_id = parent_record['id']
|
340
409
|
# load or prompt for type
|
341
|
-
if rest_has_type
|
410
|
+
if rest_has_type && type_option_type.nil?
|
342
411
|
if record_type_id.nil?
|
343
412
|
#raise_command_error "#{rest_type_label} is required.\n#{optparse}"
|
344
|
-
type_list = rest_type_interface.list({max:10000})[rest_type_list_key]
|
413
|
+
type_list = rest_type_interface.list({max:10000, creatable: true})[rest_type_list_key]
|
345
414
|
type_dropdown_options = type_list.collect {|it| {'name' => it['name'], 'value' => it['code']} }
|
346
415
|
record_type_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => rest_type_label, 'type' => 'select', 'selectOptions' => type_dropdown_options, 'required' => true}], options[:options], @api_client)['type']
|
347
416
|
end
|
348
417
|
record_type = rest_type_find_by_name_or_id(record_type_id)
|
349
418
|
if record_type.nil?
|
350
|
-
|
419
|
+
return 1, "#{rest_type_label} not found for '#{record_type_id}"
|
351
420
|
end
|
352
421
|
end
|
353
422
|
passed_options = parse_passed_options(options)
|
423
|
+
options[:params] ||= {}
|
424
|
+
options[:params][rest_parent_param] = parent_id
|
425
|
+
options[:options]['_object_key'] = rest_object_key
|
354
426
|
payload = {}
|
355
427
|
if options[:payload]
|
356
428
|
payload = options[:payload]
|
@@ -360,25 +432,41 @@ EOT
|
|
360
432
|
if record_name
|
361
433
|
record_payload['name'] = record_name
|
362
434
|
options[:options]['name'] = record_name # injected for prompt
|
435
|
+
options[:options][rest_arg] = record_name
|
363
436
|
end
|
364
437
|
if rest_has_type && record_type
|
365
438
|
# record_payload['type'] = {'code' => record_type['code']}
|
366
439
|
record_payload['type'] = record_type['code']
|
367
440
|
options[:options]['type'] = record_type['code'] # injected for prompt
|
368
441
|
# initialize params for loading optionSource data
|
369
|
-
options[:params] ||= {}
|
370
442
|
options[:params]['type'] = record_type['code']
|
371
443
|
end
|
372
444
|
record_payload.deep_merge!(passed_options)
|
373
|
-
if
|
374
|
-
|
375
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt(add_option_types, options[:options], @api_client, options[:params])
|
445
|
+
if option_types && !option_types.empty?
|
446
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
|
376
447
|
v_prompt.deep_compact!
|
377
448
|
v_prompt.booleanize! # 'on' => true
|
378
449
|
record_payload.deep_merge!(v_prompt)
|
379
450
|
end
|
380
451
|
# options by type
|
381
|
-
|
452
|
+
if rest_has_type && record_type.nil?
|
453
|
+
type_value = record_payload['type'].is_a?(Hash) ? record_payload['type']['id'] : record_payload['type']
|
454
|
+
if type_value
|
455
|
+
record_type = rest_type_find_by_name_or_id(type_value)
|
456
|
+
if record_type.nil?
|
457
|
+
return 1, "#{rest_type_label} not found for '#{type_value}"
|
458
|
+
end
|
459
|
+
end
|
460
|
+
# reload the type by id to get all the details ie. optionTypes
|
461
|
+
if record_type && record_type['optionTypes'].nil?
|
462
|
+
record_type = rest_type_find_by_name_or_id(record_type['id'])
|
463
|
+
end
|
464
|
+
end
|
465
|
+
if respond_to?("load_option_types_for_#{rest_key}", true)
|
466
|
+
my_option_types = send("load_option_types_for_#{rest_key}", record_type, parent_record)
|
467
|
+
else
|
468
|
+
my_option_types = record_type ? record_type['optionTypes'] : nil
|
469
|
+
end
|
382
470
|
if my_option_types && !my_option_types.empty?
|
383
471
|
# remove redundant fieldContext
|
384
472
|
my_option_types.each do |option_type|
|
@@ -386,15 +474,15 @@ EOT
|
|
386
474
|
option_type['fieldContext'] = nil
|
387
475
|
end
|
388
476
|
end
|
389
|
-
|
477
|
+
api_params = (options[:params] || {}).merge(record_payload)
|
478
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, api_params)
|
390
479
|
v_prompt.deep_compact!
|
391
480
|
v_prompt.booleanize! # 'on' => true
|
392
481
|
record_payload.deep_merge!(v_prompt)
|
393
482
|
end
|
394
483
|
# advanced options (uses no_prompt)
|
395
|
-
if
|
396
|
-
|
397
|
-
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(add_advanced_option_types, options[:options], @api_client, options[:params])
|
484
|
+
if advanced_option_types && !advanced_option_types.empty?
|
485
|
+
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(advanced_option_types, options[:options], @api_client, options[:params])
|
398
486
|
v_prompt.deep_compact!
|
399
487
|
v_prompt.booleanize! # 'on' => true
|
400
488
|
record_payload.deep_merge!(v_prompt)
|
@@ -421,31 +509,28 @@ EOT
|
|
421
509
|
record_type = nil
|
422
510
|
record_type_id = nil
|
423
511
|
options = {}
|
424
|
-
|
512
|
+
option_types = respond_to?("update_#{rest_key}_option_types", true) ? send("update_#{rest_key}_option_types") : []
|
513
|
+
advanced_option_types = respond_to?("update_#{rest_key}_advanced_option_types", true) ? send("update_#{rest_key}_advanced_option_types") : []
|
425
514
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
426
515
|
opts.banner = subcommand_usage("[#{rest_parent_arg}] [#{rest_arg}] [options]")
|
427
|
-
|
428
|
-
build_option_type_options(opts, options, self.send("update_#{rest_key}_option_types"))
|
429
|
-
end
|
430
|
-
if self.class.method_defined?("update_#{rest_key}_advanced_option_types")
|
431
|
-
build_option_type_options(opts, options, self.send("update_#{rest_key}_advanced_option_types"))
|
432
|
-
end
|
516
|
+
|
433
517
|
build_standard_update_options(opts, options)
|
434
518
|
opts.footer = <<-EOT
|
435
519
|
Update an existing #{rest_label.downcase}.
|
436
|
-
[#{rest_parent_arg}] is required. This is the name or id of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
437
|
-
[#{rest_arg}] is required. This is the name or id of #{a_or_an(rest_label)} #{rest_label.downcase}.
|
520
|
+
[#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
521
|
+
[#{rest_arg}] is required. This is the #{rest_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_label)} #{rest_label.downcase}.
|
438
522
|
EOT
|
439
523
|
end
|
440
524
|
optparse.parse!(args)
|
441
525
|
verify_args!(args:args, optparse:optparse, count:2)
|
526
|
+
connect(options)
|
442
527
|
parent_record = rest_parent_find_by_name_or_id(parent_id)
|
443
528
|
if parent_record.nil?
|
444
|
-
|
529
|
+
return 1, "#{rest_parent_label} not found for '#{parent_id}"
|
445
530
|
end
|
446
531
|
parent_id = parent_record['id']
|
447
532
|
connect(options)
|
448
|
-
record = rest_find_by_name_or_id(id)
|
533
|
+
record = rest_find_by_name_or_id(parent_id, id)
|
449
534
|
if record.nil?
|
450
535
|
return 1, "#{rest_name} not found for '#{id}'"
|
451
536
|
end
|
@@ -454,7 +539,11 @@ EOT
|
|
454
539
|
record_type_id = record['type']['id']
|
455
540
|
record_type = rest_type_find_by_name_or_id(record_type_id)
|
456
541
|
if record_type.nil?
|
457
|
-
|
542
|
+
return 1, "#{rest_type_label} not found for '#{record_type_id}"
|
543
|
+
end
|
544
|
+
# reload the type by id to get all the details ie. optionTypes
|
545
|
+
if record_type['optionTypes'].nil?
|
546
|
+
record_type = rest_type_find_by_name_or_id(record_type['id'])
|
458
547
|
end
|
459
548
|
end
|
460
549
|
passed_options = parse_passed_options(options)
|
@@ -473,15 +562,20 @@ EOT
|
|
473
562
|
options[:params]['type'] = record_type['code']
|
474
563
|
end
|
475
564
|
# update options without prompting by default
|
476
|
-
if
|
477
|
-
|
478
|
-
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(
|
565
|
+
if option_types && !option_types.empty?
|
566
|
+
api_params = (options[:params] || {}).merge(record_payload) # need to merge in values from record too, ughhh
|
567
|
+
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(option_types, options[:options], @api_client, api_params)
|
479
568
|
v_prompt.deep_compact!
|
480
569
|
v_prompt.booleanize! # 'on' => true
|
481
570
|
record_payload.deep_merge!(v_prompt)
|
482
571
|
end
|
483
572
|
# options by type
|
484
|
-
my_option_types =
|
573
|
+
my_option_types = nil
|
574
|
+
if respond_to?("load_option_types_for_#{rest_key}", true)
|
575
|
+
my_option_types = send("load_option_types_for_#{rest_key}", record_type, parent_record)
|
576
|
+
else
|
577
|
+
my_option_types = record_type ? record_type['optionTypes'] : nil
|
578
|
+
end
|
485
579
|
if my_option_types && !my_option_types.empty?
|
486
580
|
# remove redundant fieldContext
|
487
581
|
# make them optional for updates
|
@@ -500,9 +594,8 @@ EOT
|
|
500
594
|
record_payload.deep_merge!(v_prompt)
|
501
595
|
end
|
502
596
|
# advanced options
|
503
|
-
if
|
504
|
-
|
505
|
-
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_advanced_option_types, options[:options], @api_client, options[:params])
|
597
|
+
if advanced_option_types && !advanced_option_types.empty?
|
598
|
+
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(advanced_option_types, options[:options], @api_client, options[:params])
|
506
599
|
v_prompt.deep_compact!
|
507
600
|
v_prompt.booleanize! # 'on' => true
|
508
601
|
record_payload.deep_merge!(v_prompt)
|
@@ -540,8 +633,8 @@ EOT
|
|
540
633
|
build_standard_remove_options(opts, options)
|
541
634
|
opts.footer = <<-EOT
|
542
635
|
Delete an existing #{rest_label.downcase}.
|
543
|
-
[#{rest_parent_arg}] is required. This is the name or id of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
544
|
-
[#{rest_arg}] is required. This is the name or id of #{a_or_an(rest_label)} #{rest_label.downcase}.
|
636
|
+
[#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
|
637
|
+
[#{rest_arg}] is required. This is the #{rest_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_label)} #{rest_label.downcase}.
|
545
638
|
EOT
|
546
639
|
end
|
547
640
|
optparse.parse!(args)
|
@@ -549,9 +642,9 @@ EOT
|
|
549
642
|
connect(options)
|
550
643
|
parent_record = rest_parent_find_by_name_or_id(parent_id)
|
551
644
|
if parent_record.nil?
|
552
|
-
|
645
|
+
return 1, "#{rest_parent_label} not found for '#{parent_id}"
|
553
646
|
end
|
554
|
-
record = rest_find_by_name_or_id(id)
|
647
|
+
record = rest_find_by_name_or_id(parent_id, id)
|
555
648
|
if record.nil?
|
556
649
|
return 1, "#{rest_name} not found for '#{id}'"
|
557
650
|
end
|
@@ -561,7 +654,7 @@ EOT
|
|
561
654
|
params.merge!(parse_query_options(options))
|
562
655
|
rest_interface.setopts(options)
|
563
656
|
if options[:dry_run]
|
564
|
-
print_dry_run rest_interface.dry.destroy(parent_id, record['id'])
|
657
|
+
print_dry_run rest_interface.dry.destroy(parent_id, record['id'], params)
|
565
658
|
return 0, nil
|
566
659
|
end
|
567
660
|
json_response = rest_interface.destroy(parent_id, record['id'], params)
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'morpheus/cli/mixins/print_helper'
|
2
|
+
require 'morpheus/cli/option_types'
|
3
|
+
require 'morpheus/rest_client'
|
4
|
+
# Mixin for Morpheus::Cli command classes
|
5
|
+
# Provides common methods for storage server management
|
6
|
+
# including storage servers and storage server types
|
7
|
+
module Morpheus::Cli::StorageServersHelper
|
8
|
+
|
9
|
+
def self.included(klass)
|
10
|
+
klass.send :include, Morpheus::Cli::PrintHelper
|
11
|
+
end
|
12
|
+
|
13
|
+
def storage_servers_interface
|
14
|
+
# @api_client.storage_servers
|
15
|
+
raise "#{self.class} has not defined @storage_servers_interface" if @storage_servers_interface.nil?
|
16
|
+
@storage_servers_interface
|
17
|
+
end
|
18
|
+
|
19
|
+
def storage_server_types_interface
|
20
|
+
# @api_client.storage_server_types
|
21
|
+
raise "#{self.class} has not defined @storage_server_types_interface" if @storage_server_types_interface.nil?
|
22
|
+
@storage_server_types_interface
|
23
|
+
end
|
24
|
+
|
25
|
+
def storage_server_object_key
|
26
|
+
'storageServer'
|
27
|
+
end
|
28
|
+
|
29
|
+
def storage_server_list_key
|
30
|
+
'storageServers'
|
31
|
+
end
|
32
|
+
|
33
|
+
def storage_server_label
|
34
|
+
'Storage Server'
|
35
|
+
end
|
36
|
+
|
37
|
+
def storage_server_label_plural
|
38
|
+
'Storage Server'
|
39
|
+
end
|
40
|
+
|
41
|
+
def storage_server_type_object_key
|
42
|
+
'storageServerType'
|
43
|
+
end
|
44
|
+
|
45
|
+
def storage_server_type_list_key
|
46
|
+
'storageServerTypes'
|
47
|
+
end
|
48
|
+
|
49
|
+
def storage_server_type_label
|
50
|
+
'Storage Server Type'
|
51
|
+
end
|
52
|
+
|
53
|
+
def storage_server_type_label_plural
|
54
|
+
'Storage Server Types'
|
55
|
+
end
|
56
|
+
|
57
|
+
def find_storage_server_by_name_or_id(val)
|
58
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
59
|
+
return find_storage_server_by_id(val)
|
60
|
+
else
|
61
|
+
return find_storage_server_by_name(val)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_storage_server_by_id(id)
|
66
|
+
begin
|
67
|
+
json_response = storage_servers_interface.get(id.to_i)
|
68
|
+
return json_response[storage_server_object_key]
|
69
|
+
rescue RestClient::Exception => e
|
70
|
+
if e.response && e.response.code == 404
|
71
|
+
print_red_alert "Storage Server not found by id #{id}"
|
72
|
+
else
|
73
|
+
raise e
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_storage_server_by_name(name)
|
79
|
+
lbs = storage_servers_interface.list({name: name.to_s})[storage_server_list_key]
|
80
|
+
if lbs.empty?
|
81
|
+
print_red_alert "Storage Server not found by name #{name}"
|
82
|
+
return nil
|
83
|
+
elsif lbs.size > 1
|
84
|
+
print_red_alert "#{lbs.size} storage servers found by name #{name}"
|
85
|
+
#print_lbs_table(lbs, {color: red})
|
86
|
+
print reset,"\n\n"
|
87
|
+
return nil
|
88
|
+
else
|
89
|
+
return lbs[0]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_available_storage_server_types(refresh=false)
|
94
|
+
if !@available_storage_server_types || refresh
|
95
|
+
@available_storage_server_types = storage_server_types_interface.list({max:1000})[storage_server_type_list_key]
|
96
|
+
end
|
97
|
+
return @available_storage_server_types
|
98
|
+
end
|
99
|
+
|
100
|
+
def storage_server_type_for_name_or_id(val)
|
101
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
102
|
+
return storage_server_type_for_id(val)
|
103
|
+
else
|
104
|
+
return storage_server_type_for_name(val)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def storage_server_type_for_id(id)
|
109
|
+
return get_available_storage_server_types().find { |z| z['id'].to_i == id.to_i}
|
110
|
+
end
|
111
|
+
|
112
|
+
def storage_server_type_for_name(name)
|
113
|
+
return get_available_storage_server_types().find { |z| z['name'].downcase == name.downcase || z['code'].downcase == name.downcase}
|
114
|
+
end
|
115
|
+
|
116
|
+
def find_storage_server_type_by_name_or_id(val)
|
117
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
118
|
+
return find_storage_server_type_by_id(val)
|
119
|
+
else
|
120
|
+
return find_storage_server_type_by_name(val)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def find_storage_server_type_by_id(id)
|
125
|
+
begin
|
126
|
+
json_response = storage_server_types_interface.get(id.to_i)
|
127
|
+
return json_response[storage_server_type_object_key]
|
128
|
+
rescue RestClient::Exception => e
|
129
|
+
if e.response && e.response.code == 404
|
130
|
+
print_red_alert "Storage Server Type not found by id #{id}"
|
131
|
+
return nil
|
132
|
+
else
|
133
|
+
raise e
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def find_storage_server_type_by_name(name)
|
139
|
+
json_response = storage_server_types_interface.list({name: name.to_s})
|
140
|
+
storage_server_types = json_response[storage_server_type_list_key]
|
141
|
+
if storage_server_types.empty?
|
142
|
+
print_red_alert "Storage Server Type not found by name #{name}"
|
143
|
+
return storage_server_types
|
144
|
+
elsif storage_server_types.size > 1
|
145
|
+
print_red_alert "#{storage_server_types.size} storage server types found by name #{name}"
|
146
|
+
rows = storage_server_types.collect do |it|
|
147
|
+
{id: it['id'], name: it['name']}
|
148
|
+
end
|
149
|
+
puts as_pretty_table(rows, [:id, :name], {color:red})
|
150
|
+
return nil
|
151
|
+
else
|
152
|
+
return storage_server_types[0]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|