datadog_backup 0.10.2 → 0.10.3

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: 54c83b8ce7b212ad43f91a1619363eb683b58cbf7089a24f05b56a5a6a72d250
4
- data.tar.gz: 82986e61ff8d93fed519d03c6b38095cce0c97f0981274bb904d94f7b762e056
3
+ metadata.gz: 5833879f7fbadabad6111eae29c4e487e0d51a0b0802dcd61124985bae70cd23
4
+ data.tar.gz: 5fdc04d6d1bf28671a4a2000a20c6f1513cbf27f406def181550d956cd270d48
5
5
  SHA512:
6
- metadata.gz: ec5087654fd806a8cb562912d460dfbdf7c9e1bdb9d75728ce310b4c0b20ba690b7ccb42584c1c28dc4b5db6ba49cfe46d6cb64ad623e6dfb8939ad07dfed56c
7
- data.tar.gz: 072762f43d59b7727baccbff8a7273a84ab0b0e1fe0fbd1787486d6b1b08faad9b492b39d68a83be90637a09a6f2bbc436f386775b9da4751308253b0ff6bbc8
6
+ metadata.gz: 9cc3623d68ec1e5c5872bda3d2e341c9e5d2b1bb954e16d08a2f4d289adb01751f0b7f3f2b0549bfba2fbf91d5ab86c233b59c74f2124642c4cd52b0074a1824
7
+ data.tar.gz: 9ef0f647d84441c750a65a9cf18130fe89daad15af18ad0e07d61b74caf13ba160388551b4908609bf95a6113f3f39de854b5347becad449fcef0df70782fee2
data/.gitignore CHANGED
@@ -117,3 +117,5 @@ Gemfile.lock
117
117
 
118
118
  spec/helpers/failures.txt
119
119
  backup/
120
+
121
+ .envrc
@@ -1,3 +1,10 @@
1
+ ## [0.10.3](https://github.com/scribd/datadog_backup/compare/v0.10.2...v0.10.3) (2020-12-11)
2
+
3
+
4
+ ### Performance Improvements
5
+
6
+ * coerce patch release ([bc86649](https://github.com/scribd/datadog_backup/commit/bc86649b874cd5be1da2f6bc0d1b1ecd0728676c))
7
+
1
8
  ## [0.10.2](https://github.com/scribd/datadog_backup/compare/v0.10.1...v0.10.2) (2020-11-03)
2
9
 
3
10
 
data/Guardfile CHANGED
@@ -17,7 +17,7 @@
17
17
  #
18
18
  # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
19
19
 
20
- # Note: The cmd option is now required due to the increasing number of ways
20
+ # NOTE: The cmd option is now required due to the increasing number of ways
21
21
  # rspec may be run, below are examples of the most common uses.
22
22
  # * bundler: 'bundle exec rspec'
23
23
  # * bundler binstubs: 'bin/rspec'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
- gem 'datadog_backup', :source => 'https://scribd.jfrog.io/artifactory/gems-local'
5
+ gem 'datadog_backup'
@@ -91,7 +91,7 @@ module DatadogBackup
91
91
  end
92
92
 
93
93
  def matching_resource_instance(klass)
94
- resource_instances.select { |resource_instance| resource_instance.class == klass }.first
94
+ resource_instances.select { |resource_instance| resource_instance.instance_of?(klass) }.first
95
95
  end
96
96
 
97
97
  def resource_instances
@@ -117,7 +117,7 @@ module DatadogBackup
117
117
  exit
118
118
  when 'r'
119
119
  puts "Restoring #{id} to Datadog."
120
- definitive_resource_instance(id).update_with_200(id, definitive_resource_instance(id).load_from_file_by_id(id))
120
+ definitive_resource_instance(id).update(id, definitive_resource_instance(id).load_from_file_by_id(id))
121
121
  when 'd'
122
122
  puts "Downloading #{id} from Datadog."
123
123
  definitive_resource_instance(id).get_and_write_file(id)
@@ -24,55 +24,48 @@ module DatadogBackup
24
24
  raise 'subclass is expected to implement #backup'
25
25
  end
26
26
 
27
- # Calls out to Datadog and checks for a '200' response
28
- def client_with_200(method, *id)
29
- max_retries = 6
30
- retries ||= 0
31
-
32
- response = client.send(method, *id)
33
-
34
- # logger.debug response
35
- raise "Method #{method} failed with error #{response}" unless response[0] == '200'
36
-
37
- response[1]
38
- rescue ::Net::OpenTimeout => e
39
- if (retries += 1) <= max_retries
40
- sleep(0.1 * retries**5) # 0.1, 3.2, 24.3, 102.4 seconds per retry
41
- retry
42
- else
43
- raise "Method #{method} failed with error #{e.message}"
44
- end
45
- end
46
-
47
27
  # Returns the diffy diff.
48
28
  # Optionally, supply an array of keys to remove from comparison
49
- def diff(id, banlist = [])
50
- current = except(get_by_id(id), banlist).deep_sort.to_yaml
51
- filesystem = except(load_from_file_by_id(id), banlist).deep_sort.to_yaml
29
+ def diff(id)
30
+ current = except(get_by_id(id)).deep_sort.to_yaml
31
+ filesystem = except(load_from_file_by_id(id)).deep_sort.to_yaml
52
32
  result = ::Diffy::Diff.new(current, filesystem, include_plus_and_minus_in_html: true).to_s(diff_format)
53
33
  logger.debug("Compared ID #{id} and found #{result}")
54
34
  result
55
35
  end
56
36
 
57
37
  # Returns a hash with banlist elements removed
58
- def except(hash, banlist)
38
+ def except(hash)
59
39
  hash.tap do # tap returns self
60
- banlist.each do |key|
40
+ @banlist.each do |key|
61
41
  hash.delete(key) # delete returns the value at the deleted key, hence the tap wrapper
62
42
  end
63
43
  end
64
44
  end
65
45
 
46
+ def get(id)
47
+ with_200 do
48
+ api_service.request(Net::HTTP::Get, "/api/#{api_version}/#{api_resource_name}/#{id}", nil, nil, false)
49
+ end
50
+ end
51
+
52
+ def get_all
53
+ with_200 do
54
+ api_service.request(Net::HTTP::Get, "/api/#{api_version}/#{api_resource_name}", nil, nil, false)
55
+ end
56
+ end
57
+
66
58
  def get_and_write_file(id)
67
59
  write_file(dump(get_by_id(id)), filename(id))
68
60
  end
69
61
 
70
- def get_by_id(_id)
71
- raise 'subclass is expected to implement #get_by_id(id)'
62
+ def get_by_id(id)
63
+ except(get(id))
72
64
  end
73
65
 
74
66
  def initialize(options)
75
67
  @options = options
68
+ @banlist = []
76
69
  ::FileUtils.mkdir_p(mydir)
77
70
  end
78
71
 
@@ -80,25 +73,20 @@ module DatadogBackup
80
73
  self.class.to_s.split(':').last.downcase
81
74
  end
82
75
 
83
- def restore
84
- raise 'subclass is expected to implement #restore'
85
- end
86
-
76
+ # Calls out to Datadog and checks for a '200' response
87
77
  def update(id, body)
88
- api_service.request(Net::HTTP::Put, "/api/#{api_version}/#{api_resource_name}/#{id}", nil, body, true)
78
+ with_200 do
79
+ api_service.request(Net::HTTP::Put, "/api/#{api_version}/#{api_resource_name}/#{id}", nil, body, true)
80
+ end
81
+ logger.warn 'Successfully restored to datadog.'
89
82
  end
90
83
 
91
- # Calls out to Datadog and checks for a '200' response
92
- def update_with_200(id, body)
84
+ def with_200
93
85
  max_retries = 6
94
86
  retries ||= 0
95
87
 
96
- response = update(id, body)
97
-
98
- # logger.debug response
99
- raise "Update failed with error #{response}" unless response[0] == '200'
100
-
101
- logger.warn "Successfully restored #{id} to datadog."
88
+ response = yield
89
+ raise "Request failed with error #{response}" unless response[0] == '200'
102
90
 
103
91
  response[1]
104
92
  rescue ::Net::OpenTimeout => e
@@ -106,8 +94,9 @@ module DatadogBackup
106
94
  sleep(0.1 * retries**5) # 0.1, 3.2, 24.3, 102.4 seconds per retry
107
95
  retry
108
96
  else
109
- raise "Update failed with error #{e.message}"
97
+ raise "Request failed with error #{e.message}"
110
98
  end
111
99
  end
100
+
112
101
  end
113
102
  end
@@ -2,10 +2,8 @@
2
2
 
3
3
  module DatadogBackup
4
4
  class Dashboards < Core
5
- BANLIST = %w[modified_at url]
6
-
7
5
  def all_boards
8
- client_with_200(:get_all_boards).fetch('dashboards')
6
+ get_all.fetch('dashboards')
9
7
  end
10
8
 
11
9
  def api_service
@@ -37,14 +35,9 @@ module DatadogBackup
37
35
  Concurrent::Promises.zip(*futures).value!
38
36
  end
39
37
 
40
- def diff(id)
41
- super(id, BANLIST)
42
- end
43
-
44
- def get_by_id(id)
45
- except(client_with_200(:get_board, id), BANLIST)
38
+ def initialize(options)
39
+ super(options)
40
+ @banlist = %w[modified_at url].freeze
46
41
  end
47
-
48
- def restore!; end
49
42
  end
50
43
  end
@@ -31,9 +31,10 @@ module DatadogBackup
31
31
  end
32
32
 
33
33
  def dump(object)
34
- if output_format == :json
34
+ case output_format
35
+ when :json
35
36
  JSON.pretty_generate(object.deep_sort)
36
- elsif output_format == :yaml
37
+ when :yaml
37
38
  YAML.dump(object.deep_sort)
38
39
  else
39
40
  raise 'invalid output_format specified or not specified'
@@ -45,7 +46,7 @@ module DatadogBackup
45
46
  end
46
47
 
47
48
  def file_type(filepath)
48
- ::File.extname(filepath).strip.downcase[1..-1].to_sym
49
+ ::File.extname(filepath).strip.downcase[1..].to_sym
49
50
  end
50
51
 
51
52
  def find_file_by_id(id)
@@ -53,9 +54,10 @@ module DatadogBackup
53
54
  end
54
55
 
55
56
  def load_from_file(string, output_format)
56
- if output_format == :json
57
+ case output_format
58
+ when :json
57
59
  JSON.parse(string)
58
- elsif output_format == :yaml
60
+ when :yaml
59
61
  YAML.safe_load(string)
60
62
  else
61
63
  raise 'invalid output_format specified or not specified'
@@ -1,12 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatadogBackup
4
- class Monitors < Core
5
- API_SERVICE_NAME = :@monitor_svc
6
- BANLIST = %w[overall_state overall_state_modified matching_downtimes modified]
7
-
4
+ class Monitors < Core
8
5
  def all_monitors
9
- @all_monitors ||= client_with_200(:get_all_monitors)
6
+ @all_monitors ||= get_all
10
7
  end
11
8
 
12
9
  def api_service
@@ -29,14 +26,13 @@ module DatadogBackup
29
26
  end
30
27
  end
31
28
 
32
- def diff(id)
33
- super(id, BANLIST)
34
- end
35
-
36
29
  def get_by_id(id)
37
- except(all_monitors.select { |monitor| monitor['id'].to_s == id.to_s }.first, BANLIST)
30
+ except(all_monitors.select { |monitor| monitor['id'].to_s == id.to_s }.first)
38
31
  end
39
32
 
40
- def restore!; end
33
+ def initialize(options)
34
+ super(options)
35
+ @banlist = %w[overall_state overall_state_modified matching_downtimes modified].freeze
36
+ end
41
37
  end
42
38
  end
@@ -11,7 +11,7 @@ module DatadogBackup
11
11
 
12
12
  def self.watcher(logger)
13
13
  Thread.new(TPOOL) do |pool|
14
- while pool.queue_length > 0
14
+ while pool.queue_length.positive?
15
15
  sleep 2
16
16
  logger.info("#{pool.queue_length} tasks remaining for execution.")
17
17
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatadogBackup
4
- VERSION = '0.10.2'
4
+ VERSION = '0.10.3'
5
5
  end
@@ -3,6 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe DatadogBackup::Cli do
6
+ let(:api_service_double) { double(Dogapi::APIService) }
6
7
  let(:client_double) { double }
7
8
  let(:tempdir) { Dir.mktmpdir }
8
9
  let(:options) do
@@ -43,8 +44,10 @@ describe DatadogBackup::Cli do
43
44
  dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/alsostillthere.json")
44
45
  dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/deleted.json")
45
46
 
46
- allow(client_double).to receive(:get_all_boards).and_return(all_boards)
47
- allow(client_double).to receive(:get_board).and_return(['200', {}])
47
+ allow(client_double).to receive(:instance_variable_get).with(:@dashboard_service).and_return(api_service_double)
48
+ allow(api_service_double).to receive(:request).with(Net::HTTP::Get, "/api/v1/dashboard", nil, nil, false).and_return(all_boards)
49
+ allow(api_service_double).to receive(:request).with(Net::HTTP::Get, "/api/v1/dashboard/stillthere", nil, nil, false).and_return(['200', {}])
50
+ allow(api_service_double).to receive(:request).with(Net::HTTP::Get, "/api/v1/dashboard/alsostillthere", nil, nil, false).and_return(['200', {}])
48
51
  end
49
52
 
50
53
  it 'deletes the file locally as well' do
@@ -83,17 +86,16 @@ describe DatadogBackup::Cli do
83
86
 
84
87
  example 'starts interactive restore' do
85
88
  allow($stdin).to receive(:gets).and_return('q')
86
- begin
87
- expect { subject }.to(
88
- output(/\(r\)estore to Datadog, overwrite local changes and \(d\)ownload, \(s\)kip, or \(q\)uit\?/).to_stdout
89
- .and(raise_error(SystemExit))
90
- )
91
- end
89
+
90
+ expect { subject }.to(
91
+ output(/\(r\)estore to Datadog, overwrite local changes and \(d\)ownload, \(s\)kip, or \(q\)uit\?/).to_stdout
92
+ .and(raise_error(SystemExit))
93
+ )
92
94
  end
93
95
 
94
96
  example 'restore' do
95
97
  allow($stdin).to receive(:gets).and_return('r')
96
- expect(dashboards).to receive(:update_with_200).with('diffs1', { 'text' => 'diff' })
98
+ expect(dashboards).to receive(:update).with('diffs1', { 'text' => 'diff' })
97
99
  subject
98
100
  end
99
101
  example 'download' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe DatadogBackup::Core do
@@ -22,21 +24,15 @@ describe DatadogBackup::Core do
22
24
  it { is_expected.to eq client_double }
23
25
  end
24
26
 
25
- describe '#client_with_200' do
26
- subject { core.client_with_200(:get_all_boards) }
27
-
27
+ describe '#with_200' do
28
28
  context 'with 200' do
29
- before(:example) do
30
- allow(client_double).to receive(:get_all_boards).and_return(['200', { foo: :bar }])
31
- end
29
+ subject { core.with_200 {['200', { foo: :bar }]} }
32
30
 
33
31
  it { is_expected.to eq({ foo: :bar }) }
34
32
  end
35
33
 
36
34
  context 'with not 200' do
37
- before(:example) do
38
- allow(client_double).to receive(:get_all_boards).and_return(['401', {}])
39
- end
35
+ subject { core.with_200 {['400', "Error message"]} }
40
36
 
41
37
  it 'raises an error' do
42
38
  expect { subject }.to raise_error(RuntimeError)
@@ -50,34 +46,21 @@ describe DatadogBackup::Core do
50
46
  core.write_file('{"text": "diff2", "extra": "diff2"}', "#{tempdir}/core/diff.json")
51
47
  end
52
48
 
53
- context 'without banlist' do
54
- subject { core.diff('diff') }
55
- it {
56
- is_expected.to eq <<~EOF
57
- ---
58
- -extra: diff1
59
- -text: diff1
60
- +extra: diff2
61
- +text: diff2
62
- EOF
63
- }
64
- end
65
-
66
- context 'with banlist' do
67
- subject { core.diff('diff', ['extra']) }
68
- it {
69
- is_expected.to eq <<~EOF
70
- ---
71
- -text: diff1
72
- +text: diff2
73
- EOF
74
- }
75
- end
49
+ subject { core.diff('diff') }
50
+ it {
51
+ is_expected.to eq <<~EOF
52
+ ---
53
+ -extra: diff1
54
+ -text: diff1
55
+ +extra: diff2
56
+ +text: diff2
57
+ EOF
58
+ }
76
59
  end
77
60
 
78
61
  describe '#except' do
79
- subject { core.except({ a: :b, b: :c }, [:b]) }
80
- it { is_expected.to eq({ a: :b }) }
62
+ subject { core.except({ a: :b, b: :c }) }
63
+ it { is_expected.to eq({ a: :b, b: :c }) }
81
64
  end
82
65
 
83
66
  describe '#initialize' do
@@ -94,7 +77,7 @@ describe DatadogBackup::Core do
94
77
  end
95
78
 
96
79
  describe '#update' do
97
- subject { core.update_with_200('abc-123-def', '{"a": "b"}') }
80
+ subject { core.update('abc-123-def', '{"a": "b"}') }
98
81
  example 'it calls Dogapi::APIService.request' do
99
82
  stub_const('Dogapi::APIService::API_VERSION', 'v1')
100
83
  allow(core).to receive(:api_service).and_return(api_service_double)
@@ -3,6 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe DatadogBackup::Dashboards do
6
+ let(:api_service_double) { double(Dogapi::APIService) }
6
7
  let(:client_double) { double }
7
8
  let(:tempdir) { Dir.mktmpdir }
8
9
  let(:dashboards) do
@@ -59,8 +60,9 @@ describe DatadogBackup::Dashboards do
59
60
  }
60
61
  end
61
62
  before(:example) do
62
- allow(client_double).to receive(:get_all_boards).and_return(all_boards)
63
- allow(client_double).to receive(:get_board).and_return(example_dashboard)
63
+ allow(client_double).to receive(:instance_variable_get).with(:@dashboard_service).and_return(api_service_double)
64
+ allow(api_service_double).to receive(:request).with(Net::HTTP::Get, "/api/v1/dashboard", nil, nil, false).and_return(all_boards)
65
+ allow(api_service_double).to receive(:request).with(Net::HTTP::Get, "/api/v1/dashboard/abc-123-def", nil, nil, false).and_return(example_dashboard)
64
66
  end
65
67
 
66
68
  describe '#backup' do
@@ -79,22 +81,34 @@ describe DatadogBackup::Dashboards do
79
81
  describe '#all_boards' do
80
82
  subject { dashboards.all_boards }
81
83
 
82
- it 'calls get_all_boards' do
83
- subject
84
- expect(client_double).to have_received(:get_all_boards)
85
- end
86
-
87
84
  it { is_expected.to eq [dashboard_description] }
88
85
  end
89
86
 
90
87
  describe '#diff' do
91
88
  it 'calls the api only once' do
92
89
  dashboards.write_file('{"a":"b"}', dashboards.filename('abc-123-def'))
93
- dashboards.diff('abc-123-def')
94
- expect(client_double).to have_received(:get_board).exactly(1).times
90
+ expect(dashboards.diff('abc-123-def')).to eq(<<~EOF
91
+ ---
92
+ -description: example dashboard
93
+ -graphs:
94
+ -- definition:
95
+ - requests:
96
+ - - q: min:foo.bar{a:b}
97
+ - stacked: false
98
+ - viz: timeseries
99
+ - title: example graph
100
+ -title: example dashboard
101
+ +a: b
102
+ EOF
103
+ )
95
104
  end
96
105
  end
97
106
 
107
+ describe '#except' do
108
+ subject { dashboards.except({ :a => :b, 'modified_at' => :c, 'url' => :d }) }
109
+ it { is_expected.to eq({ a: :b }) }
110
+ end
111
+
98
112
  describe '#get_by_id' do
99
113
  subject { dashboards.get_by_id('abc-123-def') }
100
114
  it { is_expected.to eq board_abc_123_def }
@@ -3,6 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe DatadogBackup::Monitors do
6
+ let(:api_service_double) { double(Dogapi::APIService) }
6
7
  let(:client_double) { double }
7
8
  let(:tempdir) { Dir.mktmpdir }
8
9
  let(:monitors) do
@@ -47,19 +48,15 @@ describe DatadogBackup::Monitors do
47
48
  monitor_description
48
49
  ]
49
50
  end
51
+
50
52
  before(:example) do
51
- allow(client_double).to receive(:get_all_monitors).and_return(all_monitors)
52
- allow(client_double).to receive(:get_monitor).and_return(example_monitor)
53
+ allow(client_double).to receive(:instance_variable_get).with(:@monitor_svc).and_return(api_service_double)
54
+ allow(api_service_double).to receive(:request).with(Net::HTTP::Get, "/api/v1/monitor", nil, nil, false).and_return(all_monitors)
55
+ allow(api_service_double).to receive(:request).with(Net::HTTP::Get, "/api/v1/dashboard/123455", nil, nil, false).and_return(example_monitor)
53
56
  end
54
57
 
55
58
  describe '#all_monitors' do
56
59
  subject { monitors.all_monitors }
57
-
58
- it 'calls get_all_monitors' do
59
- subject
60
- expect(client_double).to have_received(:get_all_monitors)
61
- end
62
-
63
60
  it { is_expected.to eq [monitor_description] }
64
61
  end
65
62
 
@@ -76,10 +73,10 @@ describe DatadogBackup::Monitors do
76
73
  end
77
74
  end
78
75
 
79
- describe '#diff' do
76
+ describe '#diff and #except' do
80
77
  example 'it ignores `overall_state` and `overall_state_modified`' do
81
78
  monitors.write_file(monitors.dump(monitor_description), monitors.filename(123_455))
82
- allow(client_double).to receive(:get_all_monitors).and_return(
79
+ allow(api_service_double).to receive(:request).and_return(
83
80
  [
84
81
  '200',
85
82
  [
@@ -88,8 +85,8 @@ describe DatadogBackup::Monitors do
88
85
  'message' => 'foo',
89
86
  'id' => 123_455,
90
87
  'name' => 'foo',
91
- 'overall_state' => 'NO DATA',
92
- 'overall_state_modified' => '2020-07-27T22:55:55+00:00'
88
+ 'overall_state' => 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZ',
89
+ 'overall_state_modified' => '9999-07-27T22:55:55+00:00'
93
90
  }
94
91
  ]
95
92
  ]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
2
4
 
3
5
  require 'datadog_backup'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog_backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.2
4
+ version: 0.10.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kamran Farhadi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-11-03 00:00:00.000000000 Z
12
+ date: 2020-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: amazing_print