pager_duty-connection 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ .env.development
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pager_duty-connection.gemspec
4
+ gemspec
5
+
6
+ # for tests & running examples
7
+ group :development do
8
+ gem 'dotenv'
9
+ gem 'pry'
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Josh Nichols
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # PagerDuty::Connection
2
+
3
+ PagerDuty::Connection is a Ruby wrapper for the [PagerDuty REST API](http://developer.pagerduty.com/documentation/rest)
4
+
5
+ It has a few design goals:
6
+
7
+ * be usable to someone familiar with Ruby
8
+ * be usable to someone familiar with the PagerDuty REST API, or at least able to read the documentation
9
+ * try to be future proof for API additions
10
+ * try not to do too much magic, in order to support the above
11
+
12
+ In the end, this is what it does:
13
+
14
+ * provides methods for each of the HTTP methods you can use on the API, that takes a path (like if you copied from the documentation), and a Hash of request parameters to send
15
+ * provide a simpler way to do pagination (pass `:page => ` to `get`), because using `limit` and `offset` using as [described by the API](http://developer.pagerduty.com/documentation/rest/pagination) is tedious in practice
16
+ * converts time-like strings in responses to `Time` objects, since that is what most people will do anyways
17
+ * converts time-like objects in requests to ISO 8601 strings, as this is documented as required by the API but is easy to forget and tedious to do anytime you use time parameters (ie `since` and `until`)
18
+ * detect 404 errors, and raise them as `PagerDuty::Connection::FileNotFoundError` errors
19
+ * detect [API errors](http://developer.pagerduty.com/documentation/rest/errors) and raise them as `PagerDuty::Connection::ApiError`
20
+
21
+ And this is what it doesn't do:
22
+
23
+ * provide first class objects for Incidents, Services, etc (they can change, and have new methods)
24
+ * provide an a ActiveResource interface (ActiveResource libraries can be hard to built wrappers for. Also, it's not conducive to accessing multiple pagerduty accounts)
25
+ * have methods for individual API calls that are possible (ie `find_incident`, `list_users`, etc)
26
+ * provide [will_paginate](https://github.com/mislav/will_paginate) or [kaminari](https://github.com/amatsuda/kaminari) paginated arrays (They aren't super documented for building a library that works well with them, and have different APIs)
27
+
28
+ ## Installation
29
+
30
+ Add this line to your application's Gemfile:
31
+
32
+ gem 'pager_duty-connection'
33
+
34
+ And then execute:
35
+
36
+ $ bundle
37
+
38
+ Or install it yourself as:
39
+
40
+ $ gem install pager_duty-connection
41
+
42
+ ## Usage
43
+
44
+
45
+ Working code is worth a thousand words. The basics:
46
+
47
+ `` ruby
48
+ # setup the connection
49
+ pagerduty = PagerDuty::Connection.new(account, token)
50
+
51
+ # 4 main methods: get, post, put, and delete:
52
+
53
+ response = pagerduty.get('some/relative/path', :some => 'request', :parameter => 'to pass'
54
+ response = pagerduty.post('some/relative/path', :some => 'request', :parameter => 'to pass'
55
+ response = pagerduty.delete('some/relative/path', :some => 'request', :parameter => 'to pass'
56
+ response = pagerduty.put('some/relative/path', :some => 'request', :parameter => 'to pass'
57
+
58
+ # use something like irb or pry to poke around the responses
59
+ # the contents will vary a bit between call, ie:
60
+
61
+ response = pagerduty.get('incidents')
62
+ response.incidents # an array of incidents
63
+
64
+ response = pagerduty.get('incidents/YYZ')
65
+ response # the hash/object that represents the array
66
+ ``
67
+
68
+ For more advanced and realistic examples, check out the examples directory:
69
+
70
+ * [shifts-with-incidents-and-log-entries](examples/shifts-with-incidents-and-log-entries.rb)
71
+ * [find-users](examples/find-users.rb)
72
+
73
+ In general, you can get/put/post/delete a path, with some attributes. Use the [REST API Documentation](http://developer.pagerduty.com/documentation/rest) to get some ideas
74
+
75
+ If you are working in Rails, and using only a single PagerDuty account, you'll probably want an initializer:
76
+
77
+ ``ruby
78
+ $pagerduty = PagerDuty::Connection.new('your-subdomain', 'your-token')
79
+ ``
80
+
81
+ And if you are using [dotenv](https://github.com/bkeepers/dotenv), you can use environment variables, and stash them in .env:
82
+
83
+ ``ruby
84
+ account = ENV['PAGERDUTY_ACCOUNT'] || raise("Missing ENV['PAGERDUTY_ACCOUNT'], add to .env")
85
+ token = ENV['PAGERDUTY_TOKEN'] || raise("Missing ENV['PAGERDUTY_TOKEN'], add to .env.#{Rails.env}")
86
+ $pagerduty = PagerDuty::Connection.new(account, token)
87
+ ``
88
+
89
+ ## Questions and Answers
90
+
91
+ > What about the [pagerduty](https://github.com/envato/pagerduty) gem?
92
+
93
+ That is only for PagerDuty's [Integration API](http://developer.pagerduty.com/documentation/integration/events), ie for triggering/acknowleding/resolinv incidents
94
+
95
+ > What about the [pagerduty-full](https://github.com/gphat/pagerduty-full) gem?
96
+
97
+ It tries to be too clever and tightly models the API. For exampe, by having only Incident & Schedule classes, with specific methods for doing specific API calls, it means having to update the gem anytime new resources are added, and new API methods.
98
+
99
+ > What about [pagerduty_tools](https://github.com/precipice/pagerduty_tools)
100
+
101
+ That gem is less about being an API, and more about tools for being on call. Also, it took months for [my pull request to be reviewed](https://github.com/precipice/pagerduty_tools/pull/6), so didn't give me a lot of hope for changes making it in.
102
+
103
+ > Why not name it pagerduty-rest?
104
+
105
+ That would suggest a constant like Pagerduty::Rest, which I didn't like
106
+
107
+ > Why not name it pagerduty-connection?
108
+
109
+ That would suggest a constant like Pagerduty::Connection
110
+
111
+ ## Contributing
112
+
113
+ 1. Fork it
114
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
115
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
116
+ 4. Push to the branch (`git push origin my-new-feature`)
117
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pry'
4
+ require 'dotenv'
5
+ Dotenv.load ".env.development", '.env'
6
+
7
+ account = ENV['PAGERDUTY_ACCOUNT'] || raise("Missing ENV['PAGERDUTY_ACCOUNT'], add to .env.development")
8
+ token = ENV['PAGERDUTY_TOKEN'] || raise("Missing ENV['PAGERDUTY_TOKEN'], add to .env.development")
9
+
10
+ require 'pager_duty/connection'
11
+ $pagerduty = PagerDuty::Connection.new(account, token)
12
+
13
+ # http://developer.pagerduty.com/documentation/rest/users/list
14
+ response = $pagerduty.get('users')
15
+ response.users.each do |user|
16
+ puts "#{user.name}: #{user.email}"
17
+ end
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'dotenv'
4
+ Dotenv.load ".env.development", '.env'
5
+
6
+ account = ENV['PAGERDUTY_ACCOUNT'] || raise("Missing ENV['PAGERDUTY_ACCOUNT'], add to .env.development")
7
+ token = ENV['PAGERDUTY_TOKEN'] || raise("Missing ENV['PAGERDUTY_TOKEN'], add to .env.development")
8
+
9
+ require 'pager_duty/connection'
10
+ $pagerduty = PagerDuty::Connection.new(account, token)
11
+
12
+ schedule_id = ENV['PAGERDUTY_SCHEDULE_ID'] || raise("Missing ENV['PAGERDUTY_SCHEDULE_ID'], add to .env.development")
13
+
14
+ # pull down schedule entires for XXX schedule in the last day (ie who has been on call, and when
15
+ time_since = 1.day.ago
16
+ time_until = Time.now
17
+
18
+ # http://developer.pagerduty.com/documentation/rest/schedules/entries
19
+ response = $pagerduty.get("schedules/#{schedule_id}/entries", 'since' => time_since, 'until' => time_until, :overflow => true)
20
+
21
+ entries = response['entries'] # note, probably a bug, but response.entries doesn't do what you think it does
22
+
23
+ entries.each do |entry|
24
+ puts "#{entry.start} - #{entry.end}: #{entry.user.name}"
25
+
26
+ # find incidents during that shift
27
+ # http://developer.pagerduty.com/documentation/rest/incidents/list
28
+ response = $pagerduty.get('incidents', :since => entry['start'], :until => entry['end'])
29
+
30
+ response.incidents.each do |incident|
31
+ puts "\t#{incident.id}"
32
+
33
+ # find log entries (acknowledged, notifications, etc) for incident:
34
+ # http://developer.pagerduty.com/documentation/rest/log_entries/incident_log_entries
35
+ response = $pagerduty.get("incidents/#{incident.id}/log_entries")
36
+
37
+ # select just the notes
38
+ notes = response.log_entries.select do |log_entry|
39
+ log_entry.channel && log_entry.channel.type == 'note'
40
+ end
41
+
42
+ # and print them out:
43
+ notes.each do |log_entry|
44
+ puts "\t\t#{log_entry.channel.summary}"
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,2 @@
1
+ # convenience require for folks using bundler
2
+ require "pager_duty/connection"
data/lib/pager_duty.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'pager_duty/connection/version'
2
+
3
+ module PagerDuty
4
+ autoload :Connection, 'pager_duty/connection'
5
+ end
6
+
@@ -0,0 +1,151 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'active_support/core_ext'
4
+ require 'active_support/time_with_zone'
5
+
6
+ module PagerDuty
7
+
8
+ class Connection
9
+ attr_accessor :connection
10
+ attr_accessor :api_version
11
+
12
+ class FileNotFoundError < RuntimeError
13
+ end
14
+
15
+ class ApiError < RuntimeError
16
+ end
17
+
18
+ class RaiseFileNotFoundOn404 < Faraday::Middleware
19
+ def call(env)
20
+ response = @app.call env
21
+ if response.status == 404
22
+ raise FileNotFoundError, response.env[:url].to_s
23
+ else
24
+ response
25
+ end
26
+ end
27
+ end
28
+
29
+ class RaiseApiErrorOnNon200 < Faraday::Middleware
30
+ def call(env)
31
+ response = @app.call env
32
+ if response.status != 200
33
+ url = response.env[:url].to_s
34
+ if error = response.body['error']
35
+ # TODO May Need to check error.errors too
36
+ raise ApiError, "Got HTTP #{response.status} back for #{url}. Error code #{error.code}: #{error.message}"
37
+ else
38
+ raise ApiError, "Got HTTP #{response.status} back for #{url}"
39
+ end
40
+ else
41
+ response
42
+ end
43
+ end
44
+ end
45
+
46
+ class ConvertTimesParametersToISO8601 < Faraday::Middleware
47
+ TIME_KEYS = [:since, :until]
48
+ def call(env)
49
+
50
+ body = env[:body]
51
+ TIME_KEYS.each do |key|
52
+ if body.has_key?(key)
53
+ body[key] = body[key].iso8601 if body[key].respond_to?(:iso8601)
54
+ end
55
+ end
56
+
57
+ response = @app.call env
58
+ end
59
+
60
+
61
+ end
62
+
63
+ class ParseTimeStrings < Faraday::Middleware
64
+ TIME_KEYS = %w(start end created_on last_status_change_on started_at created_at last_incident_timestamp)
65
+
66
+ OBJECT_KEYS = %w(override entry incident alert service)
67
+
68
+ def call(env)
69
+ response = @app.call env
70
+
71
+ OBJECT_KEYS.each do |key|
72
+ object = env[:body][key]
73
+ parse_object_times(object) if object
74
+
75
+ collection_key = key.pluralize
76
+ collection = env[:body][collection_key]
77
+ parse_collection_times(collection) if collection
78
+ end
79
+
80
+ response
81
+ end
82
+
83
+ def parse_collection_times(collection)
84
+ collection.each do |object|
85
+ parse_object_times(object)
86
+ end
87
+ end
88
+
89
+ def parse_object_times(object)
90
+ time = Time.zone ? Time.zone : Time
91
+
92
+ TIME_KEYS.each do |key|
93
+ object[key] = time.parse(object[key]) if object.has_key?(key)
94
+ end
95
+ end
96
+ end
97
+
98
+ def initialize(account, token, api_version = 1)
99
+ @api_version = api_version
100
+ @connection = Faraday.new do |conn|
101
+ conn.url_prefix = "https://#{account}.pagerduty.com/api/v#{api_version}"
102
+
103
+ # use token authentication: http://developer.pagerduty.com/documentation/rest/authentication
104
+ conn.token_auth token
105
+
106
+
107
+ conn.use ParseTimeStrings
108
+ conn.use RaiseApiErrorOnNon200
109
+ # json back, mashify it
110
+ conn.response :mashify
111
+ conn.response :json, :content_type => /\bjson$/
112
+ conn.use RaiseFileNotFoundOn404
113
+
114
+ conn.use ConvertTimesParametersToISO8601
115
+ # use json
116
+ conn.request :json
117
+
118
+ conn.adapter Faraday.default_adapter
119
+ end
120
+ end
121
+
122
+ def get(path, options = {})
123
+ # paginate anything being 'get'ed, because the offset/limit isn't intutive
124
+ page = (options.delete(:page) || 1).to_i
125
+ limit = (options.delete(:limit) || 100).to_i
126
+ offset = (page - 1) * limit
127
+
128
+ run_request(:get, path, options.merge(:offset => offset, :limit => limit))
129
+ end
130
+
131
+ def put(path, options = {})
132
+ run_request(:put, path, options)
133
+ end
134
+
135
+ def post(path, options = {})
136
+ run_request(:put, path, options)
137
+ end
138
+
139
+ def delete(path, options = {})
140
+ run_request(:delete, path, options)
141
+ end
142
+
143
+ def run_request(method, path, options)
144
+ path = path.gsub(/^\//, '') # strip leading slash, to make sure relative things happen on the connection
145
+ headers = nil
146
+ response = connection.run_request(method, path, options, headers)
147
+ response.body
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,5 @@
1
+ module PagerDuty
2
+ class Connection
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pager_duty/connection/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "pager_duty-connection"
8
+ gem.version = PagerDuty::Connection::VERSION
9
+ gem.authors = ["Josh Nichols"]
10
+ gem.email = ["josh@technicalpickles.com"]
11
+ gem.description = %q{Ruby API wrapper for the PagerDuty REST API}
12
+ gem.summary = %q{Written with the power of faraday, pager_duty-connection tries to be a simple and usable Ruby API wrapper for the PagerDuty REST API}
13
+ gem.homepage = "http://github.com/technicalpickles/pager_duty-connection"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "faraday", "~> 0.8.6"
21
+ gem.add_dependency "faraday_middleware", "~> 0.9.0"
22
+ gem.add_dependency "activesupport", "~> 3.2"
23
+ gem.add_dependency "hashie", "~> 1.2"
24
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pager_duty-connection
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh Nichols
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faraday
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.8.6
30
+ - !ruby/object:Gem::Dependency
31
+ name: faraday_middleware
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: activesupport
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '3.2'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
62
+ - !ruby/object:Gem::Dependency
63
+ name: hashie
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.2'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.2'
78
+ description: Ruby API wrapper for the PagerDuty REST API
79
+ email:
80
+ - josh@technicalpickles.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - examples/find-users.rb
91
+ - examples/shifts-with-incidents-and-log-entries.rb
92
+ - lib/pager_duty-connection.rb
93
+ - lib/pager_duty.rb
94
+ - lib/pager_duty/connection.rb
95
+ - lib/pager_duty/connection/version.rb
96
+ - pager_duty-connection.gemspec
97
+ homepage: http://github.com/technicalpickles/pager_duty-connection
98
+ licenses: []
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.23
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Written with the power of faraday, pager_duty-connection tries to be a simple
121
+ and usable Ruby API wrapper for the PagerDuty REST API
122
+ test_files: []
123
+ has_rdoc: