runscope_statuspage 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +62 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/runscope_statuspage/exceptions.rb +13 -0
- data/lib/runscope_statuspage/runscope_api.rb +64 -0
- data/lib/runscope_statuspage/statuspage_api.rb +40 -0
- data/lib/runscope_statuspage/version.rb +3 -0
- data/lib/runscope_statuspage.rb +132 -0
- data/runscope_statuspage.gemspec +22 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: eb62c439ebb1ba9cc983e980d9d33e4a6494ebb9
|
4
|
+
data.tar.gz: 1e9f6d9ab1e33eda9c2bb5cd195c85c277eeb072
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9d9a8fe2c762af150c9f91b1688b0cba48fa5f11f86b755121e0ddd9671473fa3989e855f2d8415b0f7a7328769161b0d6d9dbd3989df9ebcbda357297455c60
|
7
|
+
data.tar.gz: 78b77b820f0abb1531521a7350d400ec3a1f10516ae49e86ac5e3abefe80a770b1fbb3197fa28d0945a651b56a3ecf0dee6c2dd7ea587b96e20dd07eae3feeb7
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 David Stancu
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# RunscopeStatuspage
|
2
|
+
|
3
|
+
Do you use [RunScope](https://runscope.com) to test your API, and [StatusPage](https://statuspage.io) to show it all off to your customers? Don't want to write bindings for both APIs? If yes, RunscopeStatuspage is perfect for you.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'runscope_statuspage'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install runscope_statuspage
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
In a nutshell, each call will grab metrics from RunScope then send them over to StatusPage, once per call. There is no scheduling done by this gem, it is left as an exercise for the reader. Ideally, you will want to use something such as [Sidekiq](https://github.com/mperham/sidekiq) or [Resque](https://github.com/resque/resque) to fire these jobs off every few minutes/hours. Keep in mind that StatusPage will rate-limit requests to its API, one request per minute.
|
24
|
+
|
25
|
+
### You can...
|
26
|
+
|
27
|
+
* from general to specific *
|
28
|
+
|
29
|
+
- report_everything(page, status, twitter_update)
|
30
|
+
- report_buckets(bucket_names, status, twitter_update)
|
31
|
+
- report_bucket(bucket_name, status, twitter_update)
|
32
|
+
- report_radars(bucket_name, radar_names, status, twitter_update)
|
33
|
+
- report_radar(bucket_name, radar_name, status, twitter_update)
|
34
|
+
|
35
|
+
#### Important Notes
|
36
|
+
|
37
|
+
- `status` must be either `investigating|identified|monitoring|resolved`.
|
38
|
+
- RunScope likes to throw ISEs if you specify invalid IDs or names, just keep this in mind.
|
39
|
+
|
40
|
+
#### I want bindings!
|
41
|
+
|
42
|
+
Have them! `RunscopeStatuspage::RunscopeAPI` and `RunscopeStatuspage::StatuspageAPI` contain partial coverage of each service's API.
|
43
|
+
|
44
|
+
### Glossary
|
45
|
+
|
46
|
+
- bucket: A group of radars/tests.
|
47
|
+
- radar: A test with one or more assertions.
|
48
|
+
- twitter_update parameter: StatusPage can spit incidents out to Twitter, this is a toggle for this functionality.
|
49
|
+
|
50
|
+
## Development
|
51
|
+
|
52
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
53
|
+
|
54
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
55
|
+
|
56
|
+
## Contributing
|
57
|
+
|
58
|
+
1. Fork it ( https://github.com/[my-github-username]/runscope_statuspage/fork )
|
59
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
60
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
61
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
62
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "runscope_statuspage"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative 'exceptions'
|
2
|
+
require 'httparty'
|
3
|
+
|
4
|
+
module RunscopeStatuspage
|
5
|
+
|
6
|
+
class RunscopeAPI
|
7
|
+
include HTTParty
|
8
|
+
base_uri 'https://api.runscope.com'
|
9
|
+
|
10
|
+
# Set credentials
|
11
|
+
def initialize(token)
|
12
|
+
@options = { headers: {:Authorization => "Bearer #{token}"} }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get list of buckets
|
16
|
+
def buckets
|
17
|
+
buckets = self.class.get('/buckets', @options)
|
18
|
+
if buckets.has_key?('meta') and buckets.has_key?('data')
|
19
|
+
if buckets['meta']['status'] == 'success'
|
20
|
+
buckets['data']
|
21
|
+
else
|
22
|
+
raise RunscopeAPIException.new, buckets['error']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get list of radars for bucket
|
28
|
+
def radars(bucket)
|
29
|
+
radars = self.class.get("/buckets/#{bucket}/radar", @options)
|
30
|
+
if radars.has_key?('meta') and radars.has_key?('data')
|
31
|
+
if radars['meta']['status'] == 'success'
|
32
|
+
radars['data']
|
33
|
+
else
|
34
|
+
raise RunscopeAPIException.new, radars['error']
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get a radar, from a bucket.
|
40
|
+
def get_radar(bucket, radar)
|
41
|
+
get_radar = self.class.get("/buckets/#{bucket}/radar/#{radar}", @options)
|
42
|
+
if get_radar.has_key?('meta') and get_radar.has_key?('data')
|
43
|
+
if get_radar['meta']['status'] == 'success'
|
44
|
+
get_radar['data']
|
45
|
+
else
|
46
|
+
raise RunscopeAPIException.new, get_radar['error']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get latest result from radar
|
52
|
+
def latest_radar_result(bucket, radar)
|
53
|
+
lrr = self.class.get("/buckets/#{bucket}/radar/#{radar}/results/latest", @options)
|
54
|
+
if lrr.has_key?('meta') and lrr.has_key?('data')
|
55
|
+
if lrr['meta']['status'] == 'success'
|
56
|
+
lrr['data']
|
57
|
+
else
|
58
|
+
raise RunscopeAPIException.new, lrr['error']
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative 'exceptions'
|
2
|
+
require 'httparty'
|
3
|
+
|
4
|
+
module RunscopeStatuspage
|
5
|
+
|
6
|
+
class StatuspageAPI
|
7
|
+
include HTTParty
|
8
|
+
base_uri 'https://api.statuspage.io/v1'
|
9
|
+
|
10
|
+
# Set credentials
|
11
|
+
def initialize(token)
|
12
|
+
@options = { headers: {:Authorization => "OAuth #{token}"} }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create incident
|
16
|
+
def create_realtime_incident(page, name, msg, status, twitter)
|
17
|
+
self.class.post("/pages/#{page}/incidents.json", @options.merge!(body: {:incident => {
|
18
|
+
:name => name,
|
19
|
+
:message => msg,
|
20
|
+
:status => status.nil? ? 'investigating' : status,
|
21
|
+
:wants_twitter_update => twitter
|
22
|
+
}}))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Publish data for a custom page metric
|
26
|
+
def push_metric_data(page_id, metric_id, data, timestamp)
|
27
|
+
self.class.post("/pages/#{page_id}/metrics/#{metric_id}/data.json", @options.merge!(data: {:data => {
|
28
|
+
:value => data,
|
29
|
+
:timestamp => timestamp
|
30
|
+
}})))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Delete all data for a custom page metric
|
34
|
+
def clear_metric_data
|
35
|
+
self.class.delete("/pages/#{page_id}/metrics/#{metric_id}/data.json", @options)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative 'runscope_statuspage/version'
|
2
|
+
require_relative 'runscope_statuspage/exceptions'
|
3
|
+
require_relative 'runscope_statuspage/runscope_api'
|
4
|
+
require_relative 'runscope_statuspage/statuspage_api'
|
5
|
+
|
6
|
+
module RunscopeStatuspage
|
7
|
+
# Let Ruby write boring getters and setters
|
8
|
+
class << self; attr_accessor :rs_key, :sp_key, :sp_page, :name, :msg; end
|
9
|
+
|
10
|
+
# API credentials and IDs
|
11
|
+
@rs_key = ''
|
12
|
+
@sp_key = ''
|
13
|
+
@sp_page = ''
|
14
|
+
|
15
|
+
# Verbage sent to statuspage
|
16
|
+
@name = 'Suspected issues with /name/'
|
17
|
+
@msg = 'Our automated test detected an issue while testing the /description/ endpoint. We are currently investigating this issue.'
|
18
|
+
|
19
|
+
# As the user may decide (for whatever reason)
|
20
|
+
# to change API keys after one request, we re-initialize
|
21
|
+
# these objects.
|
22
|
+
def self.reinit_rest
|
23
|
+
@rs = RunscopeAPI.new(@rs_key)
|
24
|
+
@sp = StatuspageAPI.new(@sp_key)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Splice radar hash values from keys defined in
|
28
|
+
# @name and @msg.
|
29
|
+
def self.parameterize(radar)
|
30
|
+
rname = @name
|
31
|
+
rmsg = @msg
|
32
|
+
|
33
|
+
@name.scan(/.*?(\/)([A-Za-z]*)(\/)/).each do |set|
|
34
|
+
set.each do |token|
|
35
|
+
if radar.has_key?(token)
|
36
|
+
rname = rname.sub!("/#{token}/", radar[token]) unless (token == "/" and token.length == 1)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
@msg.scan(/.*?(\/)([A-Za-z]*)(\/)/).each do |set|
|
42
|
+
set.each do |token|
|
43
|
+
if radar.has_key?(token)
|
44
|
+
rmsg = rmsg.sub!("/#{token}/", radar[token]) unless (token == "/" and token.length == 1)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
return rname, rmsg
|
50
|
+
end
|
51
|
+
|
52
|
+
# Update status page with all radars, from all buckets.
|
53
|
+
# An error will most likely be thrown if you have empty buckets.
|
54
|
+
def self.report_everything(page, status, twitter_update)
|
55
|
+
reinit_rest
|
56
|
+
|
57
|
+
@rs.buckets.each do |bucket|
|
58
|
+
@rs.radars(bucket['key']).each do |radar|
|
59
|
+
if @rs.latest_radar_result(bucket['key'], radar['uuid'])['result'] != 'pass'
|
60
|
+
@sp.create_realtime_incident(@sp_page, *parameterize(radar).concat([status, twitter_update]))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Update status page with one radar, from one bucket.
|
67
|
+
def self.report_radar(bucket_name, radar_name, status, twitter_update)
|
68
|
+
reinit_rest
|
69
|
+
|
70
|
+
@rs.buckets.each do |bucket|
|
71
|
+
if bucket['name'] == bucket_name
|
72
|
+
@rs.radars(bucket['key']).each do |radar|
|
73
|
+
if @rs.latest_radar_result(bucket['key'], radar['uuid'])['result'] != 'pass' and radar['name'] == radar_name
|
74
|
+
@sp.create_realtime_incident(@sp_page, *parameterize(radar).concat([status, twitter_update]))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
# Update status page with list of radars, from one bucket.
|
83
|
+
def self.report_radars(bucket_name, radar_names, status, twitter_update)
|
84
|
+
reinit_rest
|
85
|
+
|
86
|
+
@rs.buckets.each do |bucket|
|
87
|
+
if bucket['name'] == bucket_name
|
88
|
+
@rs.radars(bucket['key']).each do |radar|
|
89
|
+
if @rs.latest_radar_result(bucket['key'], radar['uuid'])['result'] != 'pass' and radar_names.include?(radar['name'])
|
90
|
+
@sp.create_realtime_incident(@sp_page, *parameterize(radar).concat([status, twitter_update]))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
# Update status page with all radars under passed
|
99
|
+
# bucket name.
|
100
|
+
def self.report_bucket(bucket_name, status, twitter_update)
|
101
|
+
reinit_rest
|
102
|
+
|
103
|
+
@rs.buckets.each do |bucket|
|
104
|
+
if bucket['name'] == bucket_name
|
105
|
+
@rs.radars(bucket['key']).each do |radar|
|
106
|
+
if @rs.latest_radar_result(bucket['key'], radar['uuid'])['result'] != 'pass'
|
107
|
+
@sp.create_realtime_incident(@sp_page, *parameterize(radar).concat([status, twitter_update]))
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
# Update status page with all radars under the specified
|
116
|
+
# buckets
|
117
|
+
def self.report_buckets(bucket_names, status, twitter_update)
|
118
|
+
reinit_rest
|
119
|
+
|
120
|
+
@rs.buckets.each do |bucket|
|
121
|
+
if bucket_names.include?(bucket['name'])
|
122
|
+
@rs.radars(bucket['key']).each do |radar|
|
123
|
+
if @rs.latest_radar_result(bucket['key'], radar['uuid'])['result'] != 'pass'
|
124
|
+
@sp.create_realtime_incident(@sp_page, *parameterize(radar).concat([status, twitter_update]))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'runscope_statuspage/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'runscope_statuspage'
|
8
|
+
spec.version = RunscopeStatuspage::VERSION
|
9
|
+
spec.authors = ['David Stancu']
|
10
|
+
spec.email = ['dstancu@nyu.edu']
|
11
|
+
spec.summary = 'Push RunScope data to StatusPage.io'
|
12
|
+
spec.description = 'Get test data from RunScope and easily report incidents to StatusPage.io, all with one gem.'
|
13
|
+
spec.homepage = 'https://github.com/mach-kernel/runscope_statuspage'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.8'
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: runscope_statuspage
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Stancu
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Get test data from RunScope and easily report incidents to StatusPage.io,
|
42
|
+
all with one gem.
|
43
|
+
email:
|
44
|
+
- dstancu@nyu.edu
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- bin/console
|
55
|
+
- bin/setup
|
56
|
+
- lib/runscope_statuspage.rb
|
57
|
+
- lib/runscope_statuspage/exceptions.rb
|
58
|
+
- lib/runscope_statuspage/runscope_api.rb
|
59
|
+
- lib/runscope_statuspage/statuspage_api.rb
|
60
|
+
- lib/runscope_statuspage/version.rb
|
61
|
+
- runscope_statuspage.gemspec
|
62
|
+
homepage: https://github.com/mach-kernel/runscope_statuspage
|
63
|
+
licenses:
|
64
|
+
- MIT
|
65
|
+
metadata: {}
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 2.2.2
|
83
|
+
signing_key:
|
84
|
+
specification_version: 4
|
85
|
+
summary: Push RunScope data to StatusPage.io
|
86
|
+
test_files: []
|