morpheus-cli 4.2.14 → 4.2.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/README.md +8 -6
- data/lib/morpheus/api/api_client.rb +32 -14
- data/lib/morpheus/api/auth_interface.rb +4 -2
- data/lib/morpheus/api/backup_jobs_interface.rb +9 -0
- data/lib/morpheus/api/backups_interface.rb +16 -0
- data/lib/morpheus/api/deploy_interface.rb +25 -56
- data/lib/morpheus/api/deployments_interface.rb +44 -55
- data/lib/morpheus/api/doc_interface.rb +57 -0
- data/lib/morpheus/api/instances_interface.rb +5 -0
- data/lib/morpheus/api/rest_interface.rb +40 -0
- data/lib/morpheus/api/user_sources_interface.rb +0 -15
- data/lib/morpheus/api/users_interface.rb +2 -3
- data/lib/morpheus/benchmarking.rb +2 -2
- data/lib/morpheus/cli.rb +4 -1
- data/lib/morpheus/cli/access_token_command.rb +27 -10
- data/lib/morpheus/cli/apps.rb +21 -15
- data/lib/morpheus/cli/backup_jobs_command.rb +276 -0
- data/lib/morpheus/cli/backups_command.rb +271 -0
- data/lib/morpheus/cli/blueprints_command.rb +27 -61
- data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +183 -45
- data/lib/morpheus/cli/cli_registry.rb +3 -0
- data/lib/morpheus/cli/clouds.rb +7 -10
- data/lib/morpheus/cli/clusters.rb +0 -18
- data/lib/morpheus/cli/commands/standard/benchmark_command.rb +23 -20
- data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
- data/lib/morpheus/cli/credentials.rb +13 -9
- data/lib/morpheus/cli/deploy.rb +374 -0
- data/lib/morpheus/cli/deployments.rb +521 -197
- data/lib/morpheus/cli/deploys.rb +271 -126
- data/lib/morpheus/cli/doc.rb +182 -0
- data/lib/morpheus/cli/error_handler.rb +23 -8
- data/lib/morpheus/cli/errors.rb +3 -2
- data/lib/morpheus/cli/image_builder_command.rb +2 -2
- data/lib/morpheus/cli/instances.rb +136 -17
- data/lib/morpheus/cli/invoices_command.rb +339 -225
- data/lib/morpheus/cli/jobs_command.rb +2 -2
- data/lib/morpheus/cli/library_layouts_command.rb +1 -1
- data/lib/morpheus/cli/library_option_lists_command.rb +61 -125
- data/lib/morpheus/cli/library_option_types_command.rb +32 -37
- data/lib/morpheus/cli/login.rb +9 -3
- data/lib/morpheus/cli/mixins/accounts_helper.rb +158 -100
- data/lib/morpheus/cli/mixins/backups_helper.rb +115 -0
- data/lib/morpheus/cli/mixins/deployments_helper.rb +135 -0
- data/lib/morpheus/cli/mixins/library_helper.rb +32 -0
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +149 -84
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -2
- data/lib/morpheus/cli/mixins/whoami_helper.rb +19 -6
- data/lib/morpheus/cli/network_routers_command.rb +1 -1
- data/lib/morpheus/cli/option_parser.rb +48 -5
- data/lib/morpheus/cli/option_types.rb +46 -10
- data/lib/morpheus/cli/price_sets_command.rb +1 -1
- data/lib/morpheus/cli/projects_command.rb +7 -7
- data/lib/morpheus/cli/remote.rb +3 -2
- data/lib/morpheus/cli/roles.rb +49 -92
- data/lib/morpheus/cli/security_groups.rb +7 -1
- data/lib/morpheus/cli/service_plans_command.rb +10 -10
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +7 -6
- data/lib/morpheus/cli/subnets_command.rb +1 -1
- data/lib/morpheus/cli/tasks.rb +24 -10
- data/lib/morpheus/cli/tenants_command.rb +133 -163
- data/lib/morpheus/cli/user_groups_command.rb +20 -65
- data/lib/morpheus/cli/user_settings_command.rb +115 -13
- data/lib/morpheus/cli/user_sources_command.rb +57 -24
- data/lib/morpheus/cli/users.rb +210 -186
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +29 -5
- data/lib/morpheus/cli/whoami.rb +113 -6
- data/lib/morpheus/cli/workflows.rb +11 -8
- data/lib/morpheus/ext/hash.rb +21 -0
- data/lib/morpheus/formatters.rb +7 -19
- data/lib/morpheus/terminal.rb +1 -0
- metadata +12 -3
- data/lib/morpheus/cli/auth_command.rb +0 -105
@@ -768,7 +768,7 @@ class Morpheus::Cli::JobsCommand
|
|
768
768
|
params = {}
|
769
769
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
770
770
|
opts.banner = subcommand_usage("[id]")
|
771
|
-
opts.on('-D', '--details [on|off]', String, "Can be used to enable / disable execution details. Default
|
771
|
+
opts.on('-D', '--details [on|off]', String, "Can be used to enable / disable execution details. Default is on") do |val|
|
772
772
|
options[:details] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
773
773
|
end
|
774
774
|
build_common_options(opts, options, [:json, :dry_run, :remote])
|
@@ -970,7 +970,7 @@ class Morpheus::Cli::JobsCommand
|
|
970
970
|
def format_status(status_string, return_color=cyan)
|
971
971
|
out = ""
|
972
972
|
if status_string
|
973
|
-
if ['success', 'successful', 'ok'].include?(status_string)
|
973
|
+
if ['complete','success', 'successful', 'ok'].include?(status_string)
|
974
974
|
out << "#{green}#{status_string.upcase}"
|
975
975
|
elsif ['error', 'offline', 'failed', 'failure'].include?(status_string)
|
976
976
|
out << "#{red}#{status_string.upcase}"
|
@@ -652,7 +652,7 @@ EOT
|
|
652
652
|
connect(options)
|
653
653
|
exit_code, err = 0, nil
|
654
654
|
# if !is_master_account
|
655
|
-
# print_red_alert "Permissions only available for master
|
655
|
+
# print_red_alert "Permissions only available for master tenant"
|
656
656
|
# return 1
|
657
657
|
# end
|
658
658
|
layout = find_layout_by_name_or_id(nil, args[0])
|
@@ -186,49 +186,42 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
186
186
|
my_option_types = nil
|
187
187
|
list_type = nil
|
188
188
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
189
|
-
opts.banner = subcommand_usage("[
|
190
|
-
opts.on( '-t', '--type TYPE', "Option List Type. (rest, manual)" ) do |val|
|
191
|
-
list_type = val
|
192
|
-
# options[:options] ||= {}
|
193
|
-
# options[:options]['type'] = val
|
194
|
-
end
|
189
|
+
opts.banner = subcommand_usage("[name] [options]")
|
195
190
|
build_option_type_options(opts, options, new_option_type_list_option_types())
|
196
191
|
build_standard_add_options(opts, options)
|
197
192
|
opts.footer = "Create a new option list."
|
198
193
|
end
|
199
194
|
optparse.parse!(args)
|
200
|
-
|
201
|
-
|
195
|
+
verify_args!(args:args, optparse:optparse, max:1)
|
196
|
+
if args.count == 1
|
197
|
+
options[:options]['name'] = args[0]
|
198
|
+
end
|
199
|
+
|
202
200
|
connect(options)
|
203
201
|
begin
|
204
|
-
passed_options = options[:options].reject {|k,v| k.is_a?(Symbol) }
|
205
202
|
payload = nil
|
206
203
|
if options[:payload]
|
207
204
|
payload = options[:payload]
|
208
|
-
|
209
|
-
if !passed_options.empty?
|
210
|
-
payload['optionTypeList'] ||= {}
|
211
|
-
payload['optionTypeList'].deep_merge!(passed_options)
|
212
|
-
end
|
205
|
+
payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
|
213
206
|
else
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
params = passed_options
|
219
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt(new_option_type_list_option_types(list_type), options[:options], @api_client, options[:params])
|
220
|
-
params.deep_merge!(v_prompt)
|
221
|
-
params['type'] = list_type
|
222
|
-
if params['type'] == 'rest'
|
207
|
+
payload = {}
|
208
|
+
payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
|
209
|
+
list_payload = Morpheus::Cli::OptionTypes.prompt(new_option_type_list_option_types(), options[:options], @api_client, options[:params])
|
210
|
+
if list_payload['type'] == 'rest'
|
223
211
|
# prompt for Source Headers
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
212
|
+
if !(payload['optionTypeList']['config'] && payload['optionTypeList']['config']['sourceHeaders'])
|
213
|
+
source_headers = prompt_source_headers(options)
|
214
|
+
if !source_headers.empty?
|
215
|
+
list_payload['config'] ||= {}
|
216
|
+
list_payload['config']['sourceHeaders'] = source_headers
|
217
|
+
end
|
228
218
|
end
|
229
219
|
end
|
230
|
-
|
231
|
-
|
220
|
+
# tweak payload for API
|
221
|
+
['ignoreSSLErrors', 'realTime'].each { |k|
|
222
|
+
list_payload[k] = ['on','true'].include?(list_payload[k].to_s) if list_payload.key?(k)
|
223
|
+
}
|
224
|
+
payload.deep_merge!({'optionTypeList' => list_payload})
|
232
225
|
end
|
233
226
|
@option_type_lists_interface.setopts(options)
|
234
227
|
if options[:dry_run]
|
@@ -262,41 +255,31 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
262
255
|
begin
|
263
256
|
option_type_list = find_option_type_list_by_name_or_id(args[0])
|
264
257
|
exit 1 if option_type_list.nil?
|
265
|
-
passed_options = options[:options].reject {|k,v| k.is_a?(Symbol) }
|
266
258
|
payload = nil
|
267
259
|
if options[:payload]
|
268
260
|
payload = options[:payload]
|
269
|
-
|
270
|
-
if !passed_options.empty?
|
271
|
-
payload['optionTypeList'] ||= {}
|
272
|
-
payload['optionTypeList'].deep_merge!(passed_options)
|
273
|
-
end
|
261
|
+
payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
|
274
262
|
else
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
params.deep_merge!(v_prompt)
|
280
|
-
|
281
|
-
if list_type == 'rest'
|
263
|
+
payload = {}
|
264
|
+
payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
|
265
|
+
list_payload = Morpheus::Cli::OptionTypes.no_prompt(update_option_type_option_types(), options[:options], @api_client)
|
266
|
+
if list_payload['type'] == 'rest'
|
282
267
|
# parse Source Headers
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
268
|
+
if !(payload['optionTypeList']['config'] && payload['optionTypeList']['config']['sourceHeaders'])
|
269
|
+
source_headers = prompt_source_headers(options.merge({no_prompt: true}))
|
270
|
+
if !source_headers.empty?
|
271
|
+
#params['config'] ||= option_type_list['config'] || {}
|
272
|
+
params['config'] ||= {}
|
273
|
+
params['config']['sourceHeaders'] = source_headers
|
274
|
+
end
|
288
275
|
end
|
289
276
|
end
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
if
|
296
|
-
params['required'] = ['on','true'].include?(params['required'].to_s)
|
297
|
-
end
|
298
|
-
list_payload = params
|
299
|
-
payload = {'optionTypeList' => list_payload}
|
277
|
+
# tweak payload for API
|
278
|
+
['ignoreSSLErrors', 'realTime'].each { |k|
|
279
|
+
list_payload[k] = ['on','true'].include?(list_payload[k].to_s) if list_payload.key?(k)
|
280
|
+
}
|
281
|
+
payload.deep_merge!({'optionTypeList' => list_payload})
|
282
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}" if payload['optionTypeList'].empty?
|
300
283
|
end
|
301
284
|
@option_type_lists_interface.setopts(options)
|
302
285
|
if options[:dry_run]
|
@@ -355,42 +338,13 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
355
338
|
|
356
339
|
private
|
357
340
|
|
358
|
-
|
359
|
-
if val.to_s =~ /\A\d{1,}\Z/
|
360
|
-
return find_option_type_list_by_id(val)
|
361
|
-
else
|
362
|
-
return find_option_type_list_by_name(val)
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
def find_option_type_list_by_id(id)
|
367
|
-
begin
|
368
|
-
json_response = @option_type_lists_interface.get(id.to_i)
|
369
|
-
return json_response['optionTypeList']
|
370
|
-
rescue RestClient::Exception => e
|
371
|
-
if e.response && e.response.code == 404
|
372
|
-
print_red_alert "Option List not found by id #{id}"
|
373
|
-
exit 1
|
374
|
-
else
|
375
|
-
raise e
|
376
|
-
end
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
|
-
def find_option_type_list_by_name(name)
|
381
|
-
json_results = @option_type_lists_interface.list({name: name.to_s})
|
382
|
-
if json_results['optionTypeLists'].empty?
|
383
|
-
print_red_alert "Option List not found by name #{name}"
|
384
|
-
exit 1
|
385
|
-
end
|
386
|
-
option_type_list = json_results['optionTypeLists'][0]
|
387
|
-
return option_type_list
|
388
|
-
end
|
341
|
+
# finders are in LibraryHelper
|
389
342
|
|
390
343
|
def get_available_option_list_types
|
391
344
|
[
|
392
345
|
{'name' => 'REST', 'value' => 'rest'},
|
393
346
|
{'name' => 'Morpheus Api', 'value' => 'api'},
|
347
|
+
{'name' => 'LDAP', 'value' => 'ldap'},
|
394
348
|
{'name' => 'Manual', 'value' => 'manual'}
|
395
349
|
]
|
396
350
|
end
|
@@ -399,49 +353,31 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
399
353
|
get_available_option_list_types.find {|it| code == it['value'] || code == it['name'] }
|
400
354
|
end
|
401
355
|
|
402
|
-
def new_option_type_list_option_types(
|
403
|
-
|
404
|
-
|
356
|
+
def new_option_type_list_option_types()
|
357
|
+
[
|
358
|
+
# rest
|
405
359
|
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
406
360
|
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
|
407
|
-
|
408
|
-
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' =>
|
409
|
-
{'fieldName' => 'sourceUrl', 'fieldLabel' => 'Source Url', 'type' => 'text', 'required' => true, 'description' => "A REST URL can be used to fetch list data and is cached in the appliance database.", 'displayOrder' =>
|
410
|
-
{'fieldName' => 'ignoreSSLErrors', 'fieldLabel' => 'Ignore SSL Errors', 'type' => 'checkbox', 'defaultValue' =>
|
411
|
-
{'fieldName' => 'realTime', 'fieldLabel' => 'Real Time', 'type' => 'checkbox', 'defaultValue' =>
|
412
|
-
{'fieldName' => 'sourceMethod', 'fieldLabel' => 'Source Method', 'type' => 'select', 'selectOptions' => [{'name' => 'GET', 'value' => 'GET'}, {'name' => 'POST', 'value' => 'POST'}], 'defaultValue' => 'GET', 'required' => true, 'displayOrder' =>
|
361
|
+
{'code' => 'optionTypeList.type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => get_available_option_list_types, 'defaultValue' => 'rest', 'required' => true, 'description' => 'Option List Type. eg. rest, api, ldap, manual', 'displayOrder' => 3},
|
362
|
+
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 4},
|
363
|
+
{'dependsOnCode' => 'optionTypeList.type:rest', 'fieldName' => 'sourceUrl', 'fieldLabel' => 'Source Url', 'type' => 'text', 'required' => true, 'description' => "A REST URL can be used to fetch list data and is cached in the appliance database.", 'displayOrder' => 5},
|
364
|
+
{'dependsOnCode' => 'optionTypeList.type:rest', 'fieldName' => 'ignoreSSLErrors', 'fieldLabel' => 'Ignore SSL Errors', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 6},
|
365
|
+
{'dependsOnCode' => 'optionTypeList.type:rest', 'fieldName' => 'realTime', 'fieldLabel' => 'Real Time', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 7},
|
366
|
+
{'dependsOnCode' => 'optionTypeList.type:rest', 'fieldName' => 'sourceMethod', 'fieldLabel' => 'Source Method', 'type' => 'select', 'selectOptions' => [{'name' => 'GET', 'value' => 'GET'}, {'name' => 'POST', 'value' => 'POST'}], 'defaultValue' => 'GET', 'required' => true, 'displayOrder' => 8},
|
413
367
|
# sourceHeaders component (is done afterwards manually)
|
414
|
-
{'fieldName' => '
|
415
|
-
{'fieldName' => '
|
416
|
-
{'fieldName' => '
|
417
|
-
|
368
|
+
{'dependsOnCode' => 'optionTypeList.type:api', 'fieldName' => 'apiType', 'fieldLabel' => 'Option List', 'type' => 'select', 'optionSource' => 'apiOptionLists', 'required' => true, 'description' => 'The code of the api list to use, eg. clouds, servers, etc.', 'displayOrder' => 9},
|
369
|
+
{'dependsOnCode' => 'optionTypeList.type:ldap', 'fieldName' => 'sourceUsername', 'fieldLabel' => 'Source Username', 'type' => 'text', 'description' => "An LDAP Username for use when type is 'ldap'.", 'displayOrder' => 10},
|
370
|
+
{'dependsOnCode' => 'optionTypeList.type:ldap', 'fieldName' => 'sourcePassword', 'fieldLabel' => 'Source Username', 'type' => 'text', 'description' => "An LDAP Password for use when type is 'ldap'.", 'displayOrder' => 11},
|
371
|
+
{'dependsOnCode' => 'optionTypeList.type:ldap', 'fieldName' => 'ldapQuery', 'fieldLabel' => 'LDAP Query', 'type' => 'text', 'description' => "LDAP Queries are standard LDAP formatted queries where different objects can be searched. Dependent parameters can be loaded into the query using the <%=phrase%> syntax.", 'displayOrder' => 12},
|
372
|
+
{'dependsOnCode' => 'optionTypeList.type:rest|api|manual', 'fieldName' => 'initialDataset', 'fieldLabel' => 'Initial Dataset', 'type' => 'code-editor', 'description' => "Create an initial json dataset to be used as the collection for this option list. It should be a list containing objects with properties 'name', and 'value'. However, if there is a translation script, that will also be passed through.", 'displayOrder' => 13},
|
373
|
+
{'dependsOnCode' => 'optionTypeList.type:rest|api|ldap', 'fieldName' => 'translationScript', 'fieldLabel' => 'Translation Script', 'type' => 'code-editor', 'description' => "Create a js script to translate the result data object into an Array containing objects with properties name, and value. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 14},
|
374
|
+
{'dependsOnCode' => 'optionTypeList.type:rest|api', 'fieldName' => 'requestScript', 'fieldLabel' => 'Request Script', 'type' => 'code-editor', 'description' => "Create a js script to prepare the request. Return a data object as the body for a post, and return an array containing properties name and value for a get. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 15},
|
418
375
|
]
|
419
|
-
|
420
|
-
[
|
421
|
-
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
422
|
-
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
|
423
|
-
#{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Rest', 'value' => 'rest'}, {'name' => 'Manual', 'value' => 'manual'}], 'defaultValue' => 'rest', 'required' => true, 'displayOrder' => 3},
|
424
|
-
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 3},
|
425
|
-
{'fieldName' => 'apiType', 'fieldLabel' => 'Option List', 'type' => 'select', 'optionSource' => 'apiOptionLists', 'required' => true, 'description' => 'The code of the api list to use, eg. clouds, servers, etc.', 'displayOrder' => 6},
|
426
|
-
{'fieldName' => 'translationScript', 'fieldLabel' => 'Translation Script', 'type' => 'code-editor', 'description' => "Create a js script to translate the result data object into an Array containing objects with properties name, and value. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 9},
|
427
|
-
{'fieldName' => 'requestScript', 'fieldLabel' => 'Request Script', 'type' => 'code-editor', 'description' => "Create a js script to prepare the request. Return a data object as the body for a post, and return an array containing properties name and value for a get. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 10},
|
428
|
-
]
|
429
|
-
elsif list_type.to_s.downcase == 'manual'
|
430
|
-
[
|
431
|
-
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
432
|
-
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
|
433
|
-
#{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Rest', 'value' => 'rest'}, {'name' => 'Manual', 'value' => 'manual'}], 'defaultValue' => 'rest', 'required' => true, 'displayOrder' => 3},
|
434
|
-
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 3},
|
435
|
-
{'fieldName' => 'initialDataset', 'fieldLabel' => 'Dataset', 'type' => 'code-editor', 'required' => true, 'description' => "Create an initial JSON or CSV dataset to be used as the collection for this option list. It should be a list containing objects with properties 'name', and 'value'.", 'displayOrder' => 4},
|
436
|
-
]
|
437
|
-
else
|
438
|
-
print_red_alert "Unknown Option List type '#{list_type}'"
|
439
|
-
exit 1
|
440
|
-
end
|
376
|
+
|
441
377
|
end
|
442
378
|
|
443
|
-
def update_option_type_list_option_types(
|
444
|
-
list = new_option_type_list_option_types(
|
379
|
+
def update_option_type_list_option_types()
|
380
|
+
list = new_option_type_list_option_types()
|
445
381
|
list.each {|it|
|
446
382
|
it.delete('required')
|
447
383
|
it.delete('defaultValue')
|
@@ -65,7 +65,8 @@ class Morpheus::Cli::LibraryOptionTypesCommand
|
|
65
65
|
fieldLabel: option_type['fieldLabel'],
|
66
66
|
fieldName: option_type['fieldName'],
|
67
67
|
default: option_type['defaultValue'],
|
68
|
-
required: option_type['required'] ? '
|
68
|
+
required: (option_type['required'].nil? ? '' : format_boolean(option_type['required'])),
|
69
|
+
export: (option_type['exportMeta'].nil? ? '' : format_boolean(option_type['exportMeta']))
|
69
70
|
}
|
70
71
|
end
|
71
72
|
print cyan
|
@@ -76,7 +77,8 @@ class Morpheus::Cli::LibraryOptionTypesCommand
|
|
76
77
|
{:fieldLabel => {:display_name => "Field Label"} },
|
77
78
|
{:fieldName => {:display_name => "Field Name"} },
|
78
79
|
:default,
|
79
|
-
:required
|
80
|
+
:required,
|
81
|
+
:export,
|
80
82
|
], options)
|
81
83
|
print reset
|
82
84
|
print_results_pagination(json_response)
|
@@ -139,6 +141,7 @@ class Morpheus::Cli::LibraryOptionTypesCommand
|
|
139
141
|
"Placeholder" => 'placeHolder',
|
140
142
|
"Default Value" => 'defaultValue',
|
141
143
|
"Required" => lambda {|it| format_boolean(it['required']) },
|
144
|
+
"Export As Tag" => lambda {|it| it['exportMeta'].nil? ? '' : format_boolean(it['exportMeta']) },
|
142
145
|
}, option_type)
|
143
146
|
print reset,"\n"
|
144
147
|
return 0
|
@@ -162,18 +165,16 @@ class Morpheus::Cli::LibraryOptionTypesCommand
|
|
162
165
|
payload = nil
|
163
166
|
if options[:payload]
|
164
167
|
payload = options[:payload]
|
165
|
-
|
166
|
-
if options[:options]
|
167
|
-
payload['optionType'] ||= {}
|
168
|
-
payload['optionType'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
|
169
|
-
end
|
168
|
+
payload.deep_merge!({'optionType' => parse_passed_options(options)})
|
170
169
|
else
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
option_type_payload =
|
176
|
-
|
170
|
+
payload = {}
|
171
|
+
payload.deep_merge!({'optionType' => parse_passed_options(options)})
|
172
|
+
option_type_payload = Morpheus::Cli::OptionTypes.prompt(new_option_type_option_types, options[:options], @api_client)
|
173
|
+
# tweak payload for API
|
174
|
+
option_type_payload['optionList'] = {'id' => option_type_payload['optionList'].to_i} if option_type_payload['optionList'].is_a?(String) || option_type_payload['optionList'].is_a?(Numeric)
|
175
|
+
option_type_payload['required'] = ['on','true'].include?(option_type_payload['required'].to_s) if option_type_payload.key?('required')
|
176
|
+
option_type_payload['exportMeta'] = ['on','true'].include?(option_type_payload['exportMeta'].to_s) if option_type_payload.key?('exportMeta')
|
177
|
+
payload.deep_merge!({'optionType' => option_type_payload})
|
177
178
|
end
|
178
179
|
@option_types_interface.setopts(options)
|
179
180
|
if options[:dry_run]
|
@@ -207,27 +208,19 @@ class Morpheus::Cli::LibraryOptionTypesCommand
|
|
207
208
|
begin
|
208
209
|
option_type = find_option_type_by_name_or_id(args[0])
|
209
210
|
exit 1 if option_type.nil?
|
210
|
-
|
211
211
|
if options[:payload]
|
212
212
|
payload = options[:payload]
|
213
|
-
|
214
|
-
if options[:options]
|
215
|
-
payload['optionType'] ||= {}
|
216
|
-
payload['optionType'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
|
217
|
-
end
|
213
|
+
payload.deep_merge!({'optionType' => parse_passed_options(options)})
|
218
214
|
else
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
end
|
229
|
-
option_type_payload = params
|
230
|
-
payload = {optionType: option_type_payload}
|
215
|
+
payload = {}
|
216
|
+
payload.deep_merge!({'optionType' => parse_passed_options(options)})
|
217
|
+
option_type_payload = Morpheus::Cli::OptionTypes.no_prompt(update_option_type_option_types, options[:options], @api_client)
|
218
|
+
# tweak payload for API
|
219
|
+
option_type_payload['optionList'] = {'id' => option_type_payload['optionList'].to_i} if option_type_payload['optionList'].is_a?(String) || option_type_payload['optionList'].is_a?(Numeric)
|
220
|
+
option_type_payload['required'] = ['on','true'].include?(option_type_payload['required'].to_s) if option_type_payload.key?('required')
|
221
|
+
option_type_payload['exportMeta'] = ['on','true'].include?(option_type_payload['exportMeta'].to_s) if option_type_payload.key?('exportMeta')
|
222
|
+
payload.deep_merge!({'optionType' => option_type_payload})
|
223
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}" if payload['optionType'].empty?
|
231
224
|
end
|
232
225
|
@option_types_interface.setopts(options)
|
233
226
|
if options[:dry_run]
|
@@ -296,12 +289,14 @@ class Morpheus::Cli::LibraryOptionTypesCommand
|
|
296
289
|
[
|
297
290
|
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
298
291
|
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
|
299
|
-
{'fieldName' => 'fieldName', 'fieldLabel' => 'Field Name', 'type' => 'text', 'required' => true, 'description' => 'This is the input
|
300
|
-
{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Text', 'value' => 'text'}, {'name' => 'Password', 'value' => 'password'}, {'name' => 'Number', 'value' => 'number'}, {'name' => 'Checkbox', 'value' => 'checkbox'}, {'name' => 'Select', 'value' => 'select'}, {'name' => 'Hidden', 'value' => 'hidden'}], 'defaultValue' => 'text', 'required' => true, 'displayOrder' => 4},
|
301
|
-
{'fieldName' => '
|
302
|
-
{'fieldName' => '
|
303
|
-
{'fieldName' => '
|
304
|
-
{'fieldName' => '
|
292
|
+
{'fieldName' => 'fieldName', 'fieldLabel' => 'Field Name', 'type' => 'text', 'required' => true, 'description' => 'This is the input property that the value gets assigned to.', 'displayOrder' => 3},
|
293
|
+
{'code' => 'optionType.type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Text', 'value' => 'text'}, {'name' => 'Password', 'value' => 'password'}, {'name' => 'Number', 'value' => 'number'}, {'name' => 'Checkbox', 'value' => 'checkbox'}, {'name' => 'Select', 'value' => 'select'}, {'name' => 'Hidden', 'value' => 'hidden'}], 'defaultValue' => 'text', 'required' => true, 'displayOrder' => 4},
|
294
|
+
{'fieldName' => 'optionList', 'fieldLabel' => 'Option List', 'type' => 'select', 'optionSource' => 'optionTypeLists', 'required' => true, 'dependsOnCode' => 'optionType.type:select', 'description' => "The Option List to be the source of options when type is 'select'.", 'displayOrder' => 5},
|
295
|
+
{'fieldName' => 'fieldLabel', 'fieldLabel' => 'Field Label', 'type' => 'text', 'required' => true, 'description' => 'This is the input label that shows typically to the left of a custom option.', 'displayOrder' => 6},
|
296
|
+
{'fieldName' => 'placeHolder', 'fieldLabel' => 'Placeholder', 'type' => 'text', 'displayOrder' => 7},
|
297
|
+
{'fieldName' => 'defaultValue', 'fieldLabel' => 'Default Value', 'type' => 'text', 'displayOrder' => 8},
|
298
|
+
{'fieldName' => 'required', 'fieldLabel' => 'Required', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 9},
|
299
|
+
{'fieldName' => 'exportMeta', 'fieldLabel' => 'Export As Tag', 'type' => 'checkbox', 'defaultValue' => false, 'description' => 'Export as Tag.', 'displayOrder' => 10},
|
305
300
|
]
|
306
301
|
end
|
307
302
|
|
data/lib/morpheus/cli/login.rb
CHANGED
@@ -30,7 +30,7 @@ class Morpheus::Cli::Login
|
|
30
30
|
username, password = nil, nil
|
31
31
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
32
32
|
opts.banner = usage
|
33
|
-
opts.on( '-u', '--username USERNAME', "Username" ) do |val|
|
33
|
+
opts.on( '-u', '--username USERNAME', "Username. Sub-tenant users must format their username with a prefix like {subdomain}\\{username}" ) do |val|
|
34
34
|
username = val
|
35
35
|
end
|
36
36
|
opts.on( '-p', '--password PASSWORD', "Password" ) do |val|
|
@@ -50,11 +50,15 @@ class Morpheus::Cli::Login
|
|
50
50
|
opts.footer = <<-EOT
|
51
51
|
Login to a remote appliance with a username and password or using an access token.
|
52
52
|
Logging in with username and password will make an authentication api request to obtain an access token.
|
53
|
+
[username] is required, this is the username of the Morpheus User
|
54
|
+
[password] is required, this is the password of the Morpheus User
|
55
|
+
Sub-tenant users will need to pass their tenant subdomain prefix. ie. {subdomain}\\{username}
|
56
|
+
By default, the subdomain is the tenant account ID. Example: 2\\neo
|
53
57
|
The --token option can be used to login with a valid access token instead of username and password.
|
54
58
|
The specified token will be verified by making a whoami api request
|
55
59
|
If successful, the access token will be saved with the active session for the remote appliance.
|
56
|
-
This command will first logout any active session before attempting
|
57
|
-
The --test option
|
60
|
+
This command will first logout any active session before attempting authentication.
|
61
|
+
The --test option can be used to test credentials without updating the stored credentials for the appliance, neither logging you in or out.
|
58
62
|
EOT
|
59
63
|
|
60
64
|
end
|
@@ -106,6 +110,8 @@ EOT
|
|
106
110
|
if options[:test_only]
|
107
111
|
print green,"Success! Test Credentials verified for #{wallet['username']}", reset, "\n"
|
108
112
|
else
|
113
|
+
# clear whoami cache, it will be lazily load_saved_credentials
|
114
|
+
::Morpheus::Cli::Whoami.clear_whoami(@appliance_name, wallet['username'])
|
109
115
|
print green,"Success! Logged in as #{wallet['username']}", reset, "\n"
|
110
116
|
end
|
111
117
|
end
|
@@ -33,6 +33,43 @@ module Morpheus::Cli::AccountsHelper
|
|
33
33
|
@roles_interface
|
34
34
|
end
|
35
35
|
|
36
|
+
## Tenants (Accounts)
|
37
|
+
|
38
|
+
def account_column_definitions()
|
39
|
+
{
|
40
|
+
"ID" => 'id',
|
41
|
+
"Name" => 'name',
|
42
|
+
# "Name" => lambda {|it| it['name'].to_s + (it['master'] ? " (Master Tenant)" : '') },
|
43
|
+
"Description" => 'description',
|
44
|
+
"Subdomain" => 'subdomain',
|
45
|
+
"# Instances" => 'stats.instanceCount',
|
46
|
+
"# Users" => 'stats.userCount',
|
47
|
+
"Role" => lambda {|it| it['role']['authority'] rescue nil },
|
48
|
+
"Master" => lambda {|it| format_boolean(it['master']) },
|
49
|
+
"Currency" => 'currency',
|
50
|
+
"Status" => lambda {|it|
|
51
|
+
status_state = nil
|
52
|
+
if it['active']
|
53
|
+
status_state = "#{green}ACTIVE#{cyan}"
|
54
|
+
else
|
55
|
+
status_state = "#{red}INACTIVE#{cyan}"
|
56
|
+
end
|
57
|
+
status_state
|
58
|
+
},
|
59
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
60
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def list_account_column_definitions()
|
65
|
+
columns = account_column_definitions
|
66
|
+
columns.delete("Subdomain")
|
67
|
+
columns.delete("Master")
|
68
|
+
columns.delete("Currency")
|
69
|
+
return columns.upcase_keys!
|
70
|
+
end
|
71
|
+
|
72
|
+
|
36
73
|
def find_account_by_name_or_id(val)
|
37
74
|
if val.to_s =~ /\A\d{1,}\Z/
|
38
75
|
return find_account_by_id(val)
|
@@ -47,7 +84,7 @@ module Morpheus::Cli::AccountsHelper
|
|
47
84
|
return json_response['account']
|
48
85
|
rescue RestClient::Exception => e
|
49
86
|
if e.response && e.response.code == 404
|
50
|
-
print_red_alert "
|
87
|
+
print_red_alert "Tenant not found by id #{id}"
|
51
88
|
else
|
52
89
|
raise e
|
53
90
|
end
|
@@ -57,12 +94,12 @@ module Morpheus::Cli::AccountsHelper
|
|
57
94
|
def find_account_by_name(name)
|
58
95
|
accounts = accounts_interface.list({name: name.to_s})['accounts']
|
59
96
|
if accounts.empty?
|
60
|
-
print_red_alert "
|
97
|
+
print_red_alert "Tenant not found by name #{name}"
|
61
98
|
return nil
|
62
99
|
elsif accounts.size > 1
|
63
|
-
print_red_alert "#{accounts.size}
|
64
|
-
|
65
|
-
|
100
|
+
print_red_alert "Found #{accounts.size} tenants by name '#{name}'. Try using ID instead: #{format_list(accounts.collect {|it| it['id']}, 'or', 3)}"
|
101
|
+
print "\n"
|
102
|
+
print as_pretty_table(accounts, [:id, :name, :description], {color: red, thin: true})
|
66
103
|
print reset,"\n"
|
67
104
|
return nil
|
68
105
|
else
|
@@ -87,6 +124,35 @@ module Morpheus::Cli::AccountsHelper
|
|
87
124
|
return account
|
88
125
|
end
|
89
126
|
|
127
|
+
## Roles
|
128
|
+
|
129
|
+
def role_column_definitions(options={})
|
130
|
+
{
|
131
|
+
"ID" => 'id',
|
132
|
+
"Name" => 'authority',
|
133
|
+
"Description" => 'description',
|
134
|
+
#"Scope" => lambda {|it| it['scope'] },
|
135
|
+
"Type" => lambda {|it| format_role_type(it) },
|
136
|
+
"Multitenant" => lambda {|it|
|
137
|
+
format_boolean(it['multitenant']).to_s + (it['multitenantLocked'] ? " (LOCKED)" : "")
|
138
|
+
},
|
139
|
+
"Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
|
140
|
+
#"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
141
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
142
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
def subtenant_role_column_definitions(options={})
|
147
|
+
{
|
148
|
+
"ID" => 'id',
|
149
|
+
"Name" => 'authority',
|
150
|
+
"Description" => 'description',
|
151
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
152
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
90
156
|
def find_role_by_name_or_id(account_id, val)
|
91
157
|
if val.to_s =~ /\A\d{1,}\Z/
|
92
158
|
return find_role_by_id(account_id, val)
|
@@ -114,9 +180,11 @@ module Morpheus::Cli::AccountsHelper
|
|
114
180
|
print_red_alert "Role not found by name #{name}"
|
115
181
|
return nil
|
116
182
|
elsif roles.size > 1
|
117
|
-
print_red_alert "#{roles.size} roles by name #{name}"
|
118
|
-
|
119
|
-
print
|
183
|
+
print_red_alert "Found #{roles.size} roles by name '#{name}'. Try using ID instead: #{format_list(roles.collect {|it| it['id']}, 'or', 3)}"
|
184
|
+
print "\n"
|
185
|
+
# print as_pretty_table(accounts, [:id, :name, :description], {color: red, thin: true})
|
186
|
+
print as_pretty_table(roles, {"ID" => 'id', "Name" => 'authority',"Description" => 'description'}.upcase_keys!, {color: red, thin: true})
|
187
|
+
print reset,"\n"
|
120
188
|
return nil
|
121
189
|
else
|
122
190
|
return roles[0]
|
@@ -125,17 +193,57 @@ module Morpheus::Cli::AccountsHelper
|
|
125
193
|
|
126
194
|
alias_method :find_role_by_authority, :find_role_by_name
|
127
195
|
|
128
|
-
|
196
|
+
|
197
|
+
## Users
|
198
|
+
|
199
|
+
def user_column_definitions()
|
200
|
+
{
|
201
|
+
"ID" => 'id',
|
202
|
+
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
203
|
+
"First Name" => 'firstName',
|
204
|
+
"Last Name" => 'lastName',
|
205
|
+
"Username" => 'username',
|
206
|
+
"Email" => 'email',
|
207
|
+
"Role" => lambda {|it| format_user_role_names(it) },
|
208
|
+
"Notifications" => lambda {|it| it['receiveNotifications'].nil? ? '' : format_boolean(it['receiveNotifications']) },
|
209
|
+
"Status" => lambda {|it| format_user_status(it) },
|
210
|
+
"Last Login" => lambda {|it| format_duration_ago(it['lastLoginDate']) },
|
211
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
212
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
213
|
+
}
|
214
|
+
end
|
215
|
+
|
216
|
+
def list_user_column_definitions()
|
217
|
+
columns = user_column_definitions
|
218
|
+
columns.delete("Notifications")
|
219
|
+
return columns.upcase_keys!
|
220
|
+
end
|
221
|
+
|
222
|
+
def format_user_status(user, return_color=cyan)
|
223
|
+
if user["enabled"] != true
|
224
|
+
red + "DISABLED" + return_color
|
225
|
+
elsif user["accountLocked"]
|
226
|
+
red + "ACCOUNT LOCKED" + return_color
|
227
|
+
elsif user["accountExpired"]
|
228
|
+
yellow + "ACCOUNT EXPIRED" + return_color
|
229
|
+
elsif user["passwordExpired"]
|
230
|
+
yellow + "PASSWORD EXPIRED" + return_color
|
231
|
+
else
|
232
|
+
green + "ACTIVE" + return_color
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def find_user_by_username_or_id(account_id, val, params={})
|
129
237
|
if val.to_s =~ /\A\d{1,}\Z/
|
130
|
-
return find_user_by_id(account_id, val)
|
238
|
+
return find_user_by_id(account_id, val, params)
|
131
239
|
else
|
132
|
-
return find_user_by_username(account_id, val)
|
240
|
+
return find_user_by_username(account_id, val, params)
|
133
241
|
end
|
134
242
|
end
|
135
243
|
|
136
|
-
def find_user_by_id(account_id, id)
|
244
|
+
def find_user_by_id(account_id, id, params={})
|
137
245
|
begin
|
138
|
-
json_response = users_interface.get(account_id, id.to_i,
|
246
|
+
json_response = users_interface.get(account_id, id.to_i, params)
|
139
247
|
return json_response['user']
|
140
248
|
rescue RestClient::Exception => e
|
141
249
|
if e.response && e.response.code == 404
|
@@ -146,22 +254,23 @@ module Morpheus::Cli::AccountsHelper
|
|
146
254
|
end
|
147
255
|
end
|
148
256
|
|
149
|
-
def find_user_by_username(account_id, username)
|
150
|
-
users = users_interface.list(account_id, {username: username.to_s})['users']
|
257
|
+
def find_user_by_username(account_id, username, params={})
|
258
|
+
users = users_interface.list(account_id, params.merge({username: username.to_s}))['users']
|
151
259
|
if users.empty?
|
152
260
|
print_red_alert "User not found by username #{username}"
|
153
261
|
return nil
|
154
262
|
elsif users.size > 1
|
155
|
-
print_red_alert "#{users.size} users by username #{username}"
|
156
|
-
|
157
|
-
print
|
263
|
+
print_red_alert "Found #{users.size} users by username '#{username}'. Try using ID instead: #{format_list(users.collect {|it| it['id']}, 'or', 3)}"
|
264
|
+
print "\n"
|
265
|
+
print as_pretty_table(users, list_user_column_definitions, {color: red, thin: true})
|
266
|
+
print reset,"\n"
|
158
267
|
return nil
|
159
268
|
else
|
160
269
|
return users[0]
|
161
270
|
end
|
162
271
|
end
|
163
272
|
|
164
|
-
def find_all_user_ids(account_id, usernames)
|
273
|
+
def find_all_user_ids(account_id, usernames, params={})
|
165
274
|
user_ids = []
|
166
275
|
if usernames.is_a?(String)
|
167
276
|
usernames = usernames.split(",").collect {|it| it.to_s.strip }.select {|it| it }.uniq
|
@@ -170,11 +279,11 @@ module Morpheus::Cli::AccountsHelper
|
|
170
279
|
end
|
171
280
|
usernames.each do |username|
|
172
281
|
# save a query
|
173
|
-
#user = find_user_by_username_or_id(nil, username)
|
282
|
+
#user = find_user_by_username_or_id(nil, username, params)
|
174
283
|
if username.to_s =~ /\A\d{1,}\Z/
|
175
284
|
user_ids << username.to_i
|
176
285
|
else
|
177
|
-
user = find_user_by_username(account_id, username)
|
286
|
+
user = find_user_by_username(account_id, username, params)
|
178
287
|
if user.nil?
|
179
288
|
return nil
|
180
289
|
else
|
@@ -185,6 +294,32 @@ module Morpheus::Cli::AccountsHelper
|
|
185
294
|
user_ids
|
186
295
|
end
|
187
296
|
|
297
|
+
|
298
|
+
## User Groups
|
299
|
+
|
300
|
+
def user_group_column_definitions()
|
301
|
+
{
|
302
|
+
"ID" => lambda {|it| it['id'] },
|
303
|
+
#"Account" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
304
|
+
"Name" => lambda {|it| it['name'] },
|
305
|
+
"Description" => lambda {|it| it['description'] },
|
306
|
+
"Server Group" => lambda {|it| it['serverGroup'] },
|
307
|
+
"Sudo Access" => lambda {|it| format_boolean it['sudoAccess'] },
|
308
|
+
# "Shared User" => lambda {|it| format_boolean it['sharedUser'] },
|
309
|
+
"# Users" => lambda {|it| it['users'].size rescue nil },
|
310
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
311
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
312
|
+
}
|
313
|
+
end
|
314
|
+
|
315
|
+
def list_user_group_column_definitions()
|
316
|
+
columns = user_group_column_definitions
|
317
|
+
columns.delete("Sudo Access")
|
318
|
+
columns.delete("Server Group")
|
319
|
+
columns.delete("Updated")
|
320
|
+
return columns.upcase_keys!
|
321
|
+
end
|
322
|
+
|
188
323
|
def find_user_group_by_name_or_id(account_id, val)
|
189
324
|
if val.to_s =~ /\A\d{1,}\Z/
|
190
325
|
return find_user_group_by_id(account_id, val)
|
@@ -212,9 +347,8 @@ module Morpheus::Cli::AccountsHelper
|
|
212
347
|
print_red_alert "User Group not found by name #{name}"
|
213
348
|
return nil
|
214
349
|
elsif user_groups.size > 1
|
215
|
-
print_red_alert "#{user_groups.size} user groups
|
216
|
-
|
217
|
-
print_red_alert "Try using ID instead"
|
350
|
+
print_red_alert "Found #{user_groups.size} user groups by name '#{name}'. Try using ID instead: #{format_list(user_groups.collect {|it| it['id']}, 'or', 3)}"
|
351
|
+
print as_pretty_table(user_groups, [:id, :name, :description], {color: red, thin: true})
|
218
352
|
print reset,"\n"
|
219
353
|
return nil
|
220
354
|
else
|
@@ -222,36 +356,6 @@ module Morpheus::Cli::AccountsHelper
|
|
222
356
|
end
|
223
357
|
end
|
224
358
|
|
225
|
-
def print_accounts_table(accounts, options={})
|
226
|
-
table_color = options.key?(:color) ? options[:color] : cyan
|
227
|
-
rows = accounts.collect do |account|
|
228
|
-
status_state = nil
|
229
|
-
if account['active']
|
230
|
-
status_state = "#{green}ACTIVE#{table_color}"
|
231
|
-
else
|
232
|
-
status_state = "#{red}INACTIVE#{table_color}"
|
233
|
-
end
|
234
|
-
{
|
235
|
-
id: account['id'],
|
236
|
-
name: account['name'],
|
237
|
-
description: account['description'],
|
238
|
-
role: account['role'] ? account['role']['authority'] : nil,
|
239
|
-
status: status_state,
|
240
|
-
dateCreated: format_local_dt(account['dateCreated'])
|
241
|
-
}
|
242
|
-
end
|
243
|
-
print table_color if table_color
|
244
|
-
print as_pretty_table(rows, [
|
245
|
-
:id,
|
246
|
-
:name,
|
247
|
-
:description,
|
248
|
-
:role,
|
249
|
-
{:dateCreated => {:display_name => "Date Created"} },
|
250
|
-
:status
|
251
|
-
], options.merge({color:table_color}))
|
252
|
-
print reset if table_color
|
253
|
-
end
|
254
|
-
|
255
359
|
def format_role_type(role)
|
256
360
|
str = ""
|
257
361
|
if role['roleType'] == "account"
|
@@ -271,52 +375,6 @@ module Morpheus::Cli::AccountsHelper
|
|
271
375
|
return str
|
272
376
|
end
|
273
377
|
|
274
|
-
def print_roles_table(roles, options={})
|
275
|
-
table_color = options.key?(:color) ? options[:color] : cyan
|
276
|
-
rows = roles.collect do |role|
|
277
|
-
{
|
278
|
-
id: role['id'],
|
279
|
-
name: role['authority'],
|
280
|
-
description: role['description'],
|
281
|
-
scope: role['scope'],
|
282
|
-
multitenant: role['multitenant'] ? 'Yes' : 'No',
|
283
|
-
type: format_role_type(role),
|
284
|
-
owner: role['owner'] ? role['owner']['name'] : "System",
|
285
|
-
dateCreated: format_local_dt(role['dateCreated'])
|
286
|
-
}
|
287
|
-
end
|
288
|
-
columns = [
|
289
|
-
:id,
|
290
|
-
:name,
|
291
|
-
:description,
|
292
|
-
# options[:is_master_account] ? :scope : nil,
|
293
|
-
options[:is_master_account] ? :type : nil,
|
294
|
-
options[:is_master_account] ? :multitenant : nil,
|
295
|
-
options[:is_master_account] ? :owner : nil,
|
296
|
-
{:dateCreated => {:display_name => "Date Created"} }
|
297
|
-
].compact
|
298
|
-
if options[:include_fields]
|
299
|
-
columns = options[:include_fields]
|
300
|
-
end
|
301
|
-
# print table_color if table_color
|
302
|
-
print as_pretty_table(rows, columns, options)
|
303
|
-
# print reset if table_color
|
304
|
-
end
|
305
|
-
|
306
|
-
def print_users_table(users, options={})
|
307
|
-
table_color = options[:color] || cyan
|
308
|
-
rows = users.collect do |user|
|
309
|
-
{id: user['id'], username: user['username'], name: user['displayName'], first: user['firstName'], last: user['lastName'], email: user['email'], role: format_user_role_names(user), account: user['account'] ? user['account']['name'] : nil}
|
310
|
-
end
|
311
|
-
columns = [:id, :account, :first, :last, :username, :email, :role]
|
312
|
-
if options[:include_fields]
|
313
|
-
columns = options[:include_fields]
|
314
|
-
end
|
315
|
-
#print table_color if table_color
|
316
|
-
print as_pretty_table(rows, columns, options)
|
317
|
-
#print reset if table_color
|
318
|
-
end
|
319
|
-
|
320
378
|
## These user access formatted methods should probably move up to PrintHelper to be more ubiquitous.
|
321
379
|
|
322
380
|
def format_user_role_names(user)
|