kennel 1.101.0 → 1.103.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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