kennel 1.101.0 → 1.103.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 11220aba046ce1fbc63b8b62e5a60f0cbd4b04862ff7394c0ad43a1776bc34a6
4
- data.tar.gz: 257808a3036f97c8b994c35ce0c4c621bafd1a29a43da0cba6c113a9fe8297ff
3
+ metadata.gz: bee3140dd0001488c0ec264244c7a28b30f3a5f877db23438884afca5181aef5
4
+ data.tar.gz: eb0071ea0aac8be39f1517738093fd61a211cb65e61ccb1f457030b999a58487
5
5
  SHA512:
6
- metadata.gz: 1bcd69ba301375d93c1c72f9cb1ffcf057e06d4aa3f604baada0ed4dce5cd0d4e7675227d9d4ef8f09a80198bc3e14268fcdb4cd1f3623d3a810818bbbe6d4b2
7
- data.tar.gz: c189ecb33b4800d9d0e382f82fedbcfa8723f3ff0a27bbd2554528de60d50f774309da9d30c27374ae3365863861f81fae438d4843a34519c4d0a044a4d250ce
6
+ metadata.gz: 442611b5ef920684f95c698e654a53c3c367fc6c48a8def218dd40d130dba349ab512e880e88c7d9c0fb7634887bb78b40381314a81a2457a393301cee169b18
7
+ data.tar.gz: a26df226bd670a252539b4001401cb2d3dc9e32883fc2811b36cb01b26a6a9c23bc5da970c68b71cdac174432f7d4e2df5643b4a893adc9a85ce8908dcbf14e6
data/lib/kennel/id_map.rb CHANGED
@@ -15,10 +15,6 @@ module Kennel
15
15
  @map[type][tracking_id] = id
16
16
  end
17
17
 
18
- def set_new(type, tracking_id)
19
- @map[type][tracking_id] = NEW
20
- end
21
-
22
18
  def new?(type, tracking_id)
23
19
  @map[type][tracking_id] == NEW
24
20
  end
@@ -137,7 +137,7 @@ module Kennel
137
137
  pretty = convert_strings_to_heredoc(pretty)
138
138
 
139
139
  "\n#{pretty}\n "
140
- elsif k == :message
140
+ elsif [:message, :description].include?(k)
141
141
  "\n <<~TEXT\n#{v.each_line.map { |l| l.strip.empty? ? "\n" : " #{l}" }.join}\n \#{super()}\n TEXT\n "
142
142
  elsif k == :tags
143
143
  " super() + #{v.inspect} "
data/lib/kennel/syncer.rb CHANGED
@@ -3,7 +3,6 @@ module Kennel
3
3
  class Syncer
4
4
  DELETE_ORDER = ["dashboard", "slo", "monitor", "synthetics/tests"].freeze # dashboards references monitors + slos, slos reference monitors
5
5
  LINE_UP = "\e[1A\033[K" # go up and clear
6
- DEFAULT_BRANCH = "master"
7
6
 
8
7
  def initialize(api, expected, project: nil)
9
8
  @api = api
@@ -18,6 +17,7 @@ module Kennel
18
17
  if noop?
19
18
  Kennel.out.puts Utils.color(:green, "Nothing to do")
20
19
  else
20
+ @warnings.each { |message| Kennel.out.puts Utils.color(:yellow, "Warning: #{message}") }
21
21
  print_plan "Create", @create, :green
22
22
  print_plan "Update", @update, :yellow
23
23
  print_plan "Delete", @delete, :red
@@ -27,7 +27,6 @@ module Kennel
27
27
  def confirm
28
28
  return false if noop?
29
29
  return true if ENV["CI"] || !STDIN.tty?
30
- warn_about_deleting_resources_with_id if @project_filter
31
30
  Utils.ask("Execute Plan ?")
32
31
  end
33
32
 
@@ -60,30 +59,6 @@ module Kennel
60
59
 
61
60
  private
62
61
 
63
- # this is brittle/hacky since it relies on knowledge from the generation + git + branch knowledge
64
- def warn_about_deleting_resources_with_id
65
- @delete.each do |_, _, a|
66
- tracking_id = a.fetch(:tracking_id)
67
- api_resource = a.fetch(:klass).api_resource
68
-
69
- file = "generated/#{tracking_id.sub(":", "/")}.json"
70
- old = `true && git show #{DEFAULT_BRANCH}:#{file.shellescape} 2>&1` # true && to not crash on missing git
71
-
72
- next unless $?.success?
73
- old =
74
- begin
75
- JSON.parse(old)
76
- rescue StandardError
77
- false
78
- end
79
- next if !old || !old["id"]
80
-
81
- Kennel.out.puts(
82
- Utils.color(:red, "WARNING: deleting #{api_resource} #{tracking_id} will break #{DEFAULT_BRANCH} branch")
83
- )
84
- end
85
- end
86
-
87
62
  # loop over items until everything is resolved or crash when we get stuck
88
63
  # this solves cases like composite monitors depending on each other or monitor->monitor slo->slo monitor chains
89
64
  def each_resolved(list)
@@ -120,6 +95,7 @@ module Kennel
120
95
  end
121
96
 
122
97
  def calculate_diff
98
+ @warnings = []
123
99
  @update = []
124
100
  @delete = []
125
101
  @id_map = IdMap.new
@@ -181,7 +157,11 @@ module Kennel
181
157
  @expected.each do |e|
182
158
  next unless id = e.id
183
159
  resource = e.class.api_resource
184
- raise "Unable to find existing #{resource} with id #{id}\nIf the #{resource} was deleted, remove the `id: -> { #{e.id} }` line."
160
+ if Kennel.strict_imports
161
+ raise "Unable to find existing #{resource} with id #{id}\nIf the #{resource} was deleted, remove the `id: -> { #{id} }` line."
162
+ else
163
+ @warnings << "#{resource} #{e.tracking_id} specifies id #{id}, but no such #{resource} exists. 'id' will be ignored. Remove the `id: -> { #{id} }` line."
164
+ end
185
165
  end
186
166
  end
187
167
 
@@ -254,15 +234,28 @@ module Kennel
254
234
  end
255
235
 
256
236
  def populate_id_map(expected, actual)
237
+ # mark everything as new
257
238
  expected.each do |e|
258
- @id_map.set_new(e.class.api_resource, e.tracking_id)
239
+ @id_map.set(e.class.api_resource, e.tracking_id, IdMap::NEW)
240
+ if e.class.api_resource == "synthetics/tests"
241
+ @id_map.set(Kennel::Models::Monitor.api_resource, e.tracking_id, IdMap::NEW)
242
+ end
259
243
  end
260
244
 
245
+ # override resources that exist with their id
246
+ project_prefix = @project_filter && "#{@project_filter}:"
261
247
  actual.each do |a|
248
+ # ignore when not managed by kennel
262
249
  next unless tracking_id = a.fetch(:tracking_id)
263
- next unless @id_map.get(a.fetch(:klass).api_resource, tracking_id)
264
250
 
265
- @id_map.set(a.fetch(:klass).api_resource, tracking_id, a.fetch(:id))
251
+ # ignore when deleted from the codebase
252
+ # (when running with project filter we cannot see the other resources in the codebase)
253
+ api_resource = a.fetch(:klass).api_resource
254
+ next if
255
+ !@id_map.get(api_resource, tracking_id) &&
256
+ (!project_prefix || tracking_id.start_with?(project_prefix))
257
+
258
+ @id_map.set(api_resource, tracking_id, a.fetch(:id))
266
259
  if a[:klass].api_resource == "synthetics/tests"
267
260
  @id_map.set(Kennel::Models::Monitor.api_resource, tracking_id, a.fetch(:monitor_id))
268
261
  end
data/lib/kennel/tasks.rb CHANGED
@@ -3,6 +3,7 @@ require "English"
3
3
  require "kennel"
4
4
  require "kennel/unmuted_alerts"
5
5
  require "kennel/importer"
6
+ require "json"
6
7
 
7
8
  module Kennel
8
9
  module Tasks
@@ -75,6 +76,7 @@ namespace :kennel do
75
76
  is_push = (ENV["TRAVIS_PULL_REQUEST"] == "false" || ENV["GITHUB_EVENT_NAME"] == "push")
76
77
  task_name =
77
78
  if on_default_branch && is_push
79
+ Kennel.strict_imports = false
78
80
  "kennel:update_datadog"
79
81
  else
80
82
  "kennel:plan" # show plan in CI logs
@@ -89,7 +91,7 @@ namespace :kennel do
89
91
  Kennel::UnmutedAlerts.print(Kennel.send(:api), tag)
90
92
  end
91
93
 
92
- desc "show monitors with no data by TAG, for example TAG=team:foo"
94
+ desc "show monitors with no data by TAG, for example TAG=team:foo [THRESHOLD_DAYS=7] [FORMAT=json]"
93
95
  task nodata: :environment do
94
96
  tag = ENV["TAG"] || Kennel::Tasks.abort("Call with TAG=foo:bar")
95
97
  monitors = Kennel.send(:api).list("monitor", monitor_tags: tag, group_states: "no data")
@@ -97,16 +99,45 @@ namespace :kennel do
97
99
  monitors.reject! { |m| m[:tags].include? "nodata:ignore" }
98
100
  if monitors.any?
99
101
  Kennel.err.puts <<~TEXT
100
- This is a useful task to find monitors that have mis-spelled metrics or never received data at any time.
101
- To ignore monitors with nodata, tag the monitor with "nodata:ignore"
102
+ To ignore monitors with expected nodata, tag it with "nodata:ignore"
102
103
 
103
104
  TEXT
104
105
  end
105
106
 
107
+ now = Time.now
106
108
  monitors.each do |m|
107
- Kennel.out.puts m[:name]
108
- Kennel.out.puts Kennel::Utils.path_to_url("/monitors/#{m[:id]}")
109
- Kennel.out.puts
109
+ m[:days_in_no_data] =
110
+ if m[:overall_state_modified]
111
+ since = Date.parse(m[:overall_state_modified]).to_time
112
+ ((now - since) / (24 * 60 * 60)).to_i
113
+ else
114
+ 999
115
+ end
116
+ end
117
+
118
+ if threshold = ENV["THRESHOLD_DAYS"]
119
+ monitors.select! { |m| m[:days_in_no_data] > Integer(threshold) }
120
+ end
121
+
122
+ monitors.each { |m| m[:url] = Kennel::Utils.path_to_url("/monitors/#{m[:id]}") }
123
+
124
+ if ENV["FORMAT"] == "json"
125
+ report = monitors.map do |m|
126
+ match = m[:message].to_s.match(/-- Managed by kennel (\S+:\S+) in (\S+), /) || []
127
+ m.slice(:url, :name, :tags, :days_in_no_data).merge(
128
+ kennel_tracking_id: match[1],
129
+ kennel_source: match[2]
130
+ )
131
+ end
132
+
133
+ Kennel.out.puts JSON.pretty_generate(report)
134
+ else
135
+ monitors.each do |m|
136
+ Kennel.out.puts m[:name]
137
+ Kennel.out.puts Kennel::Utils.path_to_url("/monitors/#{m[:id]}")
138
+ Kennel.out.puts "No data since #{m[:days_in_no_data]}d"
139
+ Kennel.out.puts
140
+ end
110
141
  end
111
142
  end
112
143
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.101.0"
3
+ VERSION = "1.103.1"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -2,7 +2,6 @@
2
2
  require "faraday"
3
3
  require "json"
4
4
  require "zeitwerk"
5
- require "shellwords"
6
5
  require "English"
7
6
 
8
7
  require "kennel/version"
@@ -42,9 +41,10 @@ module Kennel
42
41
 
43
42
  @out = $stdout
44
43
  @err = $stderr
44
+ @strict_imports = true
45
45
 
46
46
  class << self
47
- attr_accessor :out, :err
47
+ attr_accessor :out, :err, :strict_imports
48
48
 
49
49
  def generate
50
50
  store generated
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kennel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.101.0
4
+ version: 1.103.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-09 00:00:00.000000000 Z
11
+ date: 2021-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday