dogwatch 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ module DogWatch
2
+ module Model
3
+ module Mixin
4
+ ##
5
+ # Provides a colorize() mixin that handles shell output coloring
6
+ ##
7
+ module Colorize
8
+ def colorize(param, options = {})
9
+ define_method(:color) do
10
+ case instance_variable_get("@#{ param }")
11
+ when *options.fetch(:white, [:status]) then :white
12
+ when *options.fetch(:cyan, [:debug, :trace]) then :cyan
13
+ when *options.fetch(:green, [:info, :success, :create]) then :green
14
+ when *options.fetch(:yellow, [:warn, :update]) then :yellow
15
+ when *options.fetch(:red, [:error, :fail, :delete]) then :red
16
+ else options.fetch(:default, :green)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,68 @@
1
+ require 'ostruct'
2
+ require_relative 'options'
3
+
4
+ module DogWatch
5
+ module Model
6
+ ##
7
+ # Handles monitor DSL methods and object validation
8
+ ##
9
+ class Monitor
10
+ TYPE_MAP = {
11
+ metric_alert: 'metric alert',
12
+ service_check: 'service check',
13
+ event_alert: 'event alert'
14
+ }
15
+
16
+ attr_reader :name
17
+ attr_reader :attributes
18
+
19
+ # @param [String] name
20
+ # @return [String]
21
+ def initialize(name)
22
+ @attributes = OpenStruct.new
23
+ @name = name
24
+ end
25
+
26
+ # @param [Symbol] type
27
+ # @return [String]
28
+ def type(type)
29
+ @attributes.type = TYPE_MAP[type]
30
+ end
31
+
32
+ # @param [String] query
33
+ # @return [String]
34
+ def query(query)
35
+ @attributes.query = query.to_s
36
+ end
37
+
38
+ # @param [String] message
39
+ # @return [String]
40
+ def message(message)
41
+ @attributes.message = message.to_s
42
+ end
43
+
44
+ # @param [Array] tags
45
+ # @return [Array]
46
+ def tags(tags)
47
+ @attributes.tags = tags.to_a
48
+ end
49
+
50
+ # @param [Proc] block
51
+ # @return [Hash]
52
+ def options(&block)
53
+ opts = DogWatch::Model::Options.new
54
+ opts.instance_eval(&block)
55
+ @attributes.options = opts.render
56
+ end
57
+
58
+ # @return [TrueClass|FalseClass]
59
+ def validate
60
+ return false unless TYPE_MAP.value?(@attributes.type)
61
+ return true unless @attributes.type.nil? || @attributes.type.empty? ||
62
+ @attributes.query.nil? || @attributes.query.empty?
63
+
64
+ false
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,60 @@
1
+ require 'ostruct'
2
+
3
+ module DogWatch
4
+ module Model
5
+ ##
6
+ # Handles the options block methods
7
+ ##
8
+ class Options
9
+ attr_reader :attributes
10
+
11
+ def initialize
12
+ @attributes = OpenStruct.new
13
+ end
14
+
15
+ def render
16
+ @attributes.each_pair.to_h
17
+ end
18
+
19
+ # @param [Hash] args
20
+ def silenced(args)
21
+ @attributes.silenced = args.to_h
22
+ end
23
+
24
+ # @param [Boolean] notify
25
+ def notify_no_data(notify = false)
26
+ @attributes.notify_no_data = !!notify
27
+ end
28
+
29
+ # @param [Integer] minutes
30
+ def no_data_timeframe(minutes)
31
+ @attributes.no_data_timeframe = minutes.to_i
32
+ end
33
+
34
+ # @param [Integer] hours
35
+ def timeout_h(hours)
36
+ @attributes.timeout_h = hours.to_i
37
+ end
38
+
39
+ # @param [Integer] minutes
40
+ def renotify_interval(minutes)
41
+ @attributes.renotify_interval = minutes.to_i
42
+ end
43
+
44
+ # @param [String] message
45
+ def escalation_message(message)
46
+ @attributes.escalation_message = message.to_s
47
+ end
48
+
49
+ # @param [Boolean] notify
50
+ def notify_audit(notify = false)
51
+ @attributes.notify_audit = !!notify
52
+ end
53
+
54
+ # @param [Boolean] include
55
+ def include_tags(include = true)
56
+ @attributes.include_tags = !!include
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,62 @@
1
+ require_relative 'mixin/colorize'
2
+
3
+ module DogWatch
4
+ module Model
5
+ ##
6
+ # Takes DataDog client responses and formats them nicely
7
+ ##
8
+ class Response
9
+ extend Mixin::Colorize
10
+
11
+ ERROR = '400'
12
+ CREATED = '200'
13
+ ACCEPTED = '202'
14
+ colorize(:action,
15
+ :green => [:created, :accepted, :updated],
16
+ :yellow => [],
17
+ :red => [:error]
18
+ )
19
+
20
+ attr_accessor :response
21
+
22
+ def initialize(response, updated = false)
23
+ @response = response
24
+ @updated = updated
25
+ end
26
+
27
+ def status
28
+ return :updated if @updated == true
29
+ return :created if created?
30
+ return :error if failed?
31
+ return :accepted if accepted?
32
+ end
33
+
34
+ def message
35
+ attrs = @response[1]
36
+ return attrs['errors'] if attrs.key?('errors')
37
+ "#{status.to_s.capitalize} monitor #{attrs['name']}"\
38
+ " with message #{attrs['message']}"
39
+ end
40
+
41
+ def to_thor
42
+ action = status
43
+ text = message
44
+ [action, text, color]
45
+ end
46
+
47
+ private
48
+
49
+ def accepted?
50
+ @response[0] == ACCEPTED ? true : false
51
+ end
52
+
53
+ def created?
54
+ @response[0] == CREATED ? true : false
55
+ end
56
+
57
+ def failed?
58
+ @response[0] == ERROR ? true : false
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,51 @@
1
+ require_relative 'model/client'
2
+ require_relative 'model/monitor'
3
+
4
+ module DogWatch
5
+ ##
6
+ # Provides a container around each monitor block
7
+ ##
8
+ class Monitor
9
+ attr_reader :client
10
+ attr_reader :responses
11
+ attr_accessor :config
12
+
13
+ # @param [String] name
14
+ # @param [Proc] block
15
+ # @return [DogWatch::Model::Monitor]
16
+ def initialize(name = nil, &block)
17
+ @name = name
18
+ @monitors = []
19
+ @config = nil
20
+ instance_exec(&block)
21
+ end
22
+
23
+ # @param [String] name
24
+ # @param [Proc] block
25
+ # @return [Array]
26
+ def monitor(name, &block)
27
+ monitor = DogWatch::Model::Monitor.new(name)
28
+ monitor.instance_eval(&block)
29
+ @monitors << monitor
30
+ end
31
+
32
+ # @return [Array]
33
+ def get
34
+ @responses = @monitors.map do |m|
35
+ if m.validate
36
+ @client.execute(m)
37
+ else
38
+ # Need somewhere to inject local errors such as if the request
39
+ # was never sent because the type or query wasn't supplied.
40
+ res = ['400', { 'errors' => ['The DogWatch monitor is invalid.'] }]
41
+ DogWatch::Model::Response.new(res)
42
+ end
43
+ end
44
+ end
45
+
46
+ # @return [DogWatch::Model::Client]
47
+ def client(client = nil)
48
+ @client = client.nil? ? DogWatch::Model::Client.new(@config) : client
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,6 @@
1
+ # nodoc
2
+ module DogWatch
3
+ VERSION = IO.read(File.expand_path('../../../VERSION', __FILE__)) rescue '0.0.1'
4
+ SUMMARY = 'A DSL to create DataDog Monitors'
5
+ DESCRIPTION = IO.read(File.expand_path('../../../README.md', __FILE__)) rescue ''
6
+ end
@@ -0,0 +1,58 @@
1
+ [
2
+ "200",
3
+ [
4
+ {
5
+ "created_at": 1440168271000,
6
+ "creator": {
7
+ "email": "sperson@rapid7.com",
8
+ "handle": "sperson@rapid7.com",
9
+ "id": 10000,
10
+ "name": "Some Person"
11
+ },
12
+ "id": 123456,
13
+ "message": "Some message",
14
+ "multi": false,
15
+ "name": "Monitor name",
16
+ "options": {
17
+ "no_data_timeframe": 2,
18
+ "notify_audit": false,
19
+ "notify_no_data": false,
20
+ "renotify_interval": 0,
21
+ "silenced": {},
22
+ "timeout_h": 0
23
+ },
24
+ "org_id": 12345,
25
+ "overall_state": "OK",
26
+ "query": "Some query",
27
+ "tags": [],
28
+ "type": "event alert"
29
+ },
30
+ {
31
+ "created_at": 1436300628000,
32
+ "creator": {
33
+ "email": "sperson@rapid7.com",
34
+ "handle": "sperson@rapid7.com",
35
+ "id": 10000,
36
+ "name": "Some Person"
37
+ },
38
+ "id": 234567,
39
+ "message": "Some message",
40
+ "multi": false,
41
+ "name": "Second monitor name",
42
+ "options": {
43
+ "escalation_message": "Oh noes!",
44
+ "no_data_timeframe": 2,
45
+ "notify_audit": true,
46
+ "notify_no_data": true,
47
+ "renotify_interval": 10,
48
+ "silenced": {},
49
+ "timeout_h": 1
50
+ },
51
+ "org_id": 12345,
52
+ "overall_state": "OK",
53
+ "query": "avg(last_1m):avg:system.cpu.user{region:us-east-1} > 20",
54
+ "tags": [],
55
+ "type": "metric alert"
56
+ }
57
+ ]
58
+ ]
@@ -0,0 +1,22 @@
1
+ ERROR_RES = [
2
+ '400',
3
+ { 'errors' => ["The value provided for parameter 'query' is invalid"] }
4
+ ]
5
+ VALID_RES = [
6
+ '200',
7
+ {
8
+ 'name' => 'foobar',
9
+ 'query' => 'some query',
10
+ 'message' => 'foobar',
11
+ 'id' => 1_234_567
12
+ }
13
+ ]
14
+ ACCEPTED_RES = [
15
+ '202',
16
+ {
17
+ 'name' => 'foobar',
18
+ 'query' => 'some query',
19
+ 'message' => 'foobar',
20
+ 'id' => 1_234_567
21
+ }
22
+ ]
@@ -0,0 +1,66 @@
1
+ require_relative '../test_helper'
2
+ require_relative '../../lib/dogwatch/model/client'
3
+ require_relative '../../lib/dogwatch/model/config'
4
+ require_relative '../../lib/dogwatch/model/monitor'
5
+ require 'dogapi'
6
+ require 'json'
7
+
8
+ class TestClient < Minitest::Test
9
+ TEST_RESPONSE = [
10
+ '200',
11
+ [
12
+ name: 'test monitor',
13
+ type: 'metric alert',
14
+ query: 'test query'
15
+ ]
16
+ ]
17
+
18
+ UPDATED_RESPONSE = [
19
+ '200',
20
+ [
21
+ name: 'Monitor name',
22
+ type: :metric_alert,
23
+ query: 'scheduled maintenance query'
24
+ ]
25
+ ]
26
+
27
+ def setup
28
+ config = DogWatch::Model::Config.new('foo', 'bar')
29
+
30
+ m = monitors
31
+ k = Class.new(DogWatch::Model::Client) do
32
+ define_method(:all_monitors) do
33
+ m[1]
34
+ end
35
+ end
36
+ @client = k.new(config)
37
+ end
38
+
39
+ def monitors
40
+ monitor_file = File.expand_path('../../data/monitors.json', __FILE__)
41
+ monitors = JSON.parse(IO.read(monitor_file))
42
+ monitors
43
+ end
44
+
45
+ def test_create_monitor
46
+ new_monitor = DogWatch::Model::Monitor.new('test monitor')
47
+ new_monitor.type(:metric_alert)
48
+ new_monitor.query('test query')
49
+
50
+ @client.client.stub :monitor, TEST_RESPONSE do
51
+ @client.execute(new_monitor)
52
+ assert_equal @client.response.status, :created
53
+ end
54
+ end
55
+
56
+ def test_update_monitor
57
+ update_monitor = DogWatch::Model::Monitor.new('Monitor name')
58
+ update_monitor.type(:metric_alert)
59
+ update_monitor.query('scheduled maintenance query')
60
+
61
+ @client.client.stub :update_monitor, UPDATED_RESPONSE do
62
+ @client.execute(update_monitor)
63
+ assert_equal @client.response.status, :updated
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../test_helper'
2
+ require_relative '../../lib/dogwatch/model/mixin/colorize'
3
+
4
+ class ToColor
5
+ extend DogWatch::Model::Mixin::Colorize
6
+
7
+ colorize(:action,
8
+ :green => [:created, :accepted, :updated],
9
+ :yellow => [],
10
+ :red => [:error])
11
+ end
12
+
13
+ class TestColorize < Minitest::Test
14
+ def setup
15
+ @tocolor = ToColor.new
16
+ end
17
+
18
+ def test_colorize_default
19
+ assert_equal :green, @tocolor.color
20
+ end
21
+ end