morpheus-cli 4.1.4 → 4.1.5

Sign up to get free protection for your applications and to get access to all the features.
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