pagerduty_tools 0.3.0

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.
data/.gitignore ADDED
@@ -0,0 +1,41 @@
1
+ # Ruby
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ coverage
7
+ InstalledFiles
8
+ lib/bundler/man
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+ Gemfile.lock
15
+ pkg/*
16
+
17
+
18
+ # YARD artifacts
19
+ .yardoc
20
+ _yardoc
21
+ doc/
22
+
23
+ # Emacs
24
+ *~
25
+ \#*\#
26
+ /.emacs.desktop
27
+ /.emacs.desktop.lock
28
+ .elc
29
+ auto-save-list
30
+ tramp
31
+
32
+ # OSX
33
+ .DS_Store
34
+ Icon?
35
+
36
+ # Thumbnails
37
+ ._*
38
+
39
+ # Files that might appear on external disk
40
+ .Spotlight-V100
41
+ .Trashes
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in pagerduty_tools.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,160 @@
1
+ Apache License
2
+
3
+ Version 2.0, January 2004
4
+
5
+ http://www.apache.org/licenses/
6
+
7
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
+
9
+ 1. Definitions.
10
+
11
+ "License" shall mean the terms and conditions for use, reproduction, and
12
+ distribution as defined by Sections 1 through 9 of this document.
13
+
14
+ "Licensor" shall mean the copyright owner or entity authorized by the
15
+ copyright owner that is granting the License.
16
+
17
+ "Legal Entity" shall mean the union of the acting entity and all other
18
+ entities that control, are controlled by, or are under common control with
19
+ that entity. For the purposes of this definition, "control" means (i) the
20
+ power, direct or indirect, to cause the direction or management of such
21
+ entity, whether by contract or otherwise, or (ii) ownership of fifty percent
22
+ (50%) or more of the outstanding shares, or (iii) beneficial ownership of such
23
+ entity.
24
+
25
+ "You" (or "Your") shall mean an individual or Legal Entity exercising
26
+ permissions granted by this License.
27
+
28
+ "Source" form shall mean the preferred form for making modifications,
29
+ including but not limited to software source code, documentation source, and
30
+ configuration files.
31
+
32
+ "Object" form shall mean any form resulting from mechanical transformation or
33
+ translation of a Source form, including but not limited to compiled object
34
+ code, generated documentation, and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or Object form,
37
+ made available under the License, as indicated by a copyright notice that is
38
+ included in or attached to the work (an example is provided in the Appendix
39
+ below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object form, that
42
+ is based on (or derived from) the Work and for which the editorial revisions,
43
+ annotations, elaborations, or other modifications represent, as a whole, an
44
+ original work of authorship. For the purposes of this License, Derivative
45
+ Works shall not include works that remain separable from, or merely link (or
46
+ bind by name) to the interfaces of, the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including the original
49
+ version of the Work and any modifications or additions to that Work or
50
+ Derivative Works thereof, that is intentionally submitted to Licensor for
51
+ inclusion in the Work by the copyright owner or by an individual or Legal
52
+ Entity authorized to submit on behalf of the copyright owner. For the purposes
53
+ of this definition, "submitted" means any form of electronic, verbal, or
54
+ written communication sent to the Licensor or its representatives, including
55
+ but not limited to communication on electronic mailing lists, source code
56
+ control systems, and issue tracking systems that are managed by, or on behalf
57
+ of, the Licensor for the purpose of discussing and improving the Work, but
58
+ excluding communication that is conspicuously marked or otherwise designated
59
+ in writing by the copyright owner as "Not a Contribution."
60
+
61
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
62
+ of whom a Contribution has been received by Licensor and subsequently
63
+ incorporated within the Work.
64
+
65
+ 2. Grant of Copyright License. Subject to the terms and conditions of this
66
+ License, each Contributor hereby grants to You a perpetual, worldwide,
67
+ non-exclusive, no-charge, royalty-free, irrevocable copyright license to
68
+ reproduce, prepare Derivative Works of, publicly display, publicly perform,
69
+ sublicense, and distribute the Work and such Derivative Works in Source or
70
+ Object form.
71
+
72
+ 3. Grant of Patent License. Subject to the terms and conditions of this
73
+ License, each Contributor hereby grants to You a perpetual, worldwide,
74
+ non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this
75
+ section) patent license to make, have made, use, offer to sell, sell, import,
76
+ and otherwise transfer the Work, where such license applies only to those
77
+ patent claims licensable by such Contributor that are necessarily infringed by
78
+ their Contribution(s) alone or by combination of their Contribution(s) with
79
+ the Work to which such Contribution(s) was submitted. If You institute patent
80
+ litigation against any entity (including a cross-claim or counterclaim in a
81
+ lawsuit) alleging that the Work or a Contribution incorporated within the Work
82
+ constitutes direct or contributory patent infringement, then any patent
83
+ licenses granted to You under this License for that Work shall terminate as of
84
+ the date such litigation is filed.
85
+
86
+ 4. Redistribution. You may reproduce and distribute copies of the Work or
87
+ Derivative Works thereof in any medium, with or without modifications, and in
88
+ Source or Object form, provided that You meet the following conditions:
89
+
90
+ You must give any other recipients of the Work or Derivative Works a copy of
91
+ this License; and
92
+
93
+ You must cause any modified files to carry prominent notices stating that You
94
+ changed the files; and
95
+
96
+ You must retain, in the Source form of any Derivative Works that You
97
+ distribute, all copyright, patent, trademark, and attribution notices from the
98
+ Source form of the Work, excluding those notices that do not pertain to any
99
+ part of the Derivative Works; and
100
+
101
+ If the Work includes a "NOTICE" text file as part of its distribution, then
102
+ any Derivative Works that You distribute must include a readable copy of the
103
+ attribution notices contained within such NOTICE file, excluding those notices
104
+ that do not pertain to any part of the Derivative Works, in at least one of
105
+ the following places: within a NOTICE text file distributed as part of the
106
+ Derivative Works; within the Source form or documentation, if provided along
107
+ with the Derivative Works; or, within a display generated by the Derivative
108
+ Works, if and wherever such third-party notices normally appear. The contents
109
+ of the NOTICE file are for informational purposes only and do not modify the
110
+ License. You may add Your own attribution notices within Derivative Works that
111
+ You distribute, alongside or as an addendum to the NOTICE text from the Work,
112
+ provided that such additional attribution notices cannot be construed as
113
+ modifying the License. You may add Your own copyright statement to Your
114
+ modifications and may provide additional or different license terms and
115
+ conditions for use, reproduction, or distribution of Your modifications, or
116
+ for any such Derivative Works as a whole, provided Your use, reproduction, and
117
+ distribution of the Work otherwise complies with the conditions stated in this
118
+ License.
119
+
120
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any
121
+ Contribution intentionally submitted for inclusion in the Work by You to the
122
+ Licensor shall be under the terms and conditions of this License, without any
123
+ additional terms or conditions. Notwithstanding the above, nothing herein
124
+ shall supersede or modify the terms of any separate license agreement you may
125
+ have executed with Licensor regarding such Contributions.
126
+
127
+ 6. Trademarks. This License does not grant permission to use the trade names,
128
+ trademarks, service marks, or product names of the Licensor, except as
129
+ required for reasonable and customary use in describing the origin of the Work
130
+ and reproducing the content of the NOTICE file.
131
+
132
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in
133
+ writing, Licensor provides the Work (and each Contributor provides its
134
+ Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
135
+ KIND, either express or implied, including, without limitation, any warranties
136
+ or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
137
+ PARTICULAR PURPOSE. You are solely responsible for determining the
138
+ appropriateness of using or redistributing the Work and assume any risks
139
+ associated with Your exercise of permissions under this License.
140
+
141
+ 8. Limitation of Liability. In no event and under no legal theory, whether in
142
+ tort (including negligence), contract, or otherwise, unless required by
143
+ applicable law (such as deliberate and grossly negligent acts) or agreed to in
144
+ writing, shall any Contributor be liable to You for damages, including any
145
+ direct, indirect, special, incidental, or consequential damages of any
146
+ character arising as a result of this License or out of the use or inability
147
+ to use the Work (including but not limited to damages for loss of goodwill,
148
+ work stoppage, computer failure or malfunction, or any and all other
149
+ commercial damages or losses), even if such Contributor has been advised of
150
+ the possibility of such damages.
151
+
152
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work
153
+ or Derivative Works thereof, You may choose to offer, and charge a fee for,
154
+ acceptance of support, warranty, indemnity, or other liability obligations
155
+ and/or rights consistent with this License. However, in accepting such
156
+ obligations, You may act only on Your own behalf and on Your sole
157
+ responsibility, not on behalf of any other Contributor, and only if You agree
158
+ to indemnify, defend, and hold each Contributor harmless for any liability
159
+ incurred by, or claims asserted against, such Contributor by reason of your
160
+ accepting any such warranty or additional liability.
data/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # pagerduty-tools #
2
+
3
+ Tools to work around limitations in the [PagerDuty](http://www.pagerduty.com)
4
+ [API](http://www.pagerduty.com/docs/api/api-documentation). As an example use,
5
+ here are two Campfire updates from these scripts that set the room topic to
6
+ the current on-call rotation, and then report on the incidents and alerts from
7
+ the previous rotation:
8
+
9
+ ![campfire example](https://github.com/precipice/pagerduty_tools/raw/master/images/campfire-example.png)
10
+
11
+ ## IMPORTANT: Status ##
12
+
13
+ Several changes to PagerDuty's site have broken parts of these tools. I'm
14
+ currently working on repairing them and on making the tools into a gem. Status
15
+ as of this writing is that the `bin/pagerduty_oncall.rb` script is working and
16
+ the others are not. The gem builds and installs.
17
+
18
+ ## Installing ##
19
+
20
+ Ruby 1.8.7 or later is required.
21
+
22
+ First, clone the GitHub repo:
23
+
24
+ $ git clone git://github.com/precipice/pagerduty-tools.git
25
+
26
+ If you don't already have [Bundler](http://gembundler.com/) installed, do that
27
+ now:
28
+
29
+ $ gem install bundler
30
+
31
+ Then install required gems via Bundler:
32
+
33
+ $ bundle install
34
+
35
+ The scripts log into the PagerDuty site when first run. Your email address
36
+ will be used to find associated PagerDuty accounts, and you can choose the
37
+ account you want to report on. After the first run, a login cookie is kept in
38
+ `~/.pagerduty-cookies` to allow future runs to be automatic (e.g., from cron).
39
+
40
+ ## Campfire Support ##
41
+
42
+ If you would like to have PagerDuty reports sent to your
43
+ [Campfire](http://www.campfirenow.com) room, create a "PagerDuty" user in your
44
+ Campfire account, and then add a configuration file at
45
+ `~/.pagerduty-campfire.yaml` containing the following:
46
+
47
+ site: https://example.campfirenow.com
48
+ room: 99999
49
+ token: abababababababababababababababababababab
50
+
51
+ with the values changed to match your configuration. I'd recommend running:
52
+
53
+ $ chmod 0600 ~/.pagerduty-campfire.yaml
54
+
55
+ after creating the file. See the documentation for each script for how to send
56
+ output to Campfire.
57
+
58
+ Tip: you can use [PagerDuty's Twitter icon](https://twitter.com/pagerduty) as
59
+ a profile icon for your Campfire PagerDuty account. This isn't necessary, but
60
+ it makes the PagerDuty message more recognizable and nicer.
61
+
62
+ ## Limitations ##
63
+
64
+ * The rotation-report.rb script works well for weekly rotations with no
65
+ exceptions set. It might work well for daily rotations (comparing to the
66
+ same day one week ago), but hasn't been tested for that; and it fails
67
+ completely if any of the weeks compared have an exception set. If you set
68
+ an exception, you can work around this limitation using the `--start-time`
69
+ and `--end-time` options to explicitly set the report date range.
70
+ * Login and other errors from PagerDuty's site are not parsed or reported.
71
+
72
+ # oncall.rb #
73
+
74
+ The `oncall.rb` script reports who is currently on call for your PagerDuty
75
+ account. Invoked with no arguments, it will list all on-call levels (1..n). If
76
+ one or more levels are given as arguments, it will only list those levels.
77
+
78
+ If the on call level has an associated on-call rotation, the name of that
79
+ rotation is used in the output. Otherwise, a generic `Level <#>` format is
80
+ used.
81
+
82
+ You can invoke oncall.rb with a `-t` or `--campfire-topic` option, and the
83
+ output of the script will be set as the topic for the configured room (see
84
+ __Campfire Support__, above). We do this out of cron right after the rotation
85
+ turns over to a new assignment.
86
+
87
+ oncall.rb defaults to showing the first escalation policy, but if you have
88
+ multiple ones and want to show a specific one, you can invoke it with `-p` or
89
+ `--policy` to specify which one to use.
90
+
91
+ Calling the script with `-h` or `--help` will display some help.
92
+
93
+ ## Examples ##
94
+
95
+ $ ./oncall.rb
96
+ Hotseat: John Henry, Hotseat Backup: Lisa Limon, Level 3: Steven Sanders
97
+
98
+ $ ./oncall.rb 1 2
99
+ Hotseat: John Henry, Hotseat Backup: Lisa Limon
100
+
101
+ $ ./oncall.rb --campfire-topic 1 2
102
+ [No shell output, but the configured Campfire room's topic becomes:
103
+ "Hotseat: John Henry, Hotseat Backup: Lisa Limon"]
104
+
105
+ # rotation-report.rb #
106
+
107
+ The `rotation-report.rb` script generates an automatic "end of shift" report
108
+ to show what happened over the course of a rotation. It measures how many
109
+ incidents occurred, shows who resolved them, and shows how many alerts people
110
+ got (including a breakout of after-midnight alerts, which we all must strive
111
+ to eradicate!). Also, it lists the top five causes for alerts during the
112
+ rotation, and compares the counts to the same period one week earlier.
113
+
114
+ Here's an example:
115
+
116
+ Rotation report for February 23 - March 02:
117
+ 19 incidents (-9% vs. last week)
118
+
119
+ Resolutions:
120
+ John Henry: 8, George Harrison: 4, Scott Brinkley: 4, Jason Neeson: 2, [Automatic]: 1
121
+
122
+ SMS/Phone Alerts (62 total, +77% vs. last week; 6 after midnight, -53% vs. last week):
123
+ John Henry: 44, George Harrison: 10, Jason Neeson: 4, Scott Brinkley: 4
124
+
125
+ Top triggers:
126
+ 6 'Pingdom: DOWN alert: example-health (www.example.com) is DOWN' (-14% vs. last week)
127
+ 5 'Pingdom: DOWN alert: sg-health (sg.example.com) is DOWN' (no occurrences last week)
128
+ 4 'Nagios: vip-api - check_api_lag' (+300% vs. last week)
129
+ 1 'Nagios: vip-redisapi - check_live_redis_lag' (-66% vs. last week)
130
+ 1 'Pingdom: DOWN alert: client-nike (www.nike.com) is DOWN' (no occurrences last week)
131
+
132
+ By default the script will report on the most recently-completed rotation.
133
+ However, you can use the `-a`|`--rotations-ago COUNT` option to specify how
134
+ far back in history you want to go. Or, you can use `-s`|`--start-time DATETIME`
135
+ and `-e`|`--end-time DATETIME` (giving the date in
136
+ [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations)
137
+ date and time format, e.g. "2011-03-02T14:00:00-05:00") to set a specific range
138
+ for the report.
139
+
140
+ Calling rotation-report.rb with a `-m`|`--campfire-message` argument will
141
+ cause the rotation report to be pasted into the configured Campfire room. (See
142
+ __Campfire Support__, above, for information about setting this up.)
143
+
144
+ Calling the script with `-h` or `--help` will display some help.
145
+
146
+ # alerts-by-day.rb #
147
+
148
+ This script is being revised and doesn't work with the rest of the package yet.
149
+
150
+ # Contributions #
151
+
152
+ Pull requests welcome. There are no tests or specs yet, so hey, contributing
153
+ couldn't be easier.
154
+
155
+ Thanks to the following people for contributions!
156
+
157
+ * [Jeffrey Wescott](https://github.com/binaryfeed)
158
+ * [André Arko](https://github.com/indirect)
159
+ * [Brian Donovan](https://github.com/eventualbuddha)
160
+ * [Brad Greenlee](https://github.com/bgreenlee)
161
+
162
+ # License #
163
+
164
+ Copyright 2011 Marc Hedlund. Distributed under the Apache License, version 2.0.
165
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright 2011 Marc Hedlund <marc@precipice.org>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # oncall-email.rb -- Notify on-call people about shift start.
18
+ #
19
+ # Original script contributed by Jeffrey Wescott
20
+ # (https://github.com/binaryfeed). Thanks!
21
+
22
+ require 'rubygems'
23
+ require 'bundler/setup'
24
+ require 'net/smtp'
25
+
26
+ require 'optparse'
27
+
28
+ lib = File.expand_path(File.join(File.dirname(__FILE__), '../lib'))
29
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
30
+
31
+ require 'pagerduty_tools'
32
+
33
+ # Look for reporting options
34
+ options = {}
35
+
36
+ optparse = OptionParser.new do |opts|
37
+ opts.banner = "Usage: oncall-email.rb\n" +
38
+ "Send an email reminder to the on-call person (and any relevant CCs)."
39
+
40
+ options[:smtp_server] = 'localhost'
41
+ opts.on( '-m', '--smtp-server HOSTNAME', 'Use HOSTNAME as the SMTP server.') do |host|
42
+ options[:smtp_server] = host
43
+ end
44
+
45
+ options[:subject] = '[PagerDuty] You are now on call'
46
+ opts.on( '-s', '--subject SUBJECT', 'Use SUBJECT as the subject line of the email.') do |subject|
47
+ options[:subject] = subject
48
+ end
49
+
50
+ options[:from_address] = 'nobody@example.com'
51
+ opts.on( '-f', '--from ADDRESS', 'Use ADDERSS as the "From:" line of the email.') do |from|
52
+ options[:from_address] = from
53
+ end
54
+
55
+ # REVIEW: Should this be an ARRAY option?
56
+ options[:ccs] = []
57
+ opts.on( '-c', '--cc EMAIL', 'Send a copy of the email to EMAIL.' ) do |cc|
58
+ options[:ccs] << cc
59
+ end
60
+
61
+ options[:message_file] = nil
62
+ opts.on( '-m', '--message-file FILENAME', 'Use contents of FILENAME as the email body.') do |filename|
63
+ options[:message_file] = filename
64
+ end
65
+
66
+ opts.on( '-p', '--policy POLICY', 'Set the Escalation Policy to display') do |policy|
67
+ options[:policy] = policy
68
+ end
69
+
70
+ opts.on( '-h', '--help', 'Display this message' ) do
71
+ puts opts
72
+ exit
73
+ end
74
+ end
75
+
76
+ optparse.parse!
77
+
78
+ # Default to sending mail to the first-level assignee only, or use levels
79
+ # given as arguments.
80
+ mail_to_levels = ARGV.count > 0 ? ARGV : "1"
81
+
82
+ # Log into PagerDuty and get the Dashboard page.
83
+ pagerduty = PagerDuty::Agent.new
84
+ escalation = PagerDuty::Escalation.new mail_to_levels, options[:policy]
85
+
86
+ # REVIEW: don't we need one Person per level? What's this for?
87
+ person = PagerDuty::Person.new
88
+
89
+ # Log into PagerDuty and get the on-call info block.
90
+ oncall_info = pagerduty.fetch "/on_call_info"
91
+ levels = escalation.parse oncall_info.body
92
+
93
+
94
+ # Get the email address for each on-call level.
95
+ levels.each do |level|
96
+ user = pagerduty.fetch level['person_path']
97
+ person.parse user.body
98
+ level['email'] = person.email
99
+ end
100
+
101
+ # REVIEW: Is the 'recips' line needed? Can Net::SMTP pull addresses from the header?
102
+ recips = options[:ccs] + (levels.map { |level| level['email'] })
103
+ to_line = levels.map{|level| "#{level['person']} <#{level['email']}>" }.join(", ")
104
+ cc_line = options[:ccs].join(", ")
105
+
106
+ header = <<HEADER_END
107
+ From: PagerDuty <#{options[:from_address]}>
108
+ To: #{to_line}
109
+ CC: #{cc_line}
110
+ Subject: #{options[:subject]}
111
+
112
+ HEADER_END
113
+
114
+ # REVIEW: Hmm...wonder if the email should be different for each person, telling
115
+ # them what level assignment they have now.
116
+
117
+ # REVIEW: Should show the full assignment list as a table.
118
+
119
+ body = <<BODY_END
120
+ Your PagerDuty on-call rotation has started. If you receive alerts about new
121
+ incidents, please acknowledge them as soon as possible if you can respond. If
122
+ not, please escalate them to the next level so they can be handled quickly.
123
+ For more information about an alert, please log into our PagerDuty account at:
124
+
125
+ https://#{pagerduty.domain}
126
+
127
+ Thanks.
128
+ BODY_END
129
+
130
+ if options[:message_file] != nil
131
+ body = ""
132
+ File.open(options[:message_file], "r") do |file|
133
+ file.each_line do |line|
134
+ body += line
135
+ end
136
+ end
137
+ end
138
+
139
+ Net::SMTP.start(options[:smtp_server]) do |smtp|
140
+ smtp.send_message header + body, options[:from_address], recips
141
+ end
142
+
143
+ exit(0)