dogwatch 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +24 -0
- data/.rubocop_todo.yml +25 -0
- data/.ruby-version +1 -0
- data/Gemfile +14 -0
- data/LICENSE +23 -0
- data/README.md +66 -0
- data/Rakefile +12 -0
- data/Thorfile +5 -0
- data/bin/dogwatch +28 -0
- data/dogwatch.gemspec +23 -0
- data/example/Dogfile +23 -0
- data/example/credentials.example +2 -0
- data/lib/dogwatch.rb +13 -0
- data/lib/dogwatch/dogfile.rb +27 -0
- data/lib/dogwatch/model/client.rb +92 -0
- data/lib/dogwatch/model/config.rb +36 -0
- data/lib/dogwatch/model/mixin/colorize.rb +23 -0
- data/lib/dogwatch/model/monitor.rb +68 -0
- data/lib/dogwatch/model/options.rb +60 -0
- data/lib/dogwatch/model/response.rb +62 -0
- data/lib/dogwatch/monitor.rb +51 -0
- data/lib/dogwatch/version.rb +6 -0
- data/test/data/monitors.json +58 -0
- data/test/data/responses.rb +22 -0
- data/test/dogwatch/test_client.rb +66 -0
- data/test/dogwatch/test_colorize.rb +21 -0
- data/test/dogwatch/test_config.rb +31 -0
- data/test/dogwatch/test_dogwatch.rb +15 -0
- data/test/dogwatch/test_monitor_model.rb +53 -0
- data/test/dogwatch/test_options.rb +81 -0
- data/test/dogwatch/test_response.rb +32 -0
- data/test/test_helper.rb +19 -0
- metadata +182 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9d79c2c09e6613e01aebac074584db2d77fb0cec
|
4
|
+
data.tar.gz: a45e5c711c68224dae11e425b249e60ba2e56862
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e61f782beb109454fc226473554a4da0c00b0e809c598228215be23bd00f7c3d85e3623dea6bb27a17e917c5772c72b4036a42c995da1db51badcf8f23ce2a35
|
7
|
+
data.tar.gz: e6ed10925ee458aec58a752fcae1680e113cc628e5914d5c1c087b0881012a2a403da9f7eb0c45de430d4bafa9bcb8f59857ade2f296b2297a0b9600e5b0b8fc
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
Include:
|
5
|
+
- lib/**/*
|
6
|
+
- bin/**/*
|
7
|
+
- test/**/*
|
8
|
+
- Gemfile
|
9
|
+
- Rakefile
|
10
|
+
- Thorfile
|
11
|
+
Exclude:
|
12
|
+
- example/**/*
|
13
|
+
- test/data/*
|
14
|
+
|
15
|
+
Encoding:
|
16
|
+
Enabled: false
|
17
|
+
RescueModifier:
|
18
|
+
Enabled: false
|
19
|
+
HashSyntax:
|
20
|
+
Enabled: false
|
21
|
+
SpaceInsideStringInterpolation:
|
22
|
+
Enabled: false
|
23
|
+
DoubleNegation:
|
24
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2015-12-02 13:53:58 -0500 using RuboCop version 0.34.2.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 2
|
10
|
+
# Configuration parameters: AllowURI, URISchemes.
|
11
|
+
Metrics/LineLength:
|
12
|
+
Max: 83
|
13
|
+
|
14
|
+
# Offense count: 2
|
15
|
+
# Cop supports --auto-correct.
|
16
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
|
17
|
+
Style/RegexpLiteral:
|
18
|
+
Exclude:
|
19
|
+
- 'dogwatch.gemspec'
|
20
|
+
|
21
|
+
# Offense count: 2
|
22
|
+
# Cop supports --auto-correct.
|
23
|
+
Style/RescueModifier:
|
24
|
+
Exclude:
|
25
|
+
- 'lib/dogwatch/version.rb'
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.2
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in convection.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem 'bundler', '~> 1.7'
|
8
|
+
gem 'minitest'
|
9
|
+
gem 'minitest-reporters', '>= 0.5.0'
|
10
|
+
gem 'rake', '~> 10.0'
|
11
|
+
gem 'rubocop', '~> 0.34'
|
12
|
+
gem 'simplecov'
|
13
|
+
gem 'thor-scmversion', '= 1.7.0'
|
14
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2015 David Greene, Rapid7 LLC.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
===========
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# DogWatch
|
2
|
+
|
3
|
+
_A DSL to create DataDog monitors_
|
4
|
+
|
5
|
+
This gem is designed to provide a simple method for creating DataDog monitors in Ruby.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'dogwatch'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```shell
|
16
|
+
$ bundle exec dogwatch create [--dogfile=DOGFILE] [--api_key=API KEY] [--app_key=APP KEY]
|
17
|
+
```
|
18
|
+
Or install it yourself as:
|
19
|
+
```shell
|
20
|
+
$ gem install dogwatch
|
21
|
+
```
|
22
|
+
|
23
|
+
## Credentials
|
24
|
+
[DataDog API credentials](https://app.datadoghq.com/account/settings#api) are required.
|
25
|
+
|
26
|
+
Generate both an api key and an app key and either place them in a file named `~/.dogwatch/credentials` or pass them via the command line.
|
27
|
+
|
28
|
+
A sample credentials file is provided in the `example` directory.
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
DogWatch is a thin DSL over the [DataDog ruby client](https://github.com/DataDog/dogapi-rb) that handles generating DataDog monitors.
|
32
|
+
|
33
|
+
The following is an example of a `Dogfile`:
|
34
|
+
```ruby
|
35
|
+
require 'dogwatch'
|
36
|
+
|
37
|
+
DogWatch.monitor do
|
38
|
+
## Create a new monitor - monitor name is REQUIRED
|
39
|
+
monitor 'MONITOR NAME' do
|
40
|
+
type :metric_alert # REQUIRED: One of [:metric_alert | :service_check | :event_alert]
|
41
|
+
query 'QUERY' # REQUIRED
|
42
|
+
message 'MESSAGE'
|
43
|
+
tags %w(A list of tags to associate with your monitor)
|
44
|
+
|
45
|
+
options do
|
46
|
+
silenced '*': nil
|
47
|
+
notify_no_data false
|
48
|
+
no_data_timeframe 3
|
49
|
+
timeout_h 99
|
50
|
+
renotify_interval 60
|
51
|
+
escalation_message 'oh snap'
|
52
|
+
include_tags true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
Monitors that already exist are matched by name and updated accordingly. If the name isn't matched exactly, DogWatch assumes you want a new monitor.
|
59
|
+
|
60
|
+
A sample `Dogfile` is provided in the `example` directory.
|
61
|
+
|
62
|
+
For a full list of options and a description of each parameter, see [DataDog's API documentation](http://docs.datadoghq.com/api/#monitors).
|
63
|
+
|
64
|
+
## TO DO
|
65
|
+
* More descriptive errors
|
66
|
+
* Better error handling if a monitor fails local validation
|
data/Rakefile
ADDED
data/Thorfile
ADDED
data/bin/dogwatch
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'thor'
|
3
|
+
require 'dogwatch/dogfile'
|
4
|
+
|
5
|
+
module DogWatch
|
6
|
+
##
|
7
|
+
# DogWatch CLI
|
8
|
+
##
|
9
|
+
class CLI < Thor
|
10
|
+
class_option :dogfile, :type => :string, :default => 'Dogfile'
|
11
|
+
class_option :api_key, :type => :string, :default => nil
|
12
|
+
class_option :app_key, :type => :string, :default => nil
|
13
|
+
def initialize(*args)
|
14
|
+
super
|
15
|
+
@cwd = Dir.getwd
|
16
|
+
@dogfile = DogWatch::DogFile.new
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'create', 'Create a monitor from a Dogfile'
|
20
|
+
def create
|
21
|
+
@dogfile.configure(File.absolute_path(options['dogfile'], @cwd),
|
22
|
+
options['api_key'], options['app_key'])
|
23
|
+
@dogfile.create { |c| say_status(*c.to_thor) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
DogWatch::CLI.start(ARGV)
|
data/dogwatch.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dogwatch/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'dogwatch'
|
8
|
+
spec.version = DogWatch::VERSION
|
9
|
+
spec.authors = ['David Greene']
|
10
|
+
spec.email = ['David_Greene@rapid7.com']
|
11
|
+
spec.summary = DogWatch::SUMMARY
|
12
|
+
spec.description = DogWatch::DESCRIPTION
|
13
|
+
spec.homepage = 'https://github.com/rapid7/dogwatch'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'dogapi', '~> 1.21'
|
22
|
+
spec.add_runtime_dependency 'thor', '~> 0.19'
|
23
|
+
end
|
data/example/Dogfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative '../lib/dogwatch'
|
2
|
+
|
3
|
+
DogWatch.monitor do
|
4
|
+
monitor 'test_alert' do
|
5
|
+
type :metric_alert
|
6
|
+
query 'avg(last_1m):avg:system.cpu.user{region:us-east-1} > 20'
|
7
|
+
message 'A message to include with notifications for this monitor.'\
|
8
|
+
'Email notifications can be sent to specific users by '\
|
9
|
+
'using the same \'@username\' notation as events.'
|
10
|
+
|
11
|
+
tags %w(A list of tags to associate with your monitor)
|
12
|
+
|
13
|
+
options do
|
14
|
+
silenced '*': nil
|
15
|
+
notify_no_data false
|
16
|
+
no_data_timeframe 3
|
17
|
+
timeout_h 99
|
18
|
+
renotify_interval 60
|
19
|
+
escalation_message 'oh snap'
|
20
|
+
include_tags true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/dogwatch.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'model/config'
|
2
|
+
require_relative 'model/client'
|
3
|
+
|
4
|
+
module DogWatch
|
5
|
+
##
|
6
|
+
# Manage the execution of the Dogfile
|
7
|
+
##
|
8
|
+
class DogFile
|
9
|
+
# @param [String] dogfile
|
10
|
+
# @param [String|Object] api_key
|
11
|
+
# @param [String|Object] app_key
|
12
|
+
def configure(dogfile, api_key = nil, app_key = nil)
|
13
|
+
@dogfile = dogfile
|
14
|
+
@config = DogWatch::Model::Config.new(api_key, app_key)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [Proc] block
|
18
|
+
def create(&block)
|
19
|
+
monitor = instance_eval(IO.read(@dogfile), @dogfile, 1)
|
20
|
+
monitor.config = @config
|
21
|
+
monitor.client
|
22
|
+
|
23
|
+
monitor.get
|
24
|
+
monitor.responses.each { |r| block.call(r) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'dogapi'
|
2
|
+
require_relative 'config'
|
3
|
+
require_relative 'response'
|
4
|
+
|
5
|
+
module DogWatch
|
6
|
+
module Model
|
7
|
+
##
|
8
|
+
# Client interface for the DataDog API
|
9
|
+
##
|
10
|
+
class Client
|
11
|
+
attr_accessor :client
|
12
|
+
attr_accessor :config
|
13
|
+
attr_reader :response
|
14
|
+
|
15
|
+
# @param [DogWatch::Model::Config] config
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
@client = Dogapi::Client.new(@config.api_key, @config.app_key)
|
19
|
+
@all_monitors = all_monitors
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [DogWatch::Model::Monitor] monitor
|
23
|
+
def execute(monitor)
|
24
|
+
if monitor_exists?(monitor.name)
|
25
|
+
update_monitor(monitor)
|
26
|
+
else
|
27
|
+
new_monitor(monitor)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param [DogWatch::Model::Monitor] monitor
|
32
|
+
# @return [DogWatch::Model::Response]
|
33
|
+
def update_monitor(monitor)
|
34
|
+
options = options(monitor)
|
35
|
+
existing_monitor = get_monitor(monitor.name)
|
36
|
+
response = @client.update_monitor(existing_monitor['id'],
|
37
|
+
monitor.attributes.query,
|
38
|
+
options)
|
39
|
+
updated = %w(200 202).include?(response[0])
|
40
|
+
@response = DogWatch::Model::Response.new(response, updated)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param [DogWatch::Model::Monitor] monitor
|
44
|
+
# @return [DogWatch::Model::Response]
|
45
|
+
def new_monitor(monitor)
|
46
|
+
options = options(monitor)
|
47
|
+
response = @client.monitor(monitor.attributes.type,
|
48
|
+
monitor.attributes.query,
|
49
|
+
options)
|
50
|
+
@response = DogWatch::Model::Response.new(response)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# @param [DogWatch::Model::Monitor] monitor
|
56
|
+
# @return [Hash]
|
57
|
+
def options(monitor)
|
58
|
+
{
|
59
|
+
name: monitor.name,
|
60
|
+
message: monitor.attributes.message,
|
61
|
+
tags: monitor.attributes.tags,
|
62
|
+
options: monitor.attributes.options
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [String] name
|
67
|
+
# @return [TrueClass|FalseClass]
|
68
|
+
def monitor_exists?(name)
|
69
|
+
@all_monitors.count { |m| m['name'] == name } > 0
|
70
|
+
end
|
71
|
+
|
72
|
+
# @param [String] name
|
73
|
+
# @return [Hash]
|
74
|
+
def get_monitor(name)
|
75
|
+
@all_monitors.find { |m| m['name'] == name }
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [Array]
|
79
|
+
def all_monitors
|
80
|
+
response = @client.get_all_monitors if @all_monitors.nil?
|
81
|
+
@all_monitors = response[1] if response[0] == '200'
|
82
|
+
@all_monitors
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [DogWatch::Model::Config]
|
86
|
+
def config
|
87
|
+
@config = DogWatch::Model::Config.new if @config.nil?
|
88
|
+
@config
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module DogWatch
|
4
|
+
module Model
|
5
|
+
##
|
6
|
+
# Manages API configuration. Currently handles
|
7
|
+
# credential only.
|
8
|
+
##
|
9
|
+
class Config
|
10
|
+
attr_accessor :api_key
|
11
|
+
attr_accessor :app_key
|
12
|
+
|
13
|
+
# @param [String] api_key
|
14
|
+
# @param [String] app_key
|
15
|
+
def initialize(api_key = nil, app_key = nil)
|
16
|
+
@api_key = api_key unless api_key.nil?
|
17
|
+
@app_key = app_key unless app_key.nil?
|
18
|
+
return unless app_key.nil? || api_key.nil?
|
19
|
+
|
20
|
+
from_file
|
21
|
+
end
|
22
|
+
|
23
|
+
def from_file
|
24
|
+
begin
|
25
|
+
config_file = IO.read("#{Dir.home}/.dogwatch/credentials")
|
26
|
+
rescue
|
27
|
+
raise('No credentials supplied')
|
28
|
+
end
|
29
|
+
|
30
|
+
credentials = YAML.load(config_file)
|
31
|
+
@api_key = credentials['api_key']
|
32
|
+
@app_key = credentials['app_key']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|