doggy 0.2.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,93 +0,0 @@
1
- module Doggy
2
- class Dash
3
- def self.upload_all
4
- objects = Doggy.all_local_items.find_all { |(type, id), object| type == 'dash' }
5
- puts "Uploading #{objects.size} dashboards"
6
- upload(objects.map { |(type, id), object| id })
7
- rescue => e
8
- puts "Exception: #{e.message}"
9
- end
10
-
11
- def self.download(ids)
12
- Doggy::Worker.new(threads: Doggy::Worker::CONCURRENT_STREAMS) { |id| new(id: id).save }.call([*ids])
13
- end
14
-
15
- def self.upload(ids)
16
- Doggy::Worker.new(threads: Doggy::Worker::CONCURRENT_STREAMS) { |id| new(id: id).push }.call([*ids])
17
- end
18
-
19
- def self.edit(id)
20
- system %{open "https://app.datadoghq.com/dash/#{id}"}
21
- if SharedHelpers.agree("Are you done?")
22
- puts 'Here is the output of your edit:'
23
- puts Doggy::Serializer::Json.dump(new(id: id).raw)
24
- else
25
- puts "run, rabbit run / dig that hole, forget the sun / and when at last the work is done / don't sit down / it's time to dig another one"
26
- edit(id)
27
- end
28
- end
29
-
30
- def initialize(**options)
31
- @id = options[:id]
32
- @title = options[:title] || raw_local['title']
33
- @description = options[:description] || raw_local['description']
34
- @graphs = options[:graphs] || raw_local['graphs']
35
- @template_variables = options[:template_variables] || raw_local['template_variables']
36
- end
37
-
38
- def raw
39
- @raw ||= begin
40
- status, result = Doggy.client.dog.get_dashboard(@id)
41
- result && result['dash'] && result['dash'].sort.to_h || {}
42
- end
43
- end
44
-
45
- def raw_local
46
- return {} unless File.exists?(path)
47
- @raw_local ||= begin
48
- object = Doggy.serializer.load(File.read(path))
49
- object['dash'] ? object['dash'] : object
50
- end
51
- end
52
-
53
- def save
54
- return if raw.nil? || raw.empty? # do not save if it's empty
55
- return if raw['errors'] # do not save if there are any errors
56
- return if raw['title'] =~ Doggy::DOG_SKIP_REGEX # do not save if it had skip tag in title
57
-
58
- File.write(path, Doggy.serializer.dump(raw))
59
- end
60
-
61
- def push
62
- return unless File.exists?(path)
63
- return if @title =~ Doggy::DOG_SKIP_REGEX
64
- return unless Doggy.determine_type(raw_local) == 'dash'
65
-
66
- # Managed by doggy (TM)
67
- @title = @title =~ MANAGED_BY_DOGGY_REGEX ? @title : @title + " 🐶"
68
-
69
- if @id
70
- SharedHelpers.with_retry do
71
- Doggy.client.dog.update_dashboard(@id, @title, @description, @graphs, @template_variables)
72
- end
73
- else
74
- SharedHelpers.with_retry do
75
- dash = Doggy.client.dog.create_dashboard(@title, @description, @graphs)
76
- end
77
- # FIXME: Remove duplication
78
- @id = dash[1]['id']
79
- @graphs = dash[1]['graphs']
80
- end
81
- end
82
-
83
- def delete
84
- Doggy.client.dog.delete_dashboard(@id)
85
- end
86
-
87
- private
88
-
89
- def path
90
- "#{Doggy.objects_path}/#{@id}.json"
91
- end
92
- end
93
- end
@@ -1,142 +0,0 @@
1
- module Doggy
2
- class Monitor
3
- def self.upload_all
4
- objects = Doggy.all_local_items.find_all { |(type, id), object| type == 'monitor' }
5
- puts "Uploading #{objects.size} monitors"
6
- upload(objects.map { |(type, id), object| id })
7
- rescue => e
8
- puts "Exception: #{e.message}"
9
- end
10
-
11
- def self.download(ids)
12
- Doggy::Worker.new(threads: Doggy::Worker::CONCURRENT_STREAMS) { |id| new(id: id).save }.call([*ids])
13
- end
14
-
15
- def self.upload(ids)
16
- Doggy::Worker.new(threads: Doggy::Worker::CONCURRENT_STREAMS) { |id| new(id: id).push }.call([*ids])
17
- end
18
-
19
- def self.mute(ids)
20
- Doggy::Worker.new(threads: Doggy::Worker::CONCURRENT_STREAMS) { |id| new(id: id).mute }.call([*ids])
21
- end
22
-
23
- def self.unmute(ids)
24
- Doggy::Worker.new(threads: Doggy::Worker::CONCURRENT_STREAMS) { |id| new(id: id).unmute }.call([*ids])
25
- end
26
-
27
- def self.edit(id)
28
- system %{open "https://app.datadoghq.com/monitors##{id}"}
29
- if SharedHelpers.agree("Are you done?")
30
- puts 'Here is the output of your edit:'
31
- puts Doggy::Serializer::Json.dump(new(id: id).raw)
32
- else
33
- puts "run, rabbit run / dig that hole, forget the sun / and when at last the work is done / don't sit down / it's time to dig another one"
34
- edit(id)
35
- end
36
- end
37
-
38
- def initialize(**options)
39
- @id = options[:id]
40
- @query = options[:query]
41
- @silenced = options[:silenced]
42
- @name = options[:name]
43
- @timeout_h = options[:timeout_h]
44
- @message = options[:message]
45
- @notify_audit = options[:notify_audit]
46
- @notify_no_data = options[:notify_no_data]
47
- @renotify_interval = options[:renotify_interval]
48
- @escalation_message = options[:escalation_message]
49
- @no_data_timeframe = options[:no_data_timeframe]
50
- @silenced_timeout_ts = options[:silenced_timeout_ts]
51
- end
52
-
53
- def raw
54
- @raw ||= begin
55
- status, alert = Doggy.client.dog.get_monitor(@id)
56
-
57
- return if status != '200'
58
-
59
- alert.delete('state') # delete unnecessary state
60
- alert.delete('overall_state') # delete unnecessary state
61
- if alert['options']
62
- alert['options'].delete('silenced') # delete unnecessary state
63
- alert['options'] = alert['options'].sort.to_h # sort option keys; DataDog response is not ordered
64
- end
65
- alert && alert.sort.to_h
66
- end
67
- end
68
-
69
- def raw_local
70
- return unless File.exists?(path)
71
- @raw_local ||= Doggy.serializer.load(File.read(path))
72
- end
73
-
74
- def save
75
- return if raw.nil? || raw.empty? # do not save if it's empty
76
- return if raw['errors'] # do not save if there are any errors
77
- return if raw['name'] =~ Doggy::DOG_SKIP_REGEX # do not save if it had skip tag in title
78
-
79
- File.write(path, Doggy.serializer.dump(raw))
80
- end
81
-
82
- def mute
83
- Doggy.client.dog.mute_monitor(@id)
84
- end
85
-
86
- def unmute
87
- Doggy.client.dog.unmute_monitor(@id)
88
- end
89
-
90
- def push
91
- @name ||= raw_local['name']
92
-
93
- return if @name =~ Doggy::DOG_SKIP_REGEX
94
- return unless Doggy.determine_type(raw_local) == 'monitor'
95
-
96
- # Managed by doggy (TM)
97
- @name = @name =~ MANAGED_BY_DOGGY_REGEX ? @name : @name + " 🐶"
98
-
99
- if @id
100
- return unless File.exists?(path)
101
-
102
- SharedHelpers.with_retry do
103
- Doggy.client.dog.update_monitor(@id, @query || raw_local['query'], {
104
- name: @name || raw_local['name'],
105
- timeout_h: @timeout_h || raw_local['timeout_h'],
106
- message: @message || raw_local['message'],
107
- notify_audit: @notify_audit || raw_local['notify_audit'],
108
- notify_no_data: @notify_no_data || raw_local['notify_no_data'],
109
- renotify_interval: @renotify_interval || raw_local['renotify_interval'],
110
- escalation_message: @escalation_message || raw_local['escalation_message'],
111
- no_data_timeframe: @no_data_timeframe || raw_local['no_data_timeframe'],
112
- silenced_timeout_ts: @silenced_timeout_ts || raw_local['silenced_timeout_ts'],
113
- options: {
114
- silenced: mute_state_for(@id),
115
- },
116
- })
117
- end
118
- else
119
- SharedHelpers.with_retry do
120
- result = Doggy.client.dog.monitor('metric alert', @query, name: @name)
121
- end
122
- @id = result[1]['id']
123
- end
124
- end
125
-
126
- def delete
127
- Doggy.client.dog.delete_alert(@id)
128
- end
129
-
130
- private
131
-
132
- def path
133
- "#{Doggy.objects_path}/#{@id}.json"
134
- end
135
-
136
- def mute_state_for(id)
137
- if remote_state = Doggy.all_local_items.detect { |key, value| key == [ 'monitor', id.to_i ] }
138
- remote_state[1]['options']['silenced'] if remote_state[1]['options']
139
- end
140
- end
141
- end
142
- end
@@ -1,80 +0,0 @@
1
- module Doggy
2
- class Screen
3
- def self.upload_all
4
- objects = Doggy.all_local_items.find_all { |(type, id), object| type == 'screen' }
5
- puts "Uploading #{objects.size} screens"
6
- upload(objects.map { |(type, id), object| id })
7
- rescue => e
8
- puts "Exception: #{e.message}"
9
- end
10
-
11
- def self.download(ids)
12
- Doggy::Worker.new(threads: Doggy::Worker::CONCURRENT_STREAMS) { |id| new(id: id).save }.call([*ids])
13
- end
14
-
15
- def self.upload(ids)
16
- Doggy::Worker.new(threads: Doggy::Worker::CONCURRENT_STREAMS) { |id| new(id: id).push }.call([*ids])
17
- end
18
-
19
- def self.edit(id)
20
- system %{open "https://app.datadoghq.com/screen/#{id}"}
21
- if SharedHelpers.agree("Are you done?")
22
- puts 'Here is the output of your edit:'
23
- puts Doggy::Serializer::Json.dump(new(id: id).raw)
24
- else
25
- puts "run, rabbit run / dig that hole, forget the sun / and when at last the work is done / don't sit down / it's time to dig another one"
26
- edit(id)
27
- end
28
- end
29
-
30
- def initialize(**options)
31
- @id = options[:id]
32
- @description = options[:description] || raw_local
33
- end
34
-
35
- def raw
36
- @raw ||= begin
37
- status, result = Doggy.client.dog.get_screenboard(@id)
38
- result && result.sort.to_h
39
- end
40
- end
41
-
42
- def raw_local
43
- return {} unless File.exists?(path)
44
- @raw_local ||= Doggy.serializer.load(File.read(path))
45
- end
46
-
47
- def save
48
- return if raw['errors'] # do now download an item if it doesn't exist
49
- return if raw['board_title'] =~ Doggy::DOG_SKIP_REGEX
50
- return if raw.empty?
51
- File.write(path, Doggy.serializer.dump(raw))
52
- end
53
-
54
- def push
55
- return if @description =~ Doggy::DOG_SKIP_REGEX
56
- return unless Doggy.determine_type(raw_local) == 'screen'
57
- if @id
58
- SharedHelpers.with_retry do
59
- Doggy.client.dog.update_screenboard(@id, @description)
60
- end
61
- else
62
- SharedHelpers.with_retry do
63
- result = Doggy.client.dog.create_screenboard(@description)
64
- end
65
- @id = result[1]['id']
66
- @description = result[1]
67
- end
68
- end
69
-
70
- def delete
71
- Doggy.client.dog.delete_screenboard(@id)
72
- end
73
-
74
- private
75
-
76
- def path
77
- "#{Doggy.objects_path}/#{@id}.json"
78
- end
79
- end
80
- end
@@ -1,15 +0,0 @@
1
- module Doggy
2
- module Serializer
3
- class Json
4
- # De-serialize a Hash from JSON string
5
- def self.load(string)
6
- ::JSON.load(string)
7
- end
8
-
9
- # Serialize a Hash to JSON string
10
- def self.dump(object, options = {})
11
- ::JSON.pretty_generate(object, options) + "\n"
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- module Doggy
2
- module Serializer
3
- class Yaml
4
- # De-serialize a Hash from YAML string
5
- def self.load(string)
6
- ::YAML.load(string)
7
- end
8
-
9
- # Serialize a Hash to YAML string
10
- def self.dump(object, options = {})
11
- ::YAML.dump(object, options)
12
- end
13
- end
14
- end
15
- end
@@ -1,63 +0,0 @@
1
- module Doggy
2
- module SharedHelpers
3
- MAX_TRIES = 5
4
-
5
- def self.strip_heredoc(string)
6
- indent = string.scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
7
- string.gsub(/^[ \t]{#{indent}}/, '')
8
- end
9
-
10
- def self.with_retry(times: MAX_TRIES, reraise: false)
11
- tries = 0
12
- while tries < times
13
- begin
14
- yield
15
- break
16
- rescue => e
17
- error "Caught error! Attempt #{tries}..."
18
- error "#{e.class.name}: #{e.message}"
19
- error "#{e.backtrace.join("\n")}"
20
- tries += 1
21
-
22
- raise e if tries >= times && reraise
23
- end
24
- end
25
- end
26
-
27
- def self.agree(prompt)
28
- raise Error, "Not a tty" unless $stdin.tty?
29
-
30
- puts prompt + " (Y/N)"
31
- line = $stdin.readline.chomp.upcase
32
- puts
33
- line == "Y"
34
- end
35
-
36
- def self.error(msg)
37
- puts "[ERROR] #{ msg }"
38
- end
39
-
40
- def self.find_root
41
- File.dirname(find_file("Gemfile"))
42
- end
43
-
44
- def self.find_file(*names)
45
- search_up(*names) do |filename|
46
- return filename if File.file?(filename)
47
- end
48
- end
49
-
50
- def self.search_up(*names)
51
- previous = nil
52
- current = File.expand_path(Pathname.pwd)
53
-
54
- until !File.directory?(current) || current == previous
55
- names.each do |name|
56
- filename = File.join(current, name)
57
- yield filename
58
- end
59
- current, previous = File.expand_path("..", current), current
60
- end
61
- end
62
- end
63
- end
@@ -1,31 +0,0 @@
1
- require 'thread'
2
- require 'thread/pool'
3
-
4
- Thread.abort_on_exception = true
5
-
6
- module Doggy
7
- class Worker
8
- # Spawn 10 threads for HTTP requests.
9
- CONCURRENT_STREAMS = 10
10
-
11
- def initialize(options = {}, &runner)
12
- @runner = runner
13
- @threads = options.fetch(:threads)
14
- end
15
-
16
- def call(jobs)
17
- results = []
18
- pool = Thread::Pool.new(@threads)
19
- tasks = jobs.map { |job|
20
- pool.process {
21
- results << [ job, @runner.call(job) ]
22
- }
23
- }
24
- pool.shutdown
25
- if task_with_errors = tasks.detect { |task| task.exception }
26
- raise task_with_errors.exception
27
- end
28
- results
29
- end
30
- end
31
- end