victor_ops-client 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ef7b0ede3d1b7572df728e8824d3999c05391f1b
4
+ data.tar.gz: 37c171cd2e582019d437e5dfdf09c4932dab4fed
5
+ SHA512:
6
+ metadata.gz: 7947fbdd8c0ecc7d81206aacee0fb41464525b34c858e8562fd4663b26f98cc808c4c3757397703e0c1fd8ea75512f6500dd4aeb7f4efd938544d018c19a9102
7
+ data.tar.gz: 2b218795188a34caea06f4a0332f063ea030ddecb1a2ff2d67e9a337b062e1b00b6fcc57584fcec5e96cdec32a7f587fb3166ed7b34e07e1f67086a39f4131de
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ # for a library or gem, you might want to ignore these files since the code is
29
+ # intended to run in multiple environments; otherwise, check them in:
30
+ Gemfile.lock
31
+ .ruby-version
32
+ .ruby-gemset
33
+
34
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
+ .rvmrc
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ - 2.1.0
5
+ - 2.0.0
6
+ - 1.9.3
7
+ addons:
8
+ code_climate:
9
+ repo_token: 86322de3b5909460dccb9d35d43d90178899a4887fefc28b2bf6ac5818708918
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'rake'
5
+ gem 'rest-client'
6
+ gem 'awesome_print'
7
+ gem 'daybreak'
8
+
9
+ group :test do
10
+ gem 'rspec', '~> 3.1'
11
+ gem 'simplecov', require: false
12
+ gem 'codeclimate-test-reporter', require: false
13
+ end
data/History ADDED
@@ -0,0 +1,20 @@
1
+ == 0.3.0 2015-04-09
2
+
3
+ * refactored payload generation
4
+
5
+ == 0.2.1 2015-04-08
6
+
7
+ * minor change to default naming
8
+
9
+ == 0.2.0 2015-04-08
10
+
11
+ * added persistence layer
12
+ * ability to track and update incidents between Client runs
13
+
14
+ == 0.1.0 2015-04-04
15
+
16
+ * Initial deployment
17
+
18
+ == 0.0.1 2015-04-03
19
+
20
+ * Initial development
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) [year] [fullname]
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,60 @@
1
+ [![Gem Version](https://img.shields.io/gem/v/victor_ops-client.svg)](https://rubygems.org/gems/victor_ops-client)
2
+ [![Build Status](https://travis-ci.org/clok/victor-ops-client.svg?branch=master)](https://travis-ci.org/clok/victor-ops-client)
3
+ [![Code Climate](https://codeclimate.com/github/clok/victor-ops-client/badges/gpa.svg)](https://codeclimate.com/github/clok/victor-ops-client)
4
+ [![Test Coverage](https://codeclimate.com/github/clok/victor-ops-client/badges/coverage.svg)](https://codeclimate.com/github/clok/victor-ops-client)
5
+
6
+ VictorOps Ruby Client
7
+ ---
8
+
9
+ A simple REST API client for use with the [VictorOps REST API](http://victorops.force.com/knowledgebase/articles/Integration/Alert-Ingestion-API-Documentation/)
10
+
11
+ # Install
12
+
13
+ ```
14
+ gem install victor_ops-client
15
+ ```
16
+
17
+ ## Requirements
18
+
19
+ - Ruby 1.9.3 or higher
20
+ - `rest-client` & `awesome_print`
21
+ - VictorOps API Access
22
+
23
+ ## Example
24
+
25
+ ``` ruby
26
+ $:.unshift(File.join(File.dirname(__FILE__), "/../lib"))
27
+ require 'victor_ops/client'
28
+
29
+ # Required for Initializing Client
30
+ API_URL = 'https://alert.victorops.com/REST_END_POINT/API_KEY'
31
+ ROUTING_KEY = 'example_routing_key'
32
+
33
+ client = VictorOps::Client.new api_url: API_URL, routing_key: ROUTING_KEY
34
+
35
+ # Send a CRITICAL alert
36
+ client.critical 'THE DISK IS FULL!!!'
37
+
38
+ # Send a WARNING alert
39
+ client.warn desc: 'Disk is nearing capacity', stats: `df -h`
40
+
41
+ # Send an INFO alert
42
+ client.info [ 'this', 'is', 'an', 'array' ]
43
+
44
+ # Send an ACKNOWLEDGMENT
45
+ client.ack 'bot ack'
46
+
47
+ # Send a RECOVERY
48
+ client.recovery desc: 'Disk has space', emoji: ':saiyan:'
49
+ ```
50
+
51
+ ## Contributing
52
+
53
+ * Fork the project.
54
+ * Run `bundle install`
55
+ * Run `bundle exec rake`
56
+ * Make your feature addition or bug fix.
57
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
58
+ * Run `bundle exec rake` (No, REALLY :))
59
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
60
+ * Send me a pull request. Bonus points for topic branches.
@@ -0,0 +1,9 @@
1
+ ENV['CODECLIMATE_REPO_TOKEN'] = '86322de3b5909460dccb9d35d43d90178899a4887fefc28b2bf6ac5818708918'
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ rescue LoadError
7
+ end
8
+
9
+ task default: [:spec]
File without changes
@@ -0,0 +1,25 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "/../lib"))
4
+ require 'victor_ops/client'
5
+
6
+ # Required for Initializing Client
7
+ API_URL = 'INSERT_URL_HERE'
8
+ ROUTING_KEY = 'INSERT_ROUTING_KEY_HERE'
9
+
10
+ client = VictorOps::Client.new api_url: API_URL, routing_key: ROUTING_KEY
11
+
12
+ # Send a CRITICAL alert
13
+ client.critical 'THE DISK IS FULL!!!'
14
+
15
+ # Send a WARNING alert
16
+ client.warn desc: 'Disk is nearing capacity', stats: `df -h`
17
+
18
+ # Send an INFO alert
19
+ client.info [ 'this', 'is', 'an', 'array' ]
20
+
21
+ # Send an ACKNOWLEDGMENT
22
+ client.ack 'bot ack'
23
+
24
+ # Send a RECOVERY
25
+ client.recovery desc: 'Disk has space', emoji: ':saiyan:'
@@ -0,0 +1,155 @@
1
+ require 'victor_ops/defaults'
2
+ require 'victor_ops/client/version'
3
+ require 'victor_ops/client/exceptions'
4
+ require 'victor_ops/client/persistence'
5
+
6
+ module VictorOps
7
+ class Client
8
+ require 'ostruct'
9
+ require 'awesome_print'
10
+ require 'json'
11
+ require 'rest-client'
12
+
13
+ attr_accessor :settings
14
+
15
+ def initialize(opts)
16
+ @settings = OpenStruct.new opts
17
+ AwesomePrint.defaults = { indent: -2, plain: true }
18
+ set_default_settings
19
+ configure_data_store unless settings.persist.nil?
20
+ raise VictorOps::Client::MissingSettings unless valid_settings?
21
+ end
22
+
23
+ def entity_display_name
24
+ if settings.entity_display_name.nil?
25
+ "#{settings.host}/#{settings.name}"
26
+ else
27
+ settings.entity_display_name
28
+ end
29
+ end
30
+
31
+ def entity_display_name=(str)
32
+ settings.entity_display_name = str
33
+ end
34
+
35
+ def monitoring_tool
36
+ if settings.monitoring_tool.nil?
37
+ "#{settings.routing_key}::#{settings.name}"
38
+ else
39
+ settings.monitoring_tool
40
+ end
41
+ end
42
+
43
+ def monitoring_tool=(str)
44
+ settings.monitoring_tool = str
45
+ end
46
+
47
+ def critical(data)
48
+ post critical_payload(data)
49
+ end
50
+
51
+ def warn(data)
52
+ post warn_payload(data)
53
+ end
54
+
55
+ def info(data)
56
+ post info_payload(data)
57
+ end
58
+
59
+ def ack(data)
60
+ post ack_payload(data)
61
+ end
62
+
63
+ def recovery(data)
64
+ post recovery_payload(data)
65
+ end
66
+
67
+ private
68
+
69
+ def epochtime
70
+ Time.now.to_i
71
+ end
72
+
73
+ def set_default_settings
74
+ settings.host = VictorOps::Defaults::HOST if settings.host.nil?
75
+ settings.name = VictorOps::Defaults::NAME if settings.name.nil?
76
+ end
77
+
78
+ def endpoint
79
+ "#{settings.api_url}/#{settings.routing_key}"
80
+ end
81
+
82
+ def post(payload)
83
+ resp = nil
84
+ begin
85
+ json = RestClient.post endpoint, payload.to_json
86
+ resp = JSON::parse(json)
87
+ raise VictorOps::Client::PostFailure, "Response from VictorOps contains a failure message: #{resp.ai}" if resp['result'] == 'failure'
88
+ rescue Exception => e
89
+ raise VictorOps::Client::PostFailure, "Error posting to VictorOps: #{e}"
90
+ end
91
+ resp
92
+ end
93
+
94
+ def generate_payload(data)
95
+ if data.nil? || data[:vo_alert_type].nil?
96
+ raise VictorOps::Client::MissingMessageType
97
+ end
98
+ payload = {
99
+ message_type: data.delete(:vo_alert_type),
100
+ state_start_time: epochtime,
101
+ entity_display_name: entity_display_name,
102
+ monitoring_tool: monitoring_tool,
103
+ }
104
+ payload.merge! data
105
+ payload.delete_if { |k,v| v.nil? }
106
+ end
107
+
108
+ def critical_payload(data)
109
+ generate_payload data.merge({
110
+ vo_alert_type: VictorOps::Defaults::MessageTypes::CRITICAL,
111
+ state_message: data[:message].nil? ? nil : data.delete(:message).ai
112
+ })
113
+ end
114
+
115
+ def warn_payload(data)
116
+ generate_payload data.merge({
117
+ vo_alert_type: VictorOps::Defaults::MessageTypes::WARN,
118
+ state_message: data[:message].nil? ? nil : data.delete(:message).ai
119
+ })
120
+ end
121
+
122
+ def info_payload(data)
123
+ generate_payload data.merge({
124
+ vo_alert_type: VictorOps::Defaults::MessageTypes::INFO,
125
+ state_message: data[:message].nil? ? nil : data.delete(:message).ai
126
+ })
127
+ end
128
+
129
+ def ack_payload(data)
130
+ generate_payload data.merge({
131
+ vo_alert_type: VictorOps::Defaults::MessageTypes::ACK,
132
+ ack_msg: data[:message].nil? ? nil : data.delete(:message).ai,
133
+ ack_author: data[:author].nil? ? monitoring_tool : data.delete(:author)
134
+ })
135
+ end
136
+
137
+ def recovery_payload(data)
138
+ generate_payload data.merge({
139
+ vo_alert_type: VictorOps::Defaults::MessageTypes::RECOVERY,
140
+ state_message: data[:message].nil? ? nil : data.delete(:message).ai
141
+ })
142
+ end
143
+
144
+ def valid_settings?
145
+ valid = true
146
+ [:api_url, :routing_key].each do |k|
147
+ next if valid == false
148
+ valid = false unless settings.send(k)
149
+ end
150
+ settings.api_url.chop! if settings.api_url =~ /\/$/
151
+ valid
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,15 @@
1
+ module VictorOps
2
+ class Client
3
+
4
+ class Error < StandardError; end
5
+
6
+ class MissingSettings < Error; end
7
+
8
+ class PostFailure < Error; end
9
+
10
+ class MissingMessageType < Error; end
11
+
12
+ class NotYetImplemented < Error; end
13
+
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ module VictorOps
2
+ class Client
3
+ require 'daybreak'
4
+
5
+ attr_accessor :db
6
+
7
+ def configure_data_store
8
+ settings.store_file = VictorOps::Defaults::Daybreak::PATH unless settings.store_file
9
+ @db = Daybreak::DB.new settings.store_file
10
+ ObjectSpace.define_finalizer(self, proc { shutdown })
11
+ end
12
+
13
+ def set(key, value)
14
+ db.set! key, value
15
+ end
16
+
17
+ def retrieve(key)
18
+ db[key]
19
+ end
20
+
21
+ def delete(key)
22
+ db.delete! key
23
+ end
24
+
25
+ def shutdown
26
+ db.flush
27
+ db.compact
28
+ db.close
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module VictorOps
2
+ class Client
3
+ VERSION = '0.3.0'
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ module VictorOps
2
+ module Defaults
3
+ HOST = 'localhost'
4
+ NAME = 'ruby REST client'
5
+
6
+ module MessageTypes
7
+ INFO = 'INFO'
8
+ WARN = 'WARNING'
9
+ ACK = 'ACKNOWLEDGEMENT'
10
+ CRITICAL = 'CRITICAL'
11
+ RECOVERY = 'RECOVERY'
12
+ end
13
+
14
+ module Daybreak
15
+ PATH = '/tmp/victor_ops-client.db'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,407 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ RSpec.describe VictorOps::Client do
4
+ before do
5
+ @valid_params = { api_url: 'test url', routing_key: 'test key' }
6
+ end
7
+
8
+ describe 'settings' do
9
+ before do
10
+ @client = VictorOps::Client.new @valid_params.merge(option: 'this is working')
11
+ end
12
+
13
+ it 'should return an OpenStruct hash with the input options hash as settings methods' do
14
+ expect(@client.settings).to be_a(OpenStruct)
15
+ expect(@client.settings.api_url).to eq 'test url'
16
+ expect(@client.settings.routing_key).to eq 'test key'
17
+ expect(@client.settings.option).to eq 'this is working'
18
+ expect(@client.settings.not_a_passed_option).to be_nil
19
+ end
20
+ end
21
+
22
+ describe '.monitoring_tool' do
23
+ context 'a parameter is provided on initialization' do
24
+ before do
25
+ @client = VictorOps::Client.new @valid_params.merge(monitoring_tool: 'monitorting tool')
26
+ end
27
+
28
+ it 'should return the passed in name' do
29
+ expect(@client.monitoring_tool).to eq 'monitorting tool'
30
+ end
31
+ end
32
+
33
+ context 'default initialization' do
34
+ before do
35
+ @client = VictorOps::Client.new @valid_params
36
+ end
37
+
38
+ it 'should return the default name' do
39
+ expect(@client.monitoring_tool).to eq 'test key::ruby REST client'
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '.monitoring_tool=' do
45
+ it 'should set the entity_display_name name' do
46
+ @client = VictorOps::Client.new @valid_params
47
+ @client.monitoring_tool = 'cool name bro'
48
+ expect(@client.monitoring_tool).to eq 'cool name bro'
49
+ end
50
+ end
51
+
52
+ describe '.entity_display_name' do
53
+ context 'a parameter is provided on initialization' do
54
+ before do
55
+ @client = VictorOps::Client.new @valid_params.merge(entity_display_name: 'super cool tool')
56
+ end
57
+
58
+ it 'should return the passed in nanme' do
59
+ expect(@client.entity_display_name).to eq 'super cool tool'
60
+ end
61
+ end
62
+
63
+ context 'default initialization' do
64
+ before do
65
+ @client = VictorOps::Client.new @valid_params
66
+ end
67
+
68
+ it 'should return the default name' do
69
+ expect(@client.entity_display_name).to eq 'localhost/ruby REST client'
70
+ end
71
+ end
72
+ end
73
+
74
+ describe '.entity_display_name=' do
75
+ it 'should set the entity_display_name' do
76
+ @client = VictorOps::Client.new @valid_params
77
+ @client.entity_display_name = 'cool name bro'
78
+ expect(@client.entity_display_name).to eq 'cool name bro'
79
+ end
80
+ end
81
+
82
+ describe '.critical' do
83
+ before do
84
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
85
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
86
+ end
87
+
88
+ it 'should resturn the result of the post to VictorOps' do
89
+ resp = @client.critical(message: 'test')
90
+ expect(resp).to be_a(Hash)
91
+ expect(resp['result']).to eq 'success'
92
+ end
93
+ end
94
+
95
+ describe '.warn' do
96
+ before do
97
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
98
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
99
+ end
100
+
101
+ it 'should resturn the result of the post to VictorOps' do
102
+ resp = @client.warn(message: 'test')
103
+ expect(resp).to be_a(Hash)
104
+ expect(resp['result']).to eq 'success'
105
+ end
106
+ end
107
+
108
+ describe '.info' do
109
+ before do
110
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
111
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
112
+ end
113
+
114
+ it 'should resturn the result of the post to VictorOps' do
115
+ resp = @client.info(message: 'test')
116
+ expect(resp).to be_a(Hash)
117
+ expect(resp['result']).to eq 'success'
118
+ end
119
+ end
120
+
121
+ describe '.ack' do
122
+ before do
123
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
124
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
125
+ end
126
+
127
+ it 'should resturn the result of the post to VictorOps' do
128
+ resp = @client.ack(message: 'test')
129
+ expect(resp).to be_a(Hash)
130
+ expect(resp['result']).to eq 'success'
131
+ end
132
+ end
133
+
134
+ describe '.recovery' do
135
+ before do
136
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
137
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
138
+ end
139
+
140
+ it 'should resturn the result of the post to VictorOps' do
141
+ resp = @client.recovery(message: 'test')
142
+ expect(resp).to be_a(Hash)
143
+ expect(resp['result']).to eq 'success'
144
+ end
145
+ end
146
+
147
+ context 'private methods' do
148
+ describe '.valid_settings?' do
149
+ context 'settings include required items' do
150
+ before do
151
+ @client = VictorOps::Client.new @valid_params
152
+ end
153
+
154
+ it 'should return true' do
155
+ expect(@client.send(:valid_settings?)).to be_truthy
156
+ end
157
+ end
158
+
159
+ context 'the api url has a slash at the end' do
160
+ before do
161
+ @client = VictorOps::Client.new api_url: 'slashy/url/', routing_key: 'test key'
162
+ end
163
+
164
+ it 'should return true' do
165
+ expect(@client.send(:valid_settings?)).to be_truthy
166
+ expect(@client.settings.api_url).to_not end_with('/')
167
+ expect(@client.settings.api_url).to eq 'slashy/url'
168
+ end
169
+ end
170
+
171
+ context 'the api url has no slash at the end' do
172
+ before do
173
+ @client = VictorOps::Client.new api_url: 'no/slashy/url', routing_key: 'test key'
174
+ end
175
+
176
+ it 'should return true' do
177
+ expect(@client.send(:valid_settings?)).to be_truthy
178
+ expect(@client.settings.api_url).to_not end_with('/')
179
+ expect(@client.settings.api_url).to eq 'no/slashy/url'
180
+ end
181
+ end
182
+
183
+ context 'settings do not include required items' do
184
+ before do
185
+ @client = VictorOps::Client.new @valid_params
186
+ @client.settings.routing_key = nil
187
+ end
188
+
189
+ it 'should return false' do
190
+ expect(@client.send(:valid_settings?)).to be_falsey
191
+ end
192
+ end
193
+ end
194
+
195
+ describe '.generate_payload' do
196
+ before do
197
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
198
+ end
199
+
200
+ context 'a nil hash was passed in' do
201
+ it 'should raise an expetion for no message_type provided' do
202
+ expect { @client.send(:generate_payload, nil) }.to raise_exception(VictorOps::Client::MissingMessageType)
203
+ end
204
+ end
205
+
206
+ context 'a hash without required message_type' do
207
+ it 'should raise an expetion for no message_type provided' do
208
+ expect { @client.send(:generate_payload, {stuff: 'test'}) }.to raise_exception(VictorOps::Client::MissingMessageType)
209
+ end
210
+ end
211
+
212
+ context 'a properly formed hash is passed in' do
213
+ it 'should return a payload hash' do
214
+ payload = @client.send(:generate_payload, {vo_alert_type: 'TEST'})
215
+ expect(payload[:message_type]).to eq 'TEST'
216
+ expect(payload[:state_start_time]).to be_a(Fixnum)
217
+ expect(payload[:entity_display_name]).to be_a(String)
218
+ expect(payload[:monitoring_tool]).to be_a(String)
219
+ end
220
+ end
221
+
222
+ context 'a properly formed hash is passed in with extra variables' do
223
+ it 'should return a payload hash' do
224
+ payload = @client.send(:generate_payload, {vo_alert_type: 'TEST', special_var: 'i am special'})
225
+ expect(payload[:message_type]).to eq 'TEST'
226
+ expect(payload[:special_var]).to eq 'i am special'
227
+ expect(payload[:state_start_time]).to be_a(Fixnum)
228
+ expect(payload[:entity_display_name]).to be_a(String)
229
+ expect(payload[:monitoring_tool]).to be_a(String)
230
+ end
231
+ end
232
+
233
+ context 'a properly formed hash is passed in with nil values' do
234
+ it 'should return a payload hash with the nil values removed' do
235
+ payload = @client.send(:generate_payload, {vo_alert_type: 'TEST', special_var: 'i am special', nil_value: nil})
236
+ expect(payload[:message_type]).to eq 'TEST'
237
+ expect(payload[:special_var]).to eq 'i am special'
238
+ expect(payload[:state_start_time]).to be_a(Fixnum)
239
+ expect(payload[:entity_display_name]).to be_a(String)
240
+ expect(payload[:monitoring_tool]).to be_a(String)
241
+ expect(payload.has_key?(:nil_value)).to be_falsey
242
+ end
243
+ end
244
+ end
245
+
246
+ context 'utility methods' do
247
+ before do
248
+ @client = VictorOps::Client.new @valid_params
249
+ end
250
+
251
+ describe '.epochtime' do
252
+ it 'should return the current time in intenger form' do
253
+ expect(@client.send(:epochtime)).to be_a(Fixnum)
254
+ end
255
+ end
256
+
257
+ describe '.set_default_settings' do
258
+ context 'no overides provided' do
259
+ it 'should set the default settings for the client' do
260
+ expect(@client.settings.host).to eq 'localhost'
261
+ expect(@client.settings.name).to eq 'ruby REST client'
262
+ end
263
+ end
264
+
265
+ context 'overides provided' do
266
+ before do
267
+ @client = VictorOps::Client.new @valid_params.merge(host: 'db1.com', name: 'jester')
268
+ end
269
+
270
+ it 'should set the settings to the overides for the client' do
271
+ expect(@client.settings.host).to eq 'db1.com'
272
+ expect(@client.settings.name).to eq 'jester'
273
+ end
274
+ end
275
+ end
276
+
277
+ describe '.endpoint' do
278
+ before do
279
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
280
+ end
281
+
282
+ it 'should provide the proper REST endpoint to post to' do
283
+ expect(@client.send(:endpoint)).to eq 'http://victorops.com/1234'
284
+ end
285
+ end
286
+
287
+ describe '.post' do
288
+ context 'there is a failure response from VictorOps' do
289
+ before do
290
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
291
+ allow(RestClient).to receive(:post).and_return(file_fixture('victor_ops_failure.json'))
292
+ end
293
+
294
+ it 'should raise an exception' do
295
+ expect { @client.send(:post, { test: 'hash' } ) }.to raise_exception(VictorOps::Client::PostFailure)
296
+ end
297
+ end
298
+
299
+ context 'there is a failure while posting to VictorOps' do
300
+ before do
301
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
302
+ allow(RestClient).to receive(:post).and_raise(Exception.new('test exception'))
303
+ end
304
+
305
+ it 'should raise an exception' do
306
+ expect { @client.send(:post, { test: 'hash' } ) }.to raise_exception(VictorOps::Client::PostFailure)
307
+ end
308
+ end
309
+
310
+ context 'the POST is successful' do
311
+ before do
312
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
313
+ allow(RestClient).to receive(:post).and_return(file_fixture('victor_ops_success.json'))
314
+ end
315
+
316
+ it 'return the parsed response' do
317
+ resp = @client.send(:post, { test: 'hash' } )
318
+ expect(resp).to be_a(Hash)
319
+ expect(resp['result']).to eq 'success'
320
+ expect(resp['entity_id']).to be_a(String)
321
+ end
322
+ end
323
+ end
324
+
325
+ describe '.critical_payload' do
326
+ it 'should return a Hash without duplicate data' do
327
+ data = @client.send(:critical_payload, message: 'test')
328
+ expect(data).to be_a(Hash)
329
+ expect(data[:message_type]).to eql 'CRITICAL'
330
+ expect(data[:entity_display_name]).to_not be_nil
331
+ expect(data[:monitoring_tool]).to_not be_nil
332
+ expect(data[:state_message]).to eq '"test"'
333
+ expect(data[:message]).to be_nil
334
+ end
335
+ end
336
+
337
+ describe '.warn_payload' do
338
+ it 'should return a Hash without duplicate data' do
339
+ data = @client.send(:warn_payload, message: 'test')
340
+ expect(data).to be_a(Hash)
341
+ expect(data[:message_type]).to eql 'WARNING'
342
+ expect(data[:entity_display_name]).to_not be_nil
343
+ expect(data[:monitoring_tool]).to_not be_nil
344
+ expect(data[:state_message]).to eq '"test"'
345
+ expect(data[:message]).to be_nil
346
+ end
347
+ end
348
+
349
+ describe '.info_payload' do
350
+ it 'should return a Hash without duplicate data' do
351
+ data = @client.send(:info_payload, message: 'test')
352
+ expect(data).to be_a(Hash)
353
+ expect(data[:message_type]).to eql 'INFO'
354
+ expect(data[:entity_display_name]).to_not be_nil
355
+ expect(data[:monitoring_tool]).to_not be_nil
356
+ expect(data[:state_message]).to eq '"test"'
357
+ expect(data[:message]).to be_nil
358
+ end
359
+ end
360
+
361
+ describe '.ack_payload' do
362
+ context 'no author provided' do
363
+ it 'should return a Hash without duplicate data' do
364
+ data = @client.send(:ack_payload, message: 'test')
365
+ expect(data).to be_a(Hash)
366
+ expect(data[:message_type]).to eql 'ACKNOWLEDGEMENT'
367
+ expect(data[:entity_display_name]).to_not be_nil
368
+ expect(data[:monitoring_tool]).to_not be_nil
369
+ expect(data[:state_message]).to be_nil
370
+ expect(data[:ack_msg]).to eq '"test"'
371
+ expect(data[:ack_author]).to eq data[:monitoring_tool]
372
+ expect(data[:message]).to be_nil
373
+ end
374
+ end
375
+
376
+ context 'an author is provieded' do
377
+ it 'should return a Hash without duplicate data' do
378
+ data = @client.send(:ack_payload, message: 'test', author: 'test author')
379
+ expect(data).to be_a(Hash)
380
+ expect(data[:message_type]).to eql 'ACKNOWLEDGEMENT'
381
+ expect(data[:entity_display_name]).to_not be_nil
382
+ expect(data[:monitoring_tool]).to_not be_nil
383
+ expect(data[:state_message]).to be_nil
384
+ expect(data[:ack_msg]).to eq '"test"'
385
+ expect(data[:ack_author]).to eq 'test author'
386
+ expect(data[:message]).to be_nil
387
+ expect(data[:author]).to be_nil
388
+ end
389
+ end
390
+ end
391
+
392
+ describe '.recovery_payload' do
393
+ it 'should return a Hash without duplicate data' do
394
+ data = @client.send(:recovery_payload, message: 'test')
395
+ expect(data).to be_a(Hash)
396
+ expect(data[:message_type]).to eql 'RECOVERY'
397
+ expect(data[:entity_display_name]).to_not be_nil
398
+ expect(data[:monitoring_tool]).to_not be_nil
399
+ expect(data[:state_message]).to eq '"test"'
400
+ expect(data[:message]).to be_nil
401
+ end
402
+ end
403
+ end
404
+
405
+ end
406
+
407
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ RSpec.describe VictorOps::Defaults do
4
+ describe 'MessageTypes' do
5
+ it 'should be have VictorOps defined values' do
6
+ expect(VictorOps::Defaults::MessageTypes::INFO).to eq 'INFO'
7
+ expect(VictorOps::Defaults::MessageTypes::WARN).to eq 'WARNING'
8
+ expect(VictorOps::Defaults::MessageTypes::CRITICAL).to eq 'CRITICAL'
9
+ expect(VictorOps::Defaults::MessageTypes::ACK).to eq 'ACKNOWLEDGEMENT'
10
+ expect(VictorOps::Defaults::MessageTypes::RECOVERY).to eq 'RECOVERY'
11
+ end
12
+ end
13
+
14
+ describe 'client defautlts' do
15
+ it 'should have generic defaults set' do
16
+ expect(VictorOps::Defaults::HOST).to eq 'localhost'
17
+ expect(VictorOps::Defaults::NAME).to eq 'ruby REST client'
18
+ end
19
+ end
20
+
21
+ describe 'daybreak defaults' do
22
+ it 'should have defaults needed for daybreak persistence' do
23
+ expect(VictorOps::Defaults::Daybreak::PATH).to eq '/tmp/victor_ops-client.db'
24
+ end
25
+ end
26
+ end
File without changes
@@ -0,0 +1,4 @@
1
+ {
2
+ "result": "failure",
3
+ "entity_id": "Missing something important"
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "result": "success",
3
+ "entity_id": "392c55f1-f5b6-42fa-b6d9-8aa033465ce6"
4
+ }
@@ -0,0 +1,75 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ RSpec.describe VictorOps::Client do
4
+ before do
5
+ @valid_params = { api_url: 'test url', routing_key: 'test key' }
6
+ end
7
+
8
+ context 'persistence layer' do
9
+ describe 'client does not want persistence' do
10
+ before do
11
+ @client = VictorOps::Client.new @valid_params.merge(persist: nil)
12
+ end
13
+
14
+ it 'should not configure daybreak' do
15
+ expect(@client.settings.test).to be_nil
16
+ end
17
+ end
18
+
19
+ context 'client does want persistence' do
20
+ before do
21
+ @client = VictorOps::Client.new @valid_params.merge(persist: true, store_file: 'tmp/test.db')
22
+ end
23
+
24
+ after do
25
+ @client.shutdown
26
+ end
27
+
28
+ it 'should configure daybreak' do
29
+ expect(@client.settings.store_file).to eq 'tmp/test.db'
30
+ expect(@client.db).to be_a(Daybreak::DB)
31
+ end
32
+
33
+ it 'should allow for interactions with the database directly' do
34
+ @client.db.set! 'test', 'worked'
35
+ expect(@client.db['test']).to eq 'worked'
36
+ expect(@client.db.include?('test')).to be_truthy
37
+ @client.db.delete 'test'
38
+ expect(@client.db.include?('test')).to be_falsey
39
+ expect(@client.db['test']).to be_nil
40
+ end
41
+
42
+ describe '.set' do
43
+ it 'will allow the setting of persisted values' do
44
+ @client.set('answer to all', 42)
45
+ expect(@client.db['answer to all']).to eq 42
46
+ @client.shutdown
47
+ @client = VictorOps::Client.new @valid_params.merge(persist: true, store_file: 'tmp/test.db')
48
+ expect(@client.db['answer to all']).to eq 42
49
+ end
50
+ end
51
+
52
+ describe '.retrieve' do
53
+ it 'will retrieve a persisted value' do
54
+ @client.set('tester', 'woot')
55
+ expect(@client.retrieve('tester')).to eq 'woot'
56
+ expect(@client.retrieve('not in here')).to be_nil
57
+ @client.shutdown
58
+ @client = VictorOps::Client.new @valid_params.merge(persist: true, store_file: 'tmp/test.db')
59
+ expect(@client.retrieve('tester')).to eq 'woot'
60
+ expect(@client.retrieve('not in here')).to be_nil
61
+ end
62
+ end
63
+
64
+ describe '.delete' do
65
+ it 'will delete a persisted value' do
66
+ @client.set('this will be deleted', 'woot')
67
+ expect(@client.delete('this will be deleted')).to eq 'woot'
68
+ @client.shutdown
69
+ @client = VictorOps::Client.new @valid_params.merge(persist: true, store_file: 'tmp/test.db')
70
+ expect(@client.delete('this will be deleted')).to be_nil
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,57 @@
1
+ require 'simplecov'
2
+ require 'codeclimate-test-reporter'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ CodeClimate::TestReporter::Formatter
7
+ ]
8
+ SimpleCov.start
9
+
10
+ require 'victor_ops/client'
11
+ require 'json'
12
+
13
+ def file_fixture(filename)
14
+ open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")).read
15
+ end
16
+
17
+ def file_fixture_to_json(filename)
18
+ JSON::parse(open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")).read)
19
+ end
20
+
21
+ def file_fixture_path(filename)
22
+ File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")
23
+ end
24
+
25
+ def open_tmp_file(filename)
26
+ open(File.join(File.dirname(__FILE__), '..', 'tmp', "#{filename.to_s}")).read
27
+ end
28
+
29
+ RSpec.configure do |config|
30
+ config.expect_with :rspec do |expectations|
31
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
+ end
33
+
34
+ config.mock_with :rspec do |mocks|
35
+ mocks.verify_partial_doubles = false
36
+ end
37
+
38
+ # config.filter_run :focus
39
+ # config.run_all_when_everything_filtered = true
40
+ # config.profile_examples = 10
41
+
42
+ config.disable_monkey_patching!
43
+
44
+ config.warnings = false
45
+
46
+ if config.files_to_run.one?
47
+ config.default_formatter = 'doc'
48
+ end
49
+
50
+
51
+ config.order = :random
52
+ Kernel.srand config.seed
53
+
54
+ config.after(:suite) do
55
+ FileUtils.rm('tmp/test.db') if File.exist? 'tmp/test.rb'
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ RSpec.describe VictorOps::Client do
4
+ describe "version" do
5
+ it 'should be a string type' do
6
+ expect(VictorOps::Client::VERSION).to be_a(String)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'victor_ops/client/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'victor_ops-client'
6
+ s.version = VictorOps::Client::VERSION
7
+ s.date = Time.now.strftime('%Y-%m-%d')
8
+ s.summary = "VictorOps Client"
9
+ s.description = "A gem that will allow for consistent usage of the VictorOps service from within a script or daemon."
10
+ s.authors = ["Derek Smith"]
11
+ s.email = 'derek@clokwork.net'
12
+ s.homepage = 'http://clokwork.net'
13
+
14
+ s.files = `git ls-files`.split("\n").compact
15
+ s.require_paths = ["lib"]
16
+
17
+ s.required_ruby_version = '>= 1.9.3'
18
+ s.add_dependency 'rest-client', '~> 1.8', '>= 1.8.0'
19
+ s.add_dependency 'awesome_print', '~> 1.6', '>= 1.6.1'
20
+ s.add_dependency 'daybreak', '~> 0.3', '>= 0.3.0'
21
+ s.add_development_dependency "rspec", '~> 3.0'
22
+
23
+ s.license = 'MIT'
24
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: victor_ops-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Derek Smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.8.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.8.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: awesome_print
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.6'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.6.1
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.6'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.6.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: daybreak
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.3'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 0.3.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.3'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 0.3.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: rspec
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '3.0'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '3.0'
87
+ description: A gem that will allow for consistent usage of the VictorOps service from
88
+ within a script or daemon.
89
+ email: derek@clokwork.net
90
+ executables: []
91
+ extensions: []
92
+ extra_rdoc_files: []
93
+ files:
94
+ - ".gitignore"
95
+ - ".travis.yml"
96
+ - Gemfile
97
+ - History
98
+ - MIT-LICENSE
99
+ - README.md
100
+ - Rakefile
101
+ - db/.keep
102
+ - examples/test.rb
103
+ - lib/victor_ops/client.rb
104
+ - lib/victor_ops/client/exceptions.rb
105
+ - lib/victor_ops/client/persistence.rb
106
+ - lib/victor_ops/client/version.rb
107
+ - lib/victor_ops/defaults.rb
108
+ - spec/client_spec.rb
109
+ - spec/defaults_spec.rb
110
+ - spec/fixtures/.keep
111
+ - spec/fixtures/victor_ops_failure.json
112
+ - spec/fixtures/victor_ops_success.json
113
+ - spec/persistence_spec.rb
114
+ - spec/spec_helper.rb
115
+ - spec/version_spec.rb
116
+ - tmp/.keep
117
+ - victor_ops-client.gemspec
118
+ homepage: http://clokwork.net
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 1.9.3
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.4.6
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: VictorOps Client
142
+ test_files: []