morpheus-cli 4.1.4 → 4.1.5

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus.rb +5 -0
  3. data/lib/morpheus/api.rb +2 -2
  4. data/lib/morpheus/api/api_client.rb +47 -12
  5. data/lib/morpheus/api/appliance_settings_interface.rb +30 -0
  6. data/lib/morpheus/api/auth_interface.rb +14 -10
  7. data/lib/morpheus/api/clouds_interface.rb +7 -0
  8. data/lib/morpheus/api/clusters_interface.rb +17 -5
  9. data/lib/morpheus/api/custom_instance_types_interface.rb +2 -3
  10. data/lib/morpheus/api/deployments_interface.rb +7 -0
  11. data/lib/morpheus/api/execute_schedules_interface.rb +2 -3
  12. data/lib/morpheus/api/groups_interface.rb +7 -0
  13. data/lib/morpheus/api/license_interface.rb +9 -2
  14. data/lib/morpheus/api/load_balancers_interface.rb +7 -0
  15. data/lib/morpheus/api/logs_interface.rb +11 -2
  16. data/lib/morpheus/api/monitoring_alerts_interface.rb +45 -0
  17. data/lib/morpheus/api/monitoring_checks_interface.rb +2 -2
  18. data/lib/morpheus/api/monitoring_interface.rb +13 -8
  19. data/lib/morpheus/api/power_schedules_interface.rb +2 -3
  20. data/lib/morpheus/api/servers_interface.rb +5 -2
  21. data/lib/morpheus/api/setup_interface.rb +25 -7
  22. data/lib/morpheus/api/task_sets_interface.rb +7 -1
  23. data/lib/morpheus/api/tasks_interface.rb +7 -0
  24. data/lib/morpheus/api/virtual_images_interface.rb +2 -3
  25. data/lib/morpheus/api/whitelabel_settings_interface.rb +60 -0
  26. data/lib/morpheus/cli.rb +18 -14
  27. data/lib/morpheus/cli/access_token_command.rb +18 -2
  28. data/lib/morpheus/cli/appliance_settings_command.rb +303 -0
  29. data/lib/morpheus/cli/apps.rb +4 -3
  30. data/lib/morpheus/cli/archives_command.rb +0 -21
  31. data/lib/morpheus/cli/blueprints_command.rb +2 -2
  32. data/lib/morpheus/cli/cli_command.rb +32 -8
  33. data/lib/morpheus/cli/clouds.rb +6 -11
  34. data/lib/morpheus/cli/clusters.rb +346 -117
  35. data/lib/morpheus/cli/command_error.rb +4 -0
  36. data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
  37. data/lib/morpheus/cli/containers_command.rb +2 -1
  38. data/lib/morpheus/cli/credentials.rb +49 -4
  39. data/lib/morpheus/cli/deployments.rb +2 -2
  40. data/lib/morpheus/cli/dot_file.rb +2 -2
  41. data/lib/morpheus/cli/error_handler.rb +6 -3
  42. data/lib/morpheus/cli/execute_schedules_command.rb +1 -1
  43. data/lib/morpheus/cli/groups.rb +4 -4
  44. data/lib/morpheus/cli/hosts.rb +3 -2
  45. data/lib/morpheus/cli/image_builder_command.rb +0 -21
  46. data/lib/morpheus/cli/instances.rb +17 -4
  47. data/lib/morpheus/cli/library_container_types_command.rb +1 -1
  48. data/lib/morpheus/cli/library_layouts_command.rb +1 -1
  49. data/lib/morpheus/cli/library_upgrades_command.rb +1 -1
  50. data/lib/morpheus/cli/license.rb +185 -72
  51. data/lib/morpheus/cli/load_balancers.rb +4 -4
  52. data/lib/morpheus/cli/login.rb +4 -0
  53. data/lib/morpheus/cli/logs_command.rb +132 -0
  54. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +2 -2
  55. data/lib/morpheus/cli/mixins/logs_helper.rb +65 -0
  56. data/lib/morpheus/cli/mixins/monitoring_helper.rb +410 -28
  57. data/lib/morpheus/cli/mixins/print_helper.rb +14 -4
  58. data/lib/morpheus/cli/monitoring_alerts_command.rb +800 -0
  59. data/lib/morpheus/cli/monitoring_apps_command.rb +85 -28
  60. data/lib/morpheus/cli/monitoring_checks_command.rb +60 -27
  61. data/lib/morpheus/cli/monitoring_contacts_command.rb +54 -79
  62. data/lib/morpheus/cli/monitoring_groups_command.rb +62 -23
  63. data/lib/morpheus/cli/monitoring_incidents_command.rb +91 -70
  64. data/lib/morpheus/cli/network_pools_command.rb +39 -23
  65. data/lib/morpheus/cli/power_schedules_command.rb +1 -1
  66. data/lib/morpheus/cli/remote.rb +834 -275
  67. data/lib/morpheus/cli/roles.rb +100 -38
  68. data/lib/morpheus/cli/tasks.rb +1 -1
  69. data/lib/morpheus/cli/user_settings_command.rb +20 -12
  70. data/lib/morpheus/cli/version.rb +1 -1
  71. data/lib/morpheus/cli/virtual_images.rb +1 -1
  72. data/lib/morpheus/cli/whitelabel_settings_command.rb +546 -0
  73. data/lib/morpheus/cli/whoami.rb +1 -1
  74. data/lib/morpheus/cli/workflows.rb +2 -2
  75. data/lib/morpheus/terminal.rb +22 -8
  76. metadata +11 -2
@@ -125,6 +125,16 @@ module Morpheus::Cli::PrintHelper
125
125
  end
126
126
  end
127
127
 
128
+ def parse_rest_exception(e, options={})
129
+ data = {}
130
+ begin
131
+ data = JSON.parse(e.response.to_s)
132
+ rescue => ex
133
+ # Morpheus::Logging::DarkPrinter.puts "Failed to parse error response as JSON: #{ex}" if Morpheus::Logging.debug?
134
+ end
135
+ return data
136
+ end
137
+
128
138
  def print_dry_run(api_request, options={})
129
139
  # 2nd argument used to be command_string (String)
130
140
  command_string = nil
@@ -212,14 +222,14 @@ module Morpheus::Cli::PrintHelper
212
222
  # curl output?
213
223
  if api_request[:curl] || options[:curl]
214
224
  print "\n"
215
- puts "#{cyan}#{bold}#{dark}CURL COMMAND#{reset}\n"
225
+ puts "#{cyan}#{bold}#{dark}CURL COMMAND#{reset}"
216
226
  print format_curl_command(http_method, url, headers, payload, options)
217
227
  print "\n"
218
228
  return
219
229
  end
220
230
 
221
231
  print "\n"
222
- puts "#{cyan}#{bold}#{dark}REQUEST#{reset}\n"
232
+ puts "#{cyan}#{bold}#{dark}REQUEST#{reset}"
223
233
  request_string = "#{http_method.to_s.upcase} #{url}".strip
224
234
  print request_string, "\n"
225
235
  print cyan
@@ -233,7 +243,7 @@ module Morpheus::Cli::PrintHelper
233
243
  #payload = "(unparsable) #{payload}"
234
244
  end
235
245
  end
236
- puts "#{cyan}#{bold}#{dark}JSON#{reset}\n"
246
+ puts "#{cyan}#{bold}#{dark}JSON#{reset}"
237
247
  print JSON.pretty_generate(payload)
238
248
  else
239
249
  print "Content-Type: #{content_type}", "\n"
@@ -277,7 +287,7 @@ module Morpheus::Cli::PrintHelper
277
287
  options ||= {}
278
288
  # build curl [options]
279
289
  out = ""
280
- out << "curl -X#{http_method.to_s.upcase} '#{url}'"
290
+ out << "curl -X#{http_method.to_s.upcase} \"#{url}\""
281
291
  if headers
282
292
  headers.each do |k,v|
283
293
  # avoid weird [:headers][:params]
@@ -0,0 +1,800 @@
1
+ # require 'yaml'
2
+ require 'time'
3
+ require 'io/console'
4
+ require 'rest_client'
5
+ require 'optparse'
6
+ require 'filesize'
7
+ require 'morpheus/cli/cli_command'
8
+ require 'morpheus/cli/mixins/provisioning_helper'
9
+
10
+ class Morpheus::Cli::MonitoringAlertsCommand
11
+ include Morpheus::Cli::CliCommand
12
+ include Morpheus::Cli::MonitoringHelper
13
+
14
+ set_command_name :'monitor-alerts'
15
+
16
+ register_subcommands :list, :get, :add, :update, :remove
17
+
18
+ set_command_hidden # hiding until 4.1.1 release
19
+
20
+ def initialize()
21
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
22
+ end
23
+
24
+ def connect(opts)
25
+ @api_client = establish_remote_appliance_connection(opts)
26
+ @monitoring_interface = @api_client.monitoring
27
+ @monitoring_alerts_interface = @api_client.monitoring.alerts
28
+ @monitoring_checks_interface = @api_client.monitoring.checks
29
+ @monitoring_groups_interface = @api_client.monitoring.groups
30
+ @monitoring_apps_interface = @api_client.monitoring.apps
31
+ @monitoring_contacts_interface = @api_client.monitoring.contacts
32
+ end
33
+
34
+ def handle(args)
35
+ handle_subcommand(args)
36
+ end
37
+
38
+ def list(args)
39
+ options = {}
40
+ params = {}
41
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
42
+ opts.banner = subcommand_usage()
43
+ build_common_options(opts, options, [:list, :last_updated, :query, :json, :csv, :yaml, :fields, :json, :dry_run, :remote])
44
+ opts.footer = "List monitoring alert rules."
45
+ end
46
+ optparse.parse!(args)
47
+ connect(options)
48
+ begin
49
+ params.merge!(parse_list_options(options))
50
+ # JD: lastUpdated 500ing, alerts don't have that property ? =o Fix it!
51
+ @monitoring_alerts_interface.setopts(options)
52
+ if options[:dry_run]
53
+ print_dry_run @monitoring_alerts_interface.dry.list(params)
54
+ return
55
+ end
56
+
57
+ json_response = @monitoring_alerts_interface.list(params)
58
+ if options[:json]
59
+ puts as_json(json_response, options, "alerts")
60
+ return 0
61
+ elsif options[:yaml]
62
+ puts as_json(json_response, options, "alerts")
63
+ return 0
64
+ elsif options[:csv]
65
+ puts records_as_csv(json_response['alerts'], options)
66
+ return 0
67
+ end
68
+ alerts = json_response['alerts']
69
+ title = "Morpheus Monitoring Alerts"
70
+ subtitles = []
71
+ subtitles += parse_list_subtitles(options)
72
+ print_h1 title, subtitles, options
73
+ if alerts.empty?
74
+ print cyan,"No alerts found.",reset,"\n"
75
+ else
76
+ print_alerts_table(alerts, options)
77
+ print_results_pagination(json_response, {:label => "alert", :n_label => "alerts"})
78
+ end
79
+ print reset,"\n"
80
+ rescue RestClient::Exception => e
81
+ print_rest_exception(e, options)
82
+ exit 1
83
+ end
84
+ end
85
+
86
+ def get(args)
87
+ options = {}
88
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
89
+ opts.banner = subcommand_usage("[alert]")
90
+ # opts.on(nil,'--history', "Display History") do |val|
91
+ # options[:show_history] = true
92
+ # end
93
+ # opts.on(nil,'--notifications', "Display Notifications") do |val|
94
+ # options[:show_notifications] = true
95
+ # end
96
+ build_common_options(opts, options, [:json, :csv, :fields, :dry_run, :remote])
97
+ opts.footer = "Get details about a monitoring alert rule." + "\n" +
98
+ "[alert] is required. This is the name or ID of the alert rule. Supports 1-N [alert] arguments."
99
+ end
100
+ optparse.parse!(args)
101
+ if args.count < 1
102
+ raise_command_error "wrong number of arguments, expected 1-N and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
103
+ end
104
+ connect(options)
105
+ id_list = parse_id_list(args)
106
+ return run_command_for_each_arg(id_list) do |arg|
107
+ _get(arg, options)
108
+ end
109
+ end
110
+
111
+ def _get(id, options)
112
+
113
+ begin
114
+ alert = find_alert_by_name_or_id(id)
115
+ @monitoring_alerts_interface.setopts(options)
116
+ if options[:dry_run]
117
+ print_dry_run @monitoring_alerts_interface.dry.get(alert['id'])
118
+ return
119
+ end
120
+ # get by ID to sideload associated checks,groups,apps
121
+ json_response = @monitoring_alerts_interface.get(alert['id'])
122
+ alert = json_response['alert']
123
+ if options[:json]
124
+ puts as_json(json_response, options, "alert")
125
+ return 0
126
+ elsif options[:yaml]
127
+ puts as_yaml(json_response, options, "alert")
128
+ return 0
129
+ elsif options[:csv]
130
+ puts records_as_csv([json_response['alert']], options)
131
+ return 0
132
+ end
133
+
134
+ print_h1 "Alert Details"
135
+ print cyan
136
+ description_cols = {
137
+ "ID" => 'id',
138
+ "Name" => 'name',
139
+ "Min. Severity" => "minSeverity",
140
+ "Min. Duration" => lambda {|alert| alert['minDuration'] && alert['minDuration'].to_i > 0 ? "#{alert['minDuration']} minutes" : "0 (immediate)" },
141
+ "Checks" => lambda {|alert|
142
+ if alert['allChecks']
143
+ "All"
144
+ else
145
+ checks = alert['checks'] || []
146
+ # if checks.size > 3
147
+ # checks.first(3).collect {|r| r['name'] }.join(", ") + ", (#{checks.size - 3} more)"
148
+ # else
149
+ # checks.collect {|r| r['name'] }.join(", ")
150
+ # end
151
+ checks.size.to_s
152
+ end
153
+ },
154
+ "Groups" => lambda {|alert|
155
+ if alert['allGroups']
156
+ "All"
157
+ else
158
+ check_groups = alert['checkGroups'] || []
159
+ # if check_groups.size > 3
160
+ # check_groups.first(3).collect {|r| r['name'] }.join(", ") + ", (#{check_groups.size - 3} more)"
161
+ # else
162
+ # check_groups.collect {|r| r['name'] }.join(", ")
163
+ # end
164
+ check_groups.size.to_s
165
+ end
166
+ },
167
+ "Apps" => lambda {|alert|
168
+ if alert['allApps']
169
+ "All"
170
+ else
171
+ monitor_apps = alert['apps'] || []
172
+ # if monitor_apps.size > 3
173
+ # monitor_apps.first(3).collect {|r| r['name'] }.join(", ") + ", (#{monitor_apps.size - 3} more)"
174
+ # else
175
+ # monitor_apps.collect {|r| r['name'] }.join(", ")
176
+ # end
177
+ monitor_apps.size.to_s
178
+ end
179
+ },
180
+ "Contacts" => lambda {|alert|
181
+ recipients = alert['contacts'] || alert['recipients'] || []
182
+ # if recipients.size > 3
183
+ # recipients.first(3).collect {|r| r['name'] }.join(", ") + ", (#{recipients.size - 3} more)"
184
+ # else
185
+ # recipients.collect {|r| r['name'] }.join(", ")
186
+ # end
187
+ recipients.size.to_s
188
+ },
189
+ "Created" => lambda {|alert| format_local_dt(alert['dateCreated']) },
190
+ "Updated" => lambda {|alert| format_local_dt(alert['lastUpdated']) },
191
+ }
192
+ print as_description_list(alert, description_cols)
193
+
194
+
195
+
196
+ ## Checks in this Alert
197
+ #checks = alert["checks"]
198
+ checks = json_response["checks"]
199
+ if checks && !checks.empty?
200
+ print_h2 "Checks"
201
+ print_checks_table(checks, options)
202
+ end
203
+
204
+ ## Check Groups in this Alert
205
+ # check_groups = alert["checkGroups"]
206
+ check_groups = json_response["checkGroups"]
207
+ if check_groups && !check_groups.empty?
208
+ print_h2 "Check Groups"
209
+ print_check_groups_table(check_groups, options)
210
+ end
211
+
212
+ ## Apps in this Alert
213
+ monitor_apps = alert["apps"]
214
+ monitor_apps = json_response["apps"]
215
+ if monitor_apps && !monitor_apps.empty?
216
+ print_h2 "Apps"
217
+ print_monitoring_apps_table(monitor_apps, options)
218
+ end
219
+
220
+ ## Recipients in this Alert
221
+ recipients = alert['contacts'] || alert['recipients'] || []
222
+ if recipients && !recipients.empty?
223
+ print_h2 "Contacts"
224
+ columns = [
225
+ {"CONTACT ID" => lambda {|recipient| recipient['id'] } },
226
+ {"CONTACT NAME" => lambda {|recipient| recipient['name'] } },
227
+ {"METHOD" => lambda {|recipient| format_recipient_method(recipient['method'] || recipient['addressTypes']) } },
228
+ {"NOTIFY ON CHANGE" => lambda {|recipient| format_boolean(recipient['notify']) } },
229
+ {"NOTIFY ON CLOSE" => lambda {|recipient| format_boolean(recipient['close']) } }
230
+ ]
231
+ print as_pretty_table(recipients, columns)
232
+ end
233
+
234
+ # show Notify events here...
235
+
236
+ print reset, "\n"
237
+ return 0
238
+ rescue RestClient::Exception => e
239
+ print_rest_exception(e, options)
240
+ exit 1
241
+ end
242
+ end
243
+
244
+ def add(args)
245
+ options = {}
246
+ params = {}
247
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
248
+ opts.banner = subcommand_usage("[name]")
249
+ opts.on("--name STRING", String, "Alert name") do |val|
250
+ params['name'] = val
251
+ end
252
+ opts.on('--min-severity VALUE', String, "Min. Severity. Trigger when severity level is reached. Default is critical") do |val|
253
+ params['minSeverity'] = val.to_s.downcase
254
+ end
255
+ opts.on('--min-duration MINUTES', String, "Min. Duration. Trigger after a number of minutes. Default is 0 (immediate)") do |val|
256
+ params['minDuration'] = val.to_i
257
+ end
258
+ opts.on('--all-checks [on|off]', String, "Toggle trigger for all checks.") do |val|
259
+ params['allChecks'] = val.to_s == 'on' || val.to_s == 'true' || val == '' || val.nil?
260
+ end
261
+ opts.on('--checks LIST', Array, "Checks, comma separated list of names or IDs.") do |list|
262
+ if list.size == 1 && ('[]' == list[0]) # clear array
263
+ params['checks'] = []
264
+ else
265
+ params['checks'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
266
+ end
267
+ end
268
+ opts.on('--all-groups [on|off]', String, "Toggle trigger for all check groups.") do |val|
269
+ params['allGroups'] = val.to_s == 'on' || val.to_s == 'true' || val == '' || val.nil?
270
+ end
271
+ opts.on('--groups LIST', Array, "Check Groups, comma separated list of names or IDs.") do |list|
272
+ if list.size == 1 && ('[]' == list[0]) # clear array
273
+ params['checkGroups'] = []
274
+ else
275
+ params['checkGroups'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
276
+ end
277
+ end
278
+ opts.on('--all-apps [on|off]', String, "Toggle trigger for all check groups.") do |val|
279
+ params['allApps'] = val.to_s == 'on' || val.to_s == 'true' || val == '' || val.nil?
280
+ end
281
+ opts.on('--apps LIST', Array, "Monitor Apps, comma separated list of names or IDs.") do |list|
282
+ if list.size == 1 && ('[]' == list[0]) # clear array
283
+ params['apps'] = []
284
+ else
285
+ params['apps'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
286
+ end
287
+ end
288
+ opts.on('--contacts LIST', Array, "Contacts, comma separated list of Contact names or IDs. Additional recipient settings can be passed like Contact ID:method:notifyOnClose:notifyOnChange.") do |list|
289
+ if list.size == 1 && ('[]' == list[0]) # clear array
290
+ params['contacts'] = []
291
+ else
292
+ recipient_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
293
+ params['contacts'] = recipient_list
294
+ end
295
+ end
296
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
297
+ opts.footer = "Create a monitoring alert rule." + "\n" +
298
+ "[name] is required. This is the name of the new alert rule."
299
+ end
300
+ optparse.parse!(args)
301
+ if args.count > 1
302
+ raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
303
+ end
304
+ if args[0]
305
+ params['name'] = args[0]
306
+ end
307
+ connect(options)
308
+
309
+ begin
310
+
311
+ # construct payload
312
+ payload = nil
313
+ if options[:payload]
314
+ payload = options[:payload]
315
+ else
316
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
317
+ if params['name'].nil?
318
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true, 'description' => 'The name of this alert rule.'}], options[:options])
319
+ params['name'] = v_prompt['name']
320
+ end
321
+ if params['minSeverity'].nil?
322
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'minSeverity', 'type' => 'text', 'fieldLabel' => 'Min. Severity', 'required' => false, 'selectOptions' => available_severities, 'defaultValue' => 'critical', 'description' => 'Trigger when severity level is reached.'}], options[:options])
323
+ params['minSeverity'] = v_prompt['minSeverity'].to_s unless v_prompt['minSeverity'].nil?
324
+ end
325
+ if params['minDuration'].nil?
326
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'minDuration', 'type' => 'text', 'fieldLabel' => 'Min. Duration', 'required' => false, 'defaultValue' => '0', 'description' => 'Trigger after a number of minutes.'}], options[:options])
327
+ params['minDuration'] = v_prompt['minDuration'].to_i unless v_prompt['minDuration'].nil?
328
+ end
329
+ # All Checks?
330
+ if params['allChecks'].nil?
331
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'allChecks', 'type' => 'text', 'fieldLabel' => 'All Checks?', 'required' => false, 'defaultValue' => 'off', 'description' => 'Trigger for all checks.'}], options[:options])
332
+ params['allChecks'] = (['on','true'].include?(v_prompt['allChecks'].to_s)) unless v_prompt['allChecks'].nil?
333
+ end
334
+ # Checks
335
+ if params['allChecks'] == true
336
+ params.delete('checks')
337
+ else
338
+ prompt_results = prompt_for_checks(params, options, @api_client)
339
+ if prompt_results[:success]
340
+ params['checks'] = prompt_results[:data] unless prompt_results[:data].nil?
341
+ else
342
+ return 1
343
+ end
344
+ end
345
+
346
+ # All Check Groups?
347
+ if params['allGroups'].nil?
348
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'allGroups', 'type' => 'text', 'fieldLabel' => 'All Groups?', 'required' => false, 'defaultValue' => 'off', 'description' => 'Trigger for all check groups.'}], options[:options])
349
+ params['allGroups'] = (['on','true'].include?(v_prompt['allGroups'].to_s)) unless v_prompt['allGroups'].nil?
350
+ end
351
+ # Check Groups
352
+ if params['allGroups'] == true
353
+ params.delete('checkGroups')
354
+ else
355
+ prompt_results = prompt_for_check_groups(params, options, @api_client)
356
+ if prompt_results[:success]
357
+ params['checkGroups'] = prompt_results[:data] unless prompt_results[:data].nil?
358
+ else
359
+ return 1
360
+ end
361
+ end
362
+
363
+ # All Apps?
364
+ if params['allApps'].nil?
365
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'allApps', 'type' => 'text', 'fieldLabel' => 'All Apps?', 'required' => false, 'defaultValue' => 'off', 'description' => 'Trigger for all monitoring apps.'}], options[:options])
366
+ params['allApps'] = (['on','true'].include?(v_prompt['allApps'].to_s)) unless v_prompt['allApps'].nil?
367
+ end
368
+ # Apps
369
+ if params['allApps'] == true
370
+ params.delete('apps')
371
+ else
372
+ prompt_results = prompt_for_monitor_apps(params, options, @api_client)
373
+ if prompt_results[:success]
374
+ params['apps'] = prompt_results[:data] unless prompt_results[:data].nil?
375
+ else
376
+ return 1
377
+ end
378
+ end
379
+
380
+ # Recipients (Contacts)
381
+ recipient_list = []
382
+ contact_ids = []
383
+
384
+ if params['contacts'].nil?
385
+ still_prompting = true
386
+ while still_prompting
387
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'contacts', 'type' => 'text', 'fieldLabel' => 'Contacts', 'required' => false, 'description' => "Contacts, comma separated list of contact names or IDs. Additional recipient settings can be passed like Contact ID:method:notifyOnClose:notifyOnChange"}], options[:options])
388
+ unless v_prompt['contacts'].to_s.empty?
389
+ recipient_list = v_prompt['contacts'].split(",").collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
390
+ end
391
+ bad_ids = []
392
+ if recipient_list && recipient_list.size > 0
393
+ recipient_list.each do |it|
394
+ found_contact = nil
395
+ begin
396
+ parts = it.split(":").collect { |part| part.strip }
397
+ found_contact = find_contact_by_name_or_id(parts[0])
398
+ rescue SystemExit => cmdexit
399
+ end
400
+ if found_contact
401
+ contact_ids << found_contact['id']
402
+ else
403
+ bad_ids << it
404
+ end
405
+ end
406
+ end
407
+ still_prompting = bad_ids.empty? ? false : true
408
+ end
409
+ else
410
+ recipient_list = params['contacts']
411
+ bad_ids = []
412
+ if recipient_list && recipient_list.size > 0
413
+ recipient_list.each do |it|
414
+ found_contact = nil
415
+ begin
416
+ parts = it.split(":").collect { |part| part.strip }
417
+ found_contact = find_contact_by_name_or_id(parts[0])
418
+ rescue SystemExit => cmdexit
419
+ end
420
+ if found_contact
421
+ contact_ids << found_contact['id']
422
+ else
423
+ bad_ids << it
424
+ end
425
+ end
426
+ end
427
+ if !bad_ids.empty?
428
+ return 1
429
+ end
430
+ end
431
+ recipient_records = []
432
+ # parse recipient string as Contact ID:method:notifyOnClose:notifyOnChange
433
+ recipient_list.each_with_index do |it, index|
434
+ parts = it.split(":").collect { |part| part.strip }
435
+ #recipient_id = parts[0]
436
+ recipient_id = contact_ids[index]
437
+
438
+ recipient_method = parts[1] ? parts[1].to_s : "emailAddress"
439
+ recipient_notify = parts[2] ? ['on','true'].include?(parts[2].to_s.downcase) : true
440
+ recipient_close = parts[3] ? ['on','true'].include?(parts[3].to_s.downcase) : true
441
+ recipient_record = {
442
+ "id" => recipient_id,
443
+ "method" => parse_recipient_method(recipient_method),
444
+ "notify" => recipient_notify,
445
+ "close" => recipient_close
446
+ }
447
+ recipient_records << recipient_record
448
+ end
449
+ params['contacts'] = recipient_records
450
+
451
+ payload = {'alert' => params}
452
+ end
453
+
454
+ @monitoring_alerts_interface.setopts(options)
455
+ if options[:dry_run]
456
+ print_dry_run @monitoring_alerts_interface.dry.create(payload)
457
+ return
458
+ end
459
+
460
+ json_response = @monitoring_alerts_interface.create(payload)
461
+ alert = json_response['alert']
462
+ if options[:json]
463
+ puts as_json(json_response, options)
464
+ elsif !options[:quiet]
465
+ print_green_success "Created alert (#{alert['id']}) #{alert['name']}"
466
+ #_get(alert['id'], options)
467
+ end
468
+
469
+ rescue RestClient::Exception => e
470
+ print_rest_exception(e, options)
471
+ exit 1
472
+ end
473
+ end
474
+
475
+ def update(args)
476
+ options = {}
477
+ params = {}
478
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
479
+ opts.banner = subcommand_usage("[alert]")
480
+ opts.on("--name STRING", String, "Alert name") do |val|
481
+ params['name'] = val
482
+ end
483
+ opts.on("--name STRING", String, "Alert name") do |val|
484
+ params['name'] = val
485
+ end
486
+ opts.on('--min-severity VALUE', String, "Min. Severity. Trigger when severity level is reached. Default is critical") do |val|
487
+ params['minSeverity'] = val.to_s.downcase
488
+ end
489
+ opts.on('--min-duration MINUTES', String, "Min. Duration. Trigger after a number of minutes. Default is 0 (immediate)") do |val|
490
+ params['minDuration'] = val.to_i
491
+ end
492
+ opts.on('--all-checks [on|off]', String, "Toggle trigger for all checks.") do |val|
493
+ params['allChecks'] = val.to_s == 'on' || val.to_s == 'true' || val == '' || val.nil?
494
+ end
495
+ opts.on('--checks LIST', Array, "Checks, comma separated list of names or IDs.") do |list|
496
+ if list.size == 1 && ('[]' == list[0]) # clear array
497
+ params['checks'] = []
498
+ else
499
+ params['checks'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
500
+ end
501
+ end
502
+ opts.on('--all-groups [on|off]', String, "Toggle trigger for all check groups.") do |val|
503
+ params['allGroups'] = val.to_s == 'on' || val.to_s == 'true' || val == '' || val.nil?
504
+ end
505
+ opts.on('--groups LIST', Array, "Check Groups, comma separated list of check group ID or names.") do |list|
506
+ if list.size == 1 && ('[]' == list[0]) # clear array
507
+ params['checkGroups'] = []
508
+ else
509
+ params['checkGroups'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
510
+ end
511
+ end
512
+ opts.on('--all-apps [on|off]', String, "Toggle trigger for all check groups.") do |val|
513
+ params['allApps'] = val.to_s == 'on' || val.to_s == 'true' || val == '' || val.nil?
514
+ end
515
+ opts.on('--apps LIST', Array, "Monitor Apps, comma separated list of monitor app ID or names.") do |list|
516
+ if list.size == 1 && ('[]' == list[0]) # clear array
517
+ params['apps'] = []
518
+ else
519
+ params['apps'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
520
+ end
521
+ end
522
+ opts.on('--contacts LIST', Array, "Contacts, comma separated list of contact ID or names. Additional recipient settings can be passed like Contact ID:method:notifyOnClose:notifyOnChange") do |list|
523
+ if list.size == 1 && ('[]' == list[0]) # clear array
524
+ params['contacts'] = []
525
+ else
526
+ recipient_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
527
+ params['contacts'] = recipient_list
528
+ end
529
+ end
530
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
531
+ opts.footer = "Update a monitoring alert rule." + "\n" +
532
+ "[alert] is required. This is the name or ID of the alert rule."
533
+ end
534
+ optparse.parse!(args)
535
+ if args.count != 1
536
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
537
+ end
538
+ connect(options)
539
+
540
+ begin
541
+ alert = find_alert_by_name_or_id(args[0])
542
+
543
+ # construct payload
544
+ payload = nil
545
+ if options[:payload]
546
+ payload = options[:payload]
547
+ else
548
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
549
+ # if params['name'].nil?
550
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true, 'description' => 'The name of this alert rule.'}], options[:options])
551
+ # params['name'] = v_prompt['name']
552
+ # end
553
+ # if params['minSeverity'].nil?
554
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'minSeverity', 'type' => 'text', 'fieldLabel' => 'Min. Severity', 'required' => false, 'selectOptions' => available_severities, 'defaultValue' => 'critical', 'description' => 'Trigger when severity level is reached.'}], options[:options])
555
+ # params['minSeverity'] = v_prompt['minSeverity'].to_s unless v_prompt['minSeverity'].nil?
556
+ # end
557
+ # if params['minDuration'].nil?
558
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'minDuration', 'type' => 'text', 'fieldLabel' => 'Min. Duration', 'required' => false, 'defaultValue' => '0', 'description' => 'Trigger after a number of minutes.'}], options[:options])
559
+ # params['minDuration'] = v_prompt['minDuration'].to_i unless v_prompt['minDuration'].nil?
560
+ # end
561
+ # All Checks?
562
+ # if params['allChecks'].nil?
563
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'allChecks', 'type' => 'text', 'fieldLabel' => 'All Checks?', 'required' => false, 'defaultValue' => 'off', 'description' => 'Trigger for all checks.'}], options[:options])
564
+ # params['allChecks'] = (['on','true'].include?(v_prompt['allChecks'].to_s)) unless v_prompt['allChecks'].nil?
565
+ # end
566
+ # Checks
567
+ if params['checks']
568
+ prompt_results = prompt_for_checks(params, options, @api_client)
569
+ if prompt_results[:success]
570
+ params['checks'] = prompt_results[:data] unless prompt_results[:data].nil?
571
+ else
572
+ return 1
573
+ end
574
+ end
575
+
576
+ # All Check Groups?
577
+ # if params['allGroups'].nil?
578
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'allGroups', 'type' => 'text', 'fieldLabel' => 'All Groups?', 'required' => false, 'defaultValue' => 'off', 'description' => 'Trigger for all check groups.'}], options[:options])
579
+ # params['allGroups'] = (['on','true'].include?(v_prompt['allGroups'].to_s)) unless v_prompt['allGroups'].nil?
580
+ # end
581
+ # Check Groups
582
+ if params['checkGroups']
583
+ prompt_results = prompt_for_check_groups(params, options, @api_client)
584
+ if prompt_results[:success]
585
+ params['checkGroups'] = prompt_results[:data] unless prompt_results[:data].nil?
586
+ else
587
+ return 1
588
+ end
589
+ end
590
+
591
+ # All Apps?
592
+ # if params['allApps'].nil?
593
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'allApps', 'type' => 'text', 'fieldLabel' => 'All Apps?', 'required' => false, 'defaultValue' => 'off', 'description' => 'Trigger for all monitoring apps.'}], options[:options])
594
+ # params['allApps'] = (['on','true'].include?(v_prompt['allApps'].to_s)) unless v_prompt['allApps'].nil?
595
+ # end
596
+ # Apps
597
+ if params['apps']
598
+ prompt_results = prompt_for_monitor_apps(params, options, @api_client)
599
+ if prompt_results[:success]
600
+ params['apps'] = prompt_results[:data] unless prompt_results[:data].nil?
601
+ else
602
+ return 1
603
+ end
604
+ end
605
+
606
+ # Recipients (Contacts)
607
+ if params['contacts']
608
+
609
+ recipient_list = params['contacts']
610
+ contact_ids = []
611
+ bad_ids = []
612
+ if recipient_list && recipient_list.size > 0
613
+ recipient_list.each do |it|
614
+ found_contact = nil
615
+ begin
616
+ parts = it.split(":").collect { |part| part.strip }
617
+ found_contact = find_contact_by_name_or_id(parts[0])
618
+ rescue SystemExit => cmdexit
619
+ end
620
+ if found_contact
621
+ contact_ids << found_contact['id']
622
+ else
623
+ bad_ids << it
624
+ end
625
+ end
626
+ end
627
+ if !bad_ids.empty?
628
+ return 1
629
+ end
630
+ recipient_records = []
631
+ # parse recipient string as Contact ID:method:notifyOnClose:notifyOnChange
632
+ existing_recipients = alert['contacts'] || []
633
+ recipient_list.each_with_index do |it, index|
634
+ parts = it.split(":").collect { |part| part.strip }
635
+ #recipient_id = parts[0]
636
+ recipient_id = contact_ids[index]
637
+ recipient_record = {
638
+ "id" => recipient_id
639
+ }
640
+ # preserve existing values for these settings
641
+ existing_recipient = existing_recipients.find {|rec| rec['id'] == recipient_id.to_i }
642
+ if parts[1]
643
+ recipient_record["method"] = parse_recipient_method(parts[1].to_s)
644
+ elsif existing_recipient
645
+ recipient_record["method"] = existing_recipient["method"]
646
+ end
647
+ if parts[2]
648
+ recipient_record["notify"] = ['on','true'].include?(parts[2].to_s.downcase)
649
+ elsif existing_recipient
650
+ recipient_record["notify"] = existing_recipient["notify"]
651
+ end
652
+ if parts[3]
653
+ recipient_record["close"] = ['on','true'].include?(parts[3].to_s.downcase)
654
+ elsif existing_recipient
655
+ recipient_record["close"] = existing_recipient["close"]
656
+ end
657
+ recipient_records << recipient_record
658
+ end
659
+ params['contacts'] = recipient_records
660
+ end
661
+
662
+ payload = {'alert' => params}
663
+ end
664
+
665
+ if params.empty?
666
+ print_red_alert "Specify at least one option to update"
667
+ puts optparse
668
+ exit 1
669
+ end
670
+
671
+ @monitoring_alerts_interface.setopts(options)
672
+ if options[:dry_run]
673
+ print_dry_run @monitoring_alerts_interface.dry.update(alert["id"], payload)
674
+ return
675
+ end
676
+
677
+ json_response = @monitoring_alerts_interface.update(alert["id"], payload)
678
+ alert = json_response['alert']
679
+ if options[:json]
680
+ puts as_json(json_response, options)
681
+ elsif !options[:quiet]
682
+ print_green_success "Updated alert (#{alert['id']}) #{alert['name']}"
683
+ _get(alert['id'], options)
684
+ end
685
+
686
+ rescue RestClient::Exception => e
687
+ print_rest_exception(e, options)
688
+ exit 1
689
+ end
690
+ end
691
+
692
+
693
+ def remove(args)
694
+ options = {}
695
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
696
+ opts.banner = subcommand_usage("[alert]")
697
+ build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
698
+ opts.footer = "Delete a monitoring alert rule." + "\n" +
699
+ "[alert] is required. This is the name or ID of the alert rule. Supports 1-N [alert] arguments."
700
+ end
701
+ optparse.parse!(args)
702
+ if args.count < 1
703
+ raise_command_error "wrong number of arguments, expected 1-N and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
704
+ end
705
+ connect(options)
706
+ id_list = parse_id_list(args)
707
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to delete #{id_list.size == 1 ? 'alert' : 'alerts'} #{anded_list(id_list)}?", options)
708
+ exit 1
709
+ end
710
+ return run_command_for_each_arg(id_list) do |arg|
711
+ _remove(arg, options)
712
+ end
713
+ end
714
+
715
+ def _remove(id, options)
716
+
717
+ begin
718
+ alert = find_alert_by_name_or_id(id)
719
+ @monitoring_alerts_interface.setopts(options)
720
+ if options[:dry_run]
721
+ print_dry_run @monitoring_alerts_interface.dry.destroy(alert['id'])
722
+ return
723
+ end
724
+ json_response = @monitoring_alerts_interface.destroy(alert['id'])
725
+ if options[:json]
726
+ puts as_json(json_response, options)
727
+ elsif !options[:quiet]
728
+ print_green_success json_response["msg"] || "Alert (#{alert['id']}) #{alert['name']} deleted"
729
+ end
730
+ rescue RestClient::Exception => e
731
+ print_rest_exception(e, options)
732
+ exit 1
733
+ end
734
+ end
735
+
736
+ private
737
+
738
+ def print_alerts_table(alerts, options={})
739
+ columns = [
740
+ {"ID" => "id" },
741
+ {"NAME" => "name" },
742
+ {"APPS" => lambda {|alert|
743
+ if alert['allApps']
744
+ "All"
745
+ else
746
+ monitor_apps = alert['apps'] || []
747
+ # if monitor_apps.size > 3
748
+ # monitor_apps.first(3).collect {|r| r['name'] }.join(", ") + ", (#{monitor_apps.size - 3} more)"
749
+ # else
750
+ # monitor_apps.collect {|r| r['name'] }.join(", ")
751
+ # end
752
+ monitor_apps.size.to_s
753
+ end
754
+ } },
755
+ {"CHECKS" => lambda {|alert|
756
+ if alert['allChecks']
757
+ "All"
758
+ else
759
+ checks = alert['checks'] || []
760
+ # if checks.size > 3
761
+ # checks.first(3).collect {|r| r['name'] }.join(", ") + ", (#{checks.size - 3} more)"
762
+ # # checks.size.to_s
763
+ # else
764
+ # checks.collect {|r| r['name'] }.join(", ")
765
+ # end
766
+ checks.size.to_s
767
+ end
768
+ } },
769
+ {"GROUPS" => lambda {|alert|
770
+ if alert['allGroups']
771
+ "All"
772
+ else
773
+ check_groups = alert['checkGroups'] || []
774
+ # if check_groups.size > 3
775
+ # check_groups.first(3).collect {|r| r['name'] }.join(", ") + ", (#{check_groups.size - 3} more)"
776
+ # else
777
+ # check_groups.collect {|r| r['name'] }.join(", ")
778
+ # end
779
+ check_groups.size.to_s
780
+ end
781
+ } },
782
+ {"MIN. SEVERITY" => "minSeverity" },
783
+ {"CONTACTS" => lambda {|alert|
784
+ recipients = alert['contacts'] || alert['recipients'] || []
785
+ # if recipients.size > 3
786
+ # recipients.first(3).collect {|r| r['name'] }.join(", ") + ", (#{recipients.size - 3} more)"
787
+ # else
788
+ # recipients.collect {|r| r['name'] }.join(", ")
789
+ # end
790
+ recipients.size.to_s
791
+ } },
792
+ ]
793
+ if options[:include_fields]
794
+ columns = options[:include_fields]
795
+ end
796
+ print as_pretty_table(alerts, columns, options)
797
+ end
798
+
799
+
800
+ end