morpheus-cli 5.5.1.5 → 5.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +25 -0
  4. data/lib/morpheus/api/archive_buckets_interface.rb +1 -1
  5. data/lib/morpheus/api/body_io.rb +22 -0
  6. data/lib/morpheus/api/catalog_item_types_interface.rb +5 -1
  7. data/lib/morpheus/api/clients_interface.rb +41 -0
  8. data/lib/morpheus/api/clouds_interface.rb +21 -0
  9. data/lib/morpheus/api/instances_interface.rb +8 -1
  10. data/lib/morpheus/api/integrations_interface.rb +30 -0
  11. data/lib/morpheus/api/library_instance_types_interface.rb +15 -3
  12. data/lib/morpheus/api/network_pool_server_types_interface.rb +9 -0
  13. data/lib/morpheus/api/plugins_interface.rb +22 -0
  14. data/lib/morpheus/api/roles_interface.rb +20 -1
  15. data/lib/morpheus/api/security_package_types_interface.rb +9 -0
  16. data/lib/morpheus/api/security_packages_interface.rb +9 -0
  17. data/lib/morpheus/api/security_scans_interface.rb +9 -0
  18. data/lib/morpheus/api/servers_interface.rb +17 -17
  19. data/lib/morpheus/api/storage_providers_interface.rb +1 -1
  20. data/lib/morpheus/api/virtual_images_interface.rb +1 -23
  21. data/lib/morpheus/cli/cli_command.rb +81 -7
  22. data/lib/morpheus/cli/commands/apps.rb +28 -2
  23. data/lib/morpheus/cli/commands/archives_command.rb +2 -2
  24. data/lib/morpheus/cli/commands/blueprints_command.rb +16 -0
  25. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +34 -2
  26. data/lib/morpheus/cli/commands/clients_command.rb +338 -0
  27. data/lib/morpheus/cli/commands/clouds.rb +127 -1
  28. data/lib/morpheus/cli/commands/clusters.rb +42 -12
  29. data/lib/morpheus/cli/commands/curl_command.rb +114 -135
  30. data/lib/morpheus/cli/commands/hosts.rb +108 -11
  31. data/lib/morpheus/cli/commands/instances.rb +115 -14
  32. data/lib/morpheus/cli/commands/integrations_command.rb +215 -4
  33. data/lib/morpheus/cli/commands/invoices_command.rb +20 -11
  34. data/lib/morpheus/cli/commands/jobs_command.rb +299 -190
  35. data/lib/morpheus/cli/commands/library_cluster_layouts_command.rb +16 -2
  36. data/lib/morpheus/cli/commands/library_container_scripts_command.rb +14 -0
  37. data/lib/morpheus/cli/commands/library_container_templates_command.rb +131 -48
  38. data/lib/morpheus/cli/commands/library_container_types_command.rb +17 -4
  39. data/lib/morpheus/cli/commands/library_instance_types_command.rb +85 -7
  40. data/lib/morpheus/cli/commands/library_layouts_command.rb +32 -1
  41. data/lib/morpheus/cli/commands/library_option_lists_command.rb +30 -18
  42. data/lib/morpheus/cli/commands/library_option_types_command.rb +31 -14
  43. data/lib/morpheus/cli/commands/library_spec_templates_command.rb +14 -0
  44. data/lib/morpheus/cli/commands/library_upgrades_command.rb +2 -2
  45. data/lib/morpheus/cli/commands/network_pool_server_types.rb +20 -0
  46. data/lib/morpheus/cli/commands/network_pool_servers_command.rb +55 -158
  47. data/lib/morpheus/cli/commands/network_pools_command.rb +49 -23
  48. data/lib/morpheus/cli/commands/networks_command.rb +262 -45
  49. data/lib/morpheus/cli/commands/plugins.rb +213 -0
  50. data/lib/morpheus/cli/commands/price_sets_command.rb +27 -8
  51. data/lib/morpheus/cli/commands/prices_command.rb +17 -5
  52. data/lib/morpheus/cli/commands/processes_command.rb +2 -1
  53. data/lib/morpheus/cli/commands/remote.rb +7 -10
  54. data/lib/morpheus/cli/commands/roles.rb +924 -335
  55. data/lib/morpheus/cli/commands/search_command.rb +2 -0
  56. data/lib/morpheus/cli/commands/security_groups.rb +72 -84
  57. data/lib/morpheus/cli/commands/security_package_types.rb +32 -0
  58. data/lib/morpheus/cli/commands/security_packages.rb +84 -0
  59. data/lib/morpheus/cli/commands/security_scans.rb +107 -0
  60. data/lib/morpheus/cli/commands/service_plans_command.rb +16 -14
  61. data/lib/morpheus/cli/commands/subnets_command.rb +15 -1
  62. data/lib/morpheus/cli/commands/tasks.rb +34 -1
  63. data/lib/morpheus/cli/commands/tenants_command.rb +1 -1
  64. data/lib/morpheus/cli/commands/user_settings_command.rb +11 -2
  65. data/lib/morpheus/cli/commands/users.rb +50 -9
  66. data/lib/morpheus/cli/commands/virtual_images.rb +14 -0
  67. data/lib/morpheus/cli/commands/workflows.rb +14 -0
  68. data/lib/morpheus/cli/mixins/accounts_helper.rb +6 -5
  69. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +79 -0
  70. data/lib/morpheus/cli/mixins/jobs_helper.rb +4 -5
  71. data/lib/morpheus/cli/mixins/library_helper.rb +2 -0
  72. data/lib/morpheus/cli/mixins/logs_helper.rb +3 -0
  73. data/lib/morpheus/cli/mixins/monitoring_helper.rb +1 -1
  74. data/lib/morpheus/cli/mixins/print_helper.rb +29 -4
  75. data/lib/morpheus/cli/mixins/provisioning_helper.rb +38 -9
  76. data/lib/morpheus/cli/mixins/rest_command.rb +106 -8
  77. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +6 -2
  78. data/lib/morpheus/cli/option_types.rb +94 -25
  79. data/lib/morpheus/cli/version.rb +1 -1
  80. data/lib/morpheus/formatters.rb +10 -1
  81. metadata +15 -2
@@ -28,6 +28,14 @@ class Morpheus::Cli::Tasks
28
28
  opts.on('-t', '--type x,y,z', Array, "Filter by task type code(s)") do |val|
29
29
  params['taskTypeCodes'] = val
30
30
  end
31
+
32
+ opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
33
+ add_query_parameter(params, 'labels', parse_labels(val))
34
+ end
35
+ opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
36
+ add_query_parameter(params, 'allLabels', parse_labels(val))
37
+ end
38
+
31
39
  build_standard_list_options(opts, options)
32
40
  opts.footer = "List tasks."
33
41
  end
@@ -125,6 +133,8 @@ class Morpheus::Cli::Tasks
125
133
  "Name" => 'name',
126
134
  "Code" => 'code',
127
135
  "Type" => lambda {|it| it['taskType']['name'] },
136
+ "Labels" => lambda {|it| format_list(it['labels'], '', 3) rescue '' },
137
+ "Visibility" => 'visibility',
128
138
  "Execute Target" => lambda {|it|
129
139
  if it['executeTarget'] == 'local'
130
140
  git_info = []
@@ -252,6 +262,7 @@ class Morpheus::Cli::Tasks
252
262
  task_name = nil
253
263
  task_code = nil
254
264
  task_type_name = nil
265
+ task_visibility = nil
255
266
  optparse = Morpheus::Cli::OptionParser.new do |opts|
256
267
  opts.banner = subcommand_usage("[name] -t TASK_TYPE")
257
268
  opts.on( '-t', '--type TASK_TYPE', "Task Type" ) do |val|
@@ -259,6 +270,12 @@ class Morpheus::Cli::Tasks
259
270
  end
260
271
  opts.on('--name NAME', String, "Task Name" ) do |val|
261
272
  task_name = val
273
+ end
274
+ opts.on('--visibility VISIBILITY', String, "Task Visibility" ) do |val|
275
+ task_visibility = val
276
+ end
277
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
278
+ options[:options]['labels'] = parse_labels(val)
262
279
  end
263
280
  opts.on('--code CODE', String, "Task Code" ) do |val|
264
281
  task_code = val
@@ -412,6 +429,13 @@ class Morpheus::Cli::Tasks
412
429
  return 1
413
430
  end
414
431
 
432
+ # Visibility
433
+ if task_visibility != nil
434
+ payload['task']['visibility'] = task_visibility
435
+ else
436
+ payload['task']['visibility'] = 'private'
437
+ end
438
+
415
439
  payload['task']['taskType'] = {"id" => task_type['id'], "code" => task_type['code']}
416
440
 
417
441
 
@@ -630,6 +654,12 @@ class Morpheus::Cli::Tasks
630
654
  opts.on('--name NAME', String, "Task Name" ) do |val|
631
655
  options[:options]['name'] = val
632
656
  end
657
+ opts.on('--visibility VISIBILITY', String, "Task Visibility" ) do |val|
658
+ options[:options]['visibility'] = val
659
+ end
660
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
661
+ options[:options]['labels'] = parse_labels(val)
662
+ end
633
663
  opts.on('--code CODE', String, "Task Code" ) do |val|
634
664
  options[:options]['code'] = val
635
665
  end
@@ -1175,7 +1205,10 @@ class Morpheus::Cli::Tasks
1175
1205
  {"ID" => lambda {|it| it['id'] } },
1176
1206
  {"NAME" => lambda {|it| it['name'] } },
1177
1207
  {"TYPE" => lambda {|it| it['taskType']['name'] ? it['taskType']['name'] : it['type'] } },
1178
- {"CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } },
1208
+ {"LABELS" => lambda {|it| format_list(it['labels'], '', 3) rescue '' }},
1209
+ {"VISIBILITY" => lambda {|it| it['visibility'] } },
1210
+ {"CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } }
1211
+
1179
1212
  # {"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } },
1180
1213
  ]
1181
1214
  if opts[:include_fields]
@@ -245,7 +245,7 @@ EOT
245
245
  options = {}
246
246
  optparse = Morpheus::Cli::OptionParser.new do |opts|
247
247
  opts.banner = subcommand_usage("[tenant]")
248
- opts.on('--remove-resources [on|off]', ['on','off'], "Remove Infrastructure. Default is off.") do |val|
248
+ opts.on('--remove-resources [on|off]', ['on','off'], "Remove Associated Instances. Default is off.") do |val|
249
249
  params[:removeResources] = val.nil? ? 'on' : val
250
250
  end
251
251
  build_standard_remove_options(opts, options)
@@ -79,6 +79,7 @@ EOT
79
79
  "First Name" => lambda {|it| it['firstName'] },
80
80
  "Last Name" => lambda {|it| it['lastName'] },
81
81
  "Email" => lambda {|it| it['email'] },
82
+ "Theme" => lambda {|it| it['activeTheme'] ? it['activeTheme'] : '' },
82
83
  "Avatar" => lambda {|it| it['avatar'] ? it['avatar'].split('/').last : '' },
83
84
  "Notifications" => lambda {|it| format_boolean(it['receiveNotifications']) },
84
85
  "Linux Username" => lambda {|it| it['linuxUsername'] },
@@ -102,8 +103,8 @@ EOT
102
103
  "USERNAME" => lambda {|it| it['username'] },
103
104
  "ACCESS TOKEN" => lambda {|it| it['maskedAccessToken'] },
104
105
  "REFRESH TOKEN" => lambda {|it| it['maskedRefreshToken'] },
105
- "EXPIRATION" => lambda {|it| format_local_dt(it['expiration']) },
106
- "TTL" => lambda {|it| it['expiration'] ? (format_duration(it['expiration']) rescue '') : '' }
106
+ "ACCESS EXPIRATION" => lambda {|it| format_local_dt(it['expiration']) },
107
+ "ACCESS TTL" => lambda {|it| it['expiration'] ? (format_duration(it['expiration']) rescue '') : '' }
107
108
  }
108
109
  print cyan
109
110
  puts as_pretty_table(access_tokens, cols)
@@ -807,6 +808,14 @@ EOT
807
808
  {'switch' => 'change-password', 'fieldName' => 'password', 'fieldLabel' => 'Password', 'type' => 'password', 'description' => 'Change user credentials to use a new password'},
808
809
  {'fieldName' => 'avatar', 'fieldLabel' => 'Avatar', 'type' => 'file', 'description' => 'Local filepath of image file to upload as user avatar'},
809
810
  {'fieldName' => 'desktopBackground', 'fieldLabel' => 'Desktop Background', 'type' => 'file', 'description' => 'Local filepath of image file to upload as user desktop background'},
811
+ {'switch' => 'theme', 'fieldName' => 'activeTheme', 'fieldLabel' => 'Theme', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
812
+ begin
813
+ api_client.options_for_source("themes", api_params)['data']
814
+ rescue => ex
815
+ Morpheus::Logging::DarkPrinter.puts "Failed to load options for themes. Exception: (#{ex.class}) '#{ex.message}'" if Morpheus::Logging.debug?
816
+ [{"name" => "Default", "value" => "default"}, {"name" => "Dark Mode", "value" => "darkMode"}]
817
+ end
818
+ }, 'description' => 'Active Theme to use for the UI, default or darkMode.'},
810
819
  # api cannot yet modify isUsing2fa
811
820
  # {'switch' => '2fa', 'fieldName' => 'isUsing2fa', 'fieldLabel' => '2FA Enabled', 'type' => 'checkbox', 'description' => 'Enable or Disable 2FA for your user.'}
812
821
  ]
@@ -129,15 +129,15 @@ class Morpheus::Cli::Users
129
129
  opts.on('-g','--global', "Global (All Tenants). Find users across all tenants. Default is your own tenant only.") do
130
130
  options[:global] = true
131
131
  end
132
- opts.on('-p','--permissions', "Display Permissions") do |val|
132
+ opts.on('-p','--permissions', "Display Permissions [deprecated]") do |val|
133
133
  options[:include_features_access] = true
134
134
  params['includeAccess'] = true
135
135
  end
136
- opts.on(nil,'--feature-access', "Display Permissions") do |val|
136
+ opts.add_hidden_option('-p,')
137
+ opts.on(nil,'--feature-access', "Display Feature Access") do |val|
137
138
  options[:include_features_access] = true
138
139
  params['includeAccess'] = true
139
140
  end
140
- opts.add_hidden_option('--feature-access')
141
141
  opts.on(nil,'--group-access', "Display Group Access") do
142
142
  options[:include_sites_access] = true
143
143
  params['includeAccess'] = true
@@ -162,6 +162,22 @@ class Morpheus::Cli::Users
162
162
  options[:include_personas_access] = true
163
163
  params['includeAccess'] = true
164
164
  end
165
+ opts.on(nil,'--vdi-pool-access', "Display VDI Pool Access") do
166
+ options[:include_vdi_pools_access] = true
167
+ params['includeAccess'] = true
168
+ end
169
+ opts.on(nil,'--report-type-access', "Display Report Type Access") do
170
+ options[:include_report_types_access] = true
171
+ params['includeAccess'] = true
172
+ end
173
+ opts.on(nil,'--workflow-access', "Display Workflow Access") do
174
+ options[:include_task_sets_access] = true
175
+ params['includeAccess'] = true
176
+ end
177
+ opts.on(nil,'--task-access', "Display Task Access") do
178
+ options[:include_tasks_access] = true
179
+ params['includeAccess'] = true
180
+ end
165
181
  opts.on(nil,'--all', "Display All Access Lists") do
166
182
  options[:include_features_access] = true
167
183
  options[:include_sites_access] = true
@@ -170,6 +186,10 @@ class Morpheus::Cli::Users
170
186
  options[:include_app_templates_access] = true
171
187
  options[:include_catalog_item_types_access] = true
172
188
  options[:include_personas_access] = true
189
+ options[:include_vdi_pools_access] = true
190
+ options[:include_report_types_access] = true
191
+ options[:include_task_sets_access] = true
192
+ options[:include_tasks_access] = true
173
193
  params['includeAccess'] = true
174
194
  end
175
195
  opts.on(nil, '--hide-none-access', "Hide records with 'none' access") do
@@ -185,6 +205,7 @@ EOT
185
205
  verify_args!(args:args, optparse:optparse, min:1)
186
206
  connect(options)
187
207
  id_list = parse_id_list(args)
208
+ params.merge!(parse_query_options(options))
188
209
  return run_command_for_each_arg(id_list) do |arg|
189
210
  _get(arg, params, options)
190
211
  end
@@ -244,15 +265,24 @@ EOT
244
265
  puts yellow,"No permissions found.",reset
245
266
  end
246
267
  else
247
- available_field_options = {'features' => 'Feature', 'sites' => 'Group', 'zones' => 'Cloud', 'instance_types' => 'Instance Type',
248
- 'app_templates' => 'Blueprint', 'catalog_item_types' => 'Catalog Item Type', 'personas' => 'Persona', 'vdi_pools' => 'VDI Pool', 'report_types' => 'Report Type'}
268
+ available_field_options = {
269
+ 'features' => 'Feature', 'sites' => 'Group', 'zones' => 'Cloud', 'instance_types' => 'Instance Type',
270
+ 'app_templates' => 'Blueprint', 'report_types' => 'Report Type', 'personas' => 'Persona',
271
+ 'catalog_item_types' => 'Catalog Item Type', 'vdi_pools' => 'VDI Pool', 'task_sets' => 'Workflow', 'tasks' => 'Task'
272
+ }
273
+
274
+ if is_tenant_account
275
+ available_field_options.delete("sites")
276
+ else
277
+ available_field_options.delete("zones")
278
+ end
279
+
249
280
  available_field_options.each do |field, label|
250
- if !(field == 'sites' && is_tenant_account) && options["include_#{field}_access".to_sym]
251
- access = user['access'][field.split('_').enum_for(:each_with_index).collect {|word, idx| idx == 0 ? word : word.capitalize}.join]
281
+ if options["include_#{field}_access".to_sym]
282
+ access = user['access'][field.to_s.camelcase] || []
252
283
  access = access.reject {|it| it['access'] == 'none'} if options[:hide_none_access]
253
284
 
254
285
  if field == "features"
255
- # print_h2 "Permissions", options
256
286
  print_h2 "#{label} Access", options
257
287
  else
258
288
  print_h2 "#{label} Access", options
@@ -366,7 +396,18 @@ EOT
366
396
 
367
397
  print_h1 "User Permissions: #{user['username']}", options
368
398
 
369
- available_field_options = {'features' => 'Feature', 'sites' => 'Group', 'zones' => 'Cloud', 'instance_types' => 'Instance Type', 'app_templates' => 'Blueprint', 'catalog_item_types' => 'Catalog Item Type', 'vdi_pools' => 'VDI Pool', 'report_types' => 'Report Type','personas' => 'Persona'}
399
+ available_field_options = {
400
+ 'features' => 'Feature', 'sites' => 'Group', 'zones' => 'Cloud', 'instance_types' => 'Instance Type',
401
+ 'app_templates' => 'Blueprint', 'report_types' => 'Report Type', 'personas' => 'Persona',
402
+ 'catalog_item_types' => 'Catalog Item Type', 'vdi_pools' => 'VDI Pool', 'task_sets' => 'Workflow', 'tasks' => 'Task'
403
+ }
404
+
405
+ if is_tenant_account
406
+ available_field_options.reject! {|k| k == 'sites'}
407
+ else
408
+ available_field_options.reject! {|k| k == 'zones'}
409
+ end
410
+
370
411
  available_field_options.each do |field, label|
371
412
  if !(field == 'sites' && is_tenant_account)
372
413
  access = json_response['access'][field.split('_').enum_for(:each_with_index).collect {|word, idx| idx == 0 ? word : word.capitalize}.join]
@@ -42,6 +42,12 @@ class Morpheus::Cli::VirtualImages
42
42
  opts.on('--synced', "Synced Images" ) do
43
43
  options[:filterType] = 'Synced'
44
44
  end
45
+ opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
46
+ add_query_parameter(params, 'labels', parse_labels(val))
47
+ end
48
+ opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
49
+ add_query_parameter(params, 'allLabels', parse_labels(val))
50
+ end
45
51
  opts.on('--tags Name=Value',String, "Filter by tags (metadata name value pairs).") do |val|
46
52
  val.split(",").each do |value_pair|
47
53
  k,v = value_pair.strip.split("=")
@@ -101,6 +107,7 @@ class Morpheus::Cli::VirtualImages
101
107
  virtual_image_column_definitions = {
102
108
  "ID" => 'id',
103
109
  "Name" => 'name',
110
+ "Labels" => lambda {|it| format_list(it['labels'], '', 3) rescue '' },
104
111
  "Type" => lambda {|it|
105
112
  # yick, api should return the type with every virtualImage
106
113
  image_type = virtual_image_type_for_name_or_code(it['imageType'])
@@ -197,6 +204,7 @@ EOT
197
204
  description_cols = {
198
205
  "ID" => 'id',
199
206
  "Name" => 'name',
207
+ "Labels" => lambda {|it| format_list(it['labels']) },
200
208
  "Type" => lambda {|it| image_type_display },
201
209
  "Operating System" => lambda {|it| it['osType'] ? it['osType']['name'] : "" },
202
210
  "Storage" => lambda {|it| !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default' },
@@ -302,6 +310,9 @@ EOT
302
310
  tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
303
311
  end
304
312
  end
313
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
314
+ options[:options]['labels'] = parse_labels(val)
315
+ end
305
316
  opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
306
317
  options[:tags] = val
307
318
  end
@@ -440,6 +451,9 @@ EOT
440
451
  tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
441
452
  end
442
453
  end
454
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
455
+ options[:options]['labels'] = parse_labels(val)
456
+ end
443
457
  opts.on('--tags LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
444
458
  options[:tags] = val
445
459
  end
@@ -40,6 +40,12 @@ class Morpheus::Cli::Workflows
40
40
  end
41
41
  params['type'] = workflow_type
42
42
  end
43
+ opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
44
+ add_query_parameter(params, 'labels', parse_labels(val))
45
+ end
46
+ opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
47
+ add_query_parameter(params, 'allLabels', parse_labels(val))
48
+ end
43
49
  build_standard_list_options(opts, options)
44
50
  opts.footer = "List workflows."
45
51
  end
@@ -93,6 +99,9 @@ class Morpheus::Cli::Workflows
93
99
  opts.on("--name NAME", String, "Name for workflow") do |val|
94
100
  params['name'] = val
95
101
  end
102
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
103
+ options[:options]['labels'] = parse_labels(val)
104
+ end
96
105
  opts.on("--description DESCRIPTION", String, "Description of workflow") do |val|
97
106
  params['description'] = val
98
107
  end
@@ -341,6 +350,7 @@ class Morpheus::Cli::Workflows
341
350
  description_cols = {
342
351
  "ID" => 'id',
343
352
  "Name" => 'name',
353
+ "Labels" => lambda {|it| format_list(it['labels'], '', 3) rescue '' },
344
354
  "Description" => 'description',
345
355
  "Type" => lambda {|workflow| format_workflow_type(workflow) },
346
356
  "Platform" => lambda {|it| format_platform(it['platform']) },
@@ -407,6 +417,9 @@ class Morpheus::Cli::Workflows
407
417
  opts.on("--name NAME", String, "New name for workflow") do |val|
408
418
  params['name'] = val
409
419
  end
420
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
421
+ options[:options]['labels'] = parse_labels(val)
422
+ end
410
423
  opts.on("--description DESCRIPTION", String, "Description of workflow") do |val|
411
424
  params['description'] = val
412
425
  end
@@ -762,6 +775,7 @@ class Morpheus::Cli::Workflows
762
775
  columns = [
763
776
  {"ID" => lambda {|workflow| workflow['id'] } },
764
777
  {"NAME" => lambda {|workflow| workflow['name'] } },
778
+ {"LABELS" => lambda {|it| format_list(it['labels'], '', 3) rescue '' }},
765
779
  {"DESCRIPTION" => lambda {|workflow| workflow['description'] } },
766
780
  {"TYPE" => lambda {|workflow| format_workflow_type(workflow) } },
767
781
  {"TASKS" => lambda {|workflow|
@@ -389,18 +389,19 @@ module Morpheus::Cli::AccountsHelper
389
389
  end
390
390
 
391
391
  def get_access_color(access)
392
- access ||= 'none'
392
+ access ||= 'default'
393
393
  if access == 'none'
394
394
  # maybe reset instead of white?
395
395
  white
396
- elsif access == 'read'
397
- cyan
398
- else
396
+ elsif access.include? 'full'
399
397
  green
398
+ else
399
+ cyan
400
400
  end
401
401
  end
402
402
 
403
403
  def get_access_string(access, return_color=cyan)
404
+ access ||= 'default'
404
405
  get_access_color(access) + access.to_s + return_color.to_s
405
406
  # access ||= 'none'
406
407
  # if access == 'none'
@@ -469,7 +470,7 @@ module Morpheus::Cli::AccountsHelper
469
470
  end
470
471
  # ok build out string
471
472
  out = ""
472
- access_color = get_access_color(access)
473
+ access_color = get_access_color(access || 'default')
473
474
  out << access_color if access_color
474
475
  out << padded_value
475
476
  out << reset if access_color
@@ -479,4 +479,83 @@ module Morpheus::Cli::InfrastructureHelper
479
479
  return {success:true, data: record_ids}
480
480
  end
481
481
 
482
+ def network_pool_server_list_column_definitions(options)
483
+ {
484
+ "ID" => 'id',
485
+ "Name" => lambda {|it| it['name'] },
486
+ "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
487
+ "URL" => lambda {|it| it['serviceUrl'] },
488
+ #"Pools" => lambda {|it| it['pools'] ? anded_list(it['pools'].collect {|p| p['name'] }, 3) : '' },
489
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
490
+ "Status" => lambda {|it| format_network_pool_server_status(it) },
491
+ "Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
492
+ "Last Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
493
+ }
494
+ end
495
+
496
+ def network_pool_server_column_definitions(options)
497
+ {
498
+ "ID" => 'id',
499
+ "Name" => lambda {|it| it['name'] },
500
+ "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
501
+ "URL" => lambda {|it| it['serviceUrl'] },
502
+ "App ID" => lambda {|it| it['config'] ? it['config']['appId'] : nil },
503
+ "Credentials" => lambda {|it| it['credential'] ? (it['credential']['type'] == 'local' ? '(Local)' : it['credential']['name']) : nil },
504
+ "Username" => lambda {|it| it['serviceUsername'] },
505
+ "Password" => lambda {|it| it['servicePassword'] },
506
+ "Throttle Rate" => lambda {|it| it['serviceThrottleRate'] },
507
+ "Disable SSL SNI" => lambda {|it| format_boolean it['ignoreSsl'] },
508
+ "Inventory Existing" => lambda {|it| format_boolean(it['config'] ? it['config']['inventoryExisting'] : nil) },
509
+ "IP Mode" => lambda {|it| it['serviceMode'] },
510
+ "Network Filter" => lambda {|it| it['networkFilter'] },
511
+ "Zone Filter" => lambda {|it| it['zoneFilter'] },
512
+ "Tenant Match" => lambda {|it| it['tenantMatch'] },
513
+ "Extra Attributes" => lambda {|it| it['config'] ? it['config']['extraAttributes'] : nil },
514
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
515
+ "Status" => lambda {|it| format_network_pool_server_status(it) },
516
+ #"Pools" => lambda {|it| it['pools'] ? anded_list(it['pools'].collect {|p| p['name'] }, 3) : '' },
517
+ "Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
518
+ "Last Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
519
+ }
520
+ end
521
+
522
+ def format_network_pool_server_status(network_pool_server, return_color=cyan)
523
+ out = ""
524
+ status_string = network_pool_server['status']
525
+ if status_string.nil? || status_string.empty? || status_string == "unknown"
526
+ out << "#{white}UNKNOWN#{network_pool_server['statusMessage'] ? "#{return_color} - #{network_pool_server['statusMessage']}" : ''}#{return_color}"
527
+ # elsif network_pool_server['enabled'] == false
528
+ # out << "#{red}DISABLED#{network_pool_server['statusMessage'] ? "#{return_color} - #{network_pool_server['statusMessage']}" : ''}#{return_color}"
529
+ elsif status_string == 'ok'
530
+ out << "#{green}#{status_string.upcase}#{return_color}"
531
+ elsif status_string == 'error' || status_string == 'offline'
532
+ out << "#{red}#{status_string ? status_string.upcase : 'N/A'}#{network_pool_server['statusMessage'] ? "#{return_color} - #{network_pool_server['statusMessage']}" : ''}#{return_color}"
533
+ else
534
+ out << "#{yellow}#{status_string.upcase}#{return_color}"
535
+ end
536
+ out
537
+ end
538
+
539
+ def network_pool_server_type_list_column_definitions(options)
540
+ {
541
+ "ID" => 'id',
542
+ "Name" => 'name',
543
+ "Code" => 'code',
544
+ }
545
+ end
546
+
547
+ def network_pool_server_type_column_definitions(options)
548
+ {
549
+ "ID" => 'id',
550
+ "Name" => 'name',
551
+ "Code" => 'code',
552
+ # "Integration Code" => 'integrationCode',
553
+ "Description" => 'description',
554
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
555
+ "Selectable" => lambda {|it| format_boolean(it['selectable']) },
556
+ "Plugin" => lambda {|it| format_boolean(it['isPlugin']) },
557
+ "Embedded" => lambda {|it| format_boolean(it['isEmbedded']) },
558
+ }
559
+ end
560
+
482
561
  end
@@ -79,22 +79,21 @@ module Morpheus::Cli::JobsHelper
79
79
 
80
80
  if process_data[:output] && process_data[:output].strip.length > 0
81
81
  print_h2 "Output"
82
- print process['output']
82
+ print process['output'].to_s.strip
83
+ print reset,"\n"
83
84
  end
84
85
  if process_data[:error] && process_data[:error].strip.length > 0
85
86
  print_h2 "Error"
86
- print process['message'] || process['error']
87
+ print (process['message'] || process['error']).to_s.strip
87
88
  print reset,"\n"
88
89
  end
89
-
90
90
 
91
91
  if process['events'] && !process['events'].empty?
92
92
  print_h2 "Process Events", options
93
93
  print_process_events(process['events'], options)
94
94
  end
95
- else
96
- print reset,"\n"
97
95
  end
96
+ print reset,"\n"
98
97
  return 0, nil
99
98
  end
100
99
 
@@ -59,6 +59,7 @@ module Morpheus::Cli::LibraryHelper
59
59
  {"NAME" => lambda {|instance_type| instance_type['name'] } },
60
60
  {"CODE" => lambda {|instance_type| instance_type['code'] } },
61
61
  {"TECHNOLOGY" => lambda {|instance_type| format_instance_type_technology(instance_type) } },
62
+ {"LABELS" => lambda {|instance_type| format_list(instance_type['labels'], '', 3) } },
62
63
  {"CATEGORY" => lambda {|instance_type| instance_type['category'].to_s.capitalize } },
63
64
  {"FEATURED" => lambda {|instance_type| format_boolean instance_type['featured'] } },
64
65
  {"OWNER" => lambda {|instance_type| instance_type['account'] ? instance_type['account']['name'] : '' } },
@@ -169,6 +170,7 @@ module Morpheus::Cli::LibraryHelper
169
170
  {"NAME" => lambda {|it| it['name'] } },
170
171
  {"SHORT NAME" => lambda {|it| it['shortName'] } },
171
172
  {"VERSION" => lambda {|it| it['containerVersion'] } },
173
+ {"LABELS" => lambda {|it| format_list(it['labels'], '', 3) } },
172
174
  {"CATEGORY" => lambda {|it| it['category'] } },
173
175
  {"OWNER" => lambda {|it| it['account'] ? it['account']['name'] : '' } }
174
176
  ]
@@ -47,6 +47,9 @@ module Morpheus::Cli::LogsHelper
47
47
  table_color = options.key?(:color) ? options[:color] : cyan
48
48
  term_width = current_terminal_width()
49
49
  message_col_width = current_terminal_width() - (show_object ? 56 : 36)
50
+ if options[:reverse]
51
+ log_records.reverse!
52
+ end
50
53
  log_records.each do |log_entry|
51
54
  log_level = format_log_level(log_entry['level'], table_color, 6)
52
55
  out << table_color if table_color
@@ -823,7 +823,7 @@ module Morpheus::Cli::MonitoringHelper
823
823
  # Apps
824
824
 
825
825
  monitor_app_list = nil
826
- monitor_app_ids = nil
826
+ monitor_app_ids = []
827
827
  if params['apps'].nil?
828
828
  still_prompting = true
829
829
  while still_prompting
@@ -714,7 +714,13 @@ module Morpheus::Cli::PrintHelper
714
714
  #
715
715
  def as_pretty_table(data, columns, options={})
716
716
  data = [data].flatten
717
-
717
+ if options[:reverse]
718
+ if data.is_a?(Array)
719
+ data.reverse!
720
+ elsif data.is_a?(Hash)
721
+ data.values.each {|v| v.reverse! if v.is_a?(Array) }
722
+ end
723
+ end
718
724
  # support --fields x,y,z and --all-fields or --fields all
719
725
  all_fields = data.first ? data.first.keys : []
720
726
  #todo: support --raw-fields meh, not really needed..
@@ -1106,7 +1112,13 @@ module Morpheus::Cli::PrintHelper
1106
1112
  newline = options[:csv_newline] || options[:newline] || "\n"
1107
1113
  include_header = options[:csv_no_header] ? false : true
1108
1114
  do_quotes = options[:csv_quotes] || options[:quotes]
1109
-
1115
+ if options[:reverse]
1116
+ if data.is_a?(Array)
1117
+ data.reverse!
1118
+ elsif data.is_a?(Hash)
1119
+ data.values.each {|v| v.reverse! if v.is_a?(Array) }
1120
+ end
1121
+ end
1110
1122
  if options[:include_fields]
1111
1123
  data = transform_data_for_field_options(data, options, object_key)
1112
1124
  if data.is_a?(Hash)
@@ -1134,7 +1146,7 @@ module Morpheus::Cli::PrintHelper
1134
1146
  if data.is_a?(Hash)
1135
1147
  data = data[object_key]
1136
1148
  else
1137
- Morpheus::Logging::DarkPrinter.puts "as_csv() expects data as an to fetch object key '#{object_key}' from, #{records.class}." if Morpheus::Logging.debug?
1149
+ Morpheus::Logging::DarkPrinter.puts "as_csv() expects data as an to fetch object key '#{object_key}' from, #{data.class}." if Morpheus::Logging.debug?
1138
1150
  end
1139
1151
  end
1140
1152
  end
@@ -1216,7 +1228,13 @@ module Morpheus::Cli::PrintHelper
1216
1228
  if !data
1217
1229
  return "null" # "No data"
1218
1230
  end
1219
-
1231
+ if options[:reverse]
1232
+ if data.is_a?(Array)
1233
+ data.reverse!
1234
+ elsif data.is_a?(Hash)
1235
+ data.values.each {|v| v.reverse! if v.is_a?(Array) }
1236
+ end
1237
+ end
1220
1238
  if options[:include_fields]
1221
1239
  data = transform_data_for_field_options(data, options, object_key)
1222
1240
  end
@@ -1236,6 +1254,13 @@ module Morpheus::Cli::PrintHelper
1236
1254
  if !data
1237
1255
  return "null" # "No data"
1238
1256
  end
1257
+ if options[:reverse]
1258
+ if data.is_a?(Array)
1259
+ data.reverse!
1260
+ elsif data.is_a?(Hash)
1261
+ data.values.each {|v| v.reverse! if v.is_a?(Array) }
1262
+ end
1263
+ end
1239
1264
  if options[:include_fields]
1240
1265
  data = transform_data_for_field_options(data, options, object_key)
1241
1266
  end