datadog_backup 0.10.3 → 1.0.0
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 +4 -4
- data/.github/workflows/rspec_and_release.yml +2 -2
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +1 -0
- data/bin/datadog_backup +8 -1
- data/datadog_backup.gemspec +1 -1
- data/lib/datadog_backup/cli.rb +20 -17
- data/lib/datadog_backup/core.rb +31 -3
- data/lib/datadog_backup/monitors.rb +3 -2
- data/lib/datadog_backup/options.rb +4 -0
- data/lib/datadog_backup/version.rb +1 -1
- data/spec/datadog_backup/cli_spec.rb +34 -16
- data/spec/datadog_backup/core_spec.rb +87 -8
- data/spec/datadog_backup/dashboards_spec.rb +10 -5
- data/spec/datadog_backup/local_filesystem_spec.rb +44 -24
- data/spec/datadog_backup/monitors_spec.rb +11 -4
- data/spec/datadog_backup_bin_spec.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ff7695b471968ff7c34559829656149d0e77b139d484ff8e677424d90b4303d
|
4
|
+
data.tar.gz: d1bd644801cc09c4e8c442c2765e6b3da675f2de80b3acccd1e55e4ab5dbd8b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ee25ab151f20f67983335fefe4011a44a43aaf3819b9ef3264345b20aa05f0e2d212d0004bb2a9a8a170ae90a9cd6c1c3a5ef7cc7b573da269bcb01639c0fcc
|
7
|
+
data.tar.gz: f70bf349b96a98da7a48eff26ddb5841f0c41c82b08df298ab8ed3a2f2a17301a23b29ef43c60168771a016b290f7c0e1ca1186b149db9cd1c23304a635dd3a3
|
@@ -12,7 +12,7 @@ jobs:
|
|
12
12
|
steps:
|
13
13
|
- uses: actions/checkout@v2
|
14
14
|
- name: Set up Ruby 2.7.2
|
15
|
-
uses: actions/setup-ruby@v1.1.
|
15
|
+
uses: actions/setup-ruby@v1.1.3
|
16
16
|
with:
|
17
17
|
ruby-version: 2.7.2
|
18
18
|
- name: Test with Rspec
|
@@ -28,7 +28,7 @@ jobs:
|
|
28
28
|
steps:
|
29
29
|
- uses: actions/checkout@v2
|
30
30
|
- name: Set up Ruby 2.7.2
|
31
|
-
uses: actions/setup-ruby@v1.1.
|
31
|
+
uses: actions/setup-ruby@v1.1.3
|
32
32
|
with:
|
33
33
|
ruby-version: 2.7.2
|
34
34
|
- name: Build with bundler
|
data/.rubocop.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require: rubocop-rspec
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
# [1.0.0](https://github.com/scribd/datadog_backup/compare/v0.11.0...v1.0.0) (2021-03-02)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* handle gets with no result ([8d016a1](https://github.com/scribd/datadog_backup/commit/8d016a1858b44d374a0dff121c71340bf18062e0))
|
7
|
+
|
8
|
+
|
9
|
+
### Features
|
10
|
+
|
11
|
+
* If resource doesn't exist in Datadog, the resource is recreated. ([18ba241](https://github.com/scribd/datadog_backup/commit/18ba24183e136f9d899351bbb0999aba2c22308f))
|
12
|
+
|
13
|
+
|
14
|
+
### BREAKING CHANGES
|
15
|
+
|
16
|
+
* `datadog-backup` used to exit with an error if a resource
|
17
|
+
wasn't found in Datadog.
|
18
|
+
|
19
|
+
# [0.11.0](https://github.com/scribd/datadog_backup/compare/v0.10.3...v0.11.0) (2021-01-12)
|
20
|
+
|
21
|
+
|
22
|
+
### Features
|
23
|
+
|
24
|
+
* Add force-restore flag to allow running in automation ([#46](https://github.com/scribd/datadog_backup/issues/46)) ([e067386](https://github.com/scribd/datadog_backup/commit/e0673862b6f6d86297e1352faaee872f2c4884c8))
|
25
|
+
|
1
26
|
## [0.10.3](https://github.com/scribd/datadog_backup/compare/v0.10.2...v0.10.3) (2020-12-11)
|
2
27
|
|
3
28
|
|
data/Gemfile
CHANGED
data/bin/datadog_backup
CHANGED
@@ -23,6 +23,7 @@ LOGGER.level = Logger::INFO
|
|
23
23
|
diff_format: :color,
|
24
24
|
resources: [DatadogBackup::Dashboards, DatadogBackup::Monitors],
|
25
25
|
output_format: :yaml,
|
26
|
+
force_restore: false,
|
26
27
|
logger: LOGGER
|
27
28
|
}
|
28
29
|
|
@@ -54,7 +55,10 @@ def prereqs
|
|
54
55
|
opts.on('--dashboards-only') do
|
55
56
|
@options[:resources] = [DatadogBackup::Dashboards]
|
56
57
|
end
|
57
|
-
opts.on(
|
58
|
+
opts.on(
|
59
|
+
'--json',
|
60
|
+
'format backups as JSON instead of YAML. Does not impact `diffs` nor `restore`, but do not mix formats in the same backup-dir.'
|
61
|
+
) do
|
58
62
|
@options[:output_format] = :json
|
59
63
|
end
|
60
64
|
opts.on('--no-color', 'removes colored output from diff format') do
|
@@ -63,6 +67,9 @@ def prereqs
|
|
63
67
|
opts.on('--diff-format FORMAT', 'one of `color`, `html_simple`, `html`') do |format|
|
64
68
|
@options[:diff_format] = format.to_sym
|
65
69
|
end
|
70
|
+
opts.on('--force-restore', 'force restore to Datadog') do
|
71
|
+
@options[:force_restore] = true
|
72
|
+
end
|
66
73
|
end
|
67
74
|
options.parse!
|
68
75
|
|
data/datadog_backup.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_dependency 'concurrent-ruby-edge', '0.6.0'
|
25
25
|
spec.add_dependency 'deepsort', '0.4.5'
|
26
26
|
spec.add_dependency 'diffy', '3.4.0'
|
27
|
-
spec.add_dependency 'dogapi', '1.
|
27
|
+
spec.add_dependency 'dogapi', '1.44.0'
|
28
28
|
|
29
29
|
spec.add_development_dependency 'bundler'
|
30
30
|
spec.add_development_dependency 'pry'
|
data/lib/datadog_backup/cli.rb
CHANGED
@@ -108,27 +108,30 @@ module DatadogBackup
|
|
108
108
|
id, diff = *future.value!
|
109
109
|
next unless diff
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
puts '(r)estore to Datadog, overwrite local changes and (d)ownload, (s)kip, or (q)uit?'
|
114
|
-
response = $stdin.gets.chomp
|
115
|
-
case response
|
116
|
-
when 'q'
|
117
|
-
exit
|
118
|
-
when 'r'
|
119
|
-
puts "Restoring #{id} to Datadog."
|
120
|
-
definitive_resource_instance(id).update(id, definitive_resource_instance(id).load_from_file_by_id(id))
|
121
|
-
when 'd'
|
122
|
-
puts "Downloading #{id} from Datadog."
|
123
|
-
definitive_resource_instance(id).get_and_write_file(id)
|
124
|
-
when 's'
|
125
|
-
next
|
111
|
+
if @options[:force_restore]
|
112
|
+
definitive_resource_instance(id).restore(id)
|
126
113
|
else
|
127
|
-
puts '
|
114
|
+
puts '--------------------------------------------------------------------------------'
|
115
|
+
puts format_diff_output([id, diff])
|
116
|
+
puts '(r)estore to Datadog, overwrite local changes and (d)ownload, (s)kip, or (q)uit?'
|
128
117
|
response = $stdin.gets.chomp
|
118
|
+
case response
|
119
|
+
when 'q'
|
120
|
+
exit
|
121
|
+
when 'r'
|
122
|
+
puts "Restoring #{id} to Datadog."
|
123
|
+
definitive_resource_instance(id).restore(id)
|
124
|
+
when 'd'
|
125
|
+
puts "Downloading #{id} from Datadog."
|
126
|
+
definitive_resource_instance(id).get_and_write_file(id)
|
127
|
+
when 's'
|
128
|
+
next
|
129
|
+
else
|
130
|
+
puts 'Invalid response, please try again.'
|
131
|
+
response = $stdin.gets.chomp
|
132
|
+
end
|
129
133
|
end
|
130
134
|
end
|
131
|
-
|
132
135
|
watcher.join if watcher.status
|
133
136
|
end
|
134
137
|
|
data/lib/datadog_backup/core.rb
CHANGED
@@ -47,6 +47,9 @@ module DatadogBackup
|
|
47
47
|
with_200 do
|
48
48
|
api_service.request(Net::HTTP::Get, "/api/#{api_version}/#{api_resource_name}/#{id}", nil, nil, false)
|
49
49
|
end
|
50
|
+
rescue RuntimeError => e
|
51
|
+
return {} if e.message.include?('Request failed with error ["404"')
|
52
|
+
raise e.message
|
50
53
|
end
|
51
54
|
|
52
55
|
def get_all
|
@@ -73,12 +76,38 @@ module DatadogBackup
|
|
73
76
|
self.class.to_s.split(':').last.downcase
|
74
77
|
end
|
75
78
|
|
79
|
+
# Calls out to Datadog and checks for a '200' response
|
80
|
+
def create(body)
|
81
|
+
result = with_200 do
|
82
|
+
api_service.request(Net::HTTP::Post, "/api/#{api_version}/#{api_resource_name}", nil, body, true)
|
83
|
+
end
|
84
|
+
logger.warn 'Successfully created in datadog.'
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
76
88
|
# Calls out to Datadog and checks for a '200' response
|
77
89
|
def update(id, body)
|
78
|
-
with_200 do
|
90
|
+
result = with_200 do
|
79
91
|
api_service.request(Net::HTTP::Put, "/api/#{api_version}/#{api_resource_name}/#{id}", nil, body, true)
|
80
92
|
end
|
81
93
|
logger.warn 'Successfully restored to datadog.'
|
94
|
+
result
|
95
|
+
end
|
96
|
+
|
97
|
+
def restore(id)
|
98
|
+
body = load_from_file_by_id(id)
|
99
|
+
begin
|
100
|
+
update(id, body)
|
101
|
+
rescue RuntimeError => e
|
102
|
+
if e.message.include?('Request failed with error ["404"')
|
103
|
+
new_id = create(body).fetch('id')
|
104
|
+
|
105
|
+
FileUtils.rm(find_file_by_id(id))
|
106
|
+
get_and_write_file(new_id)
|
107
|
+
else
|
108
|
+
raise e.message
|
109
|
+
end
|
110
|
+
end
|
82
111
|
end
|
83
112
|
|
84
113
|
def with_200
|
@@ -94,9 +123,8 @@ module DatadogBackup
|
|
94
123
|
sleep(0.1 * retries**5) # 0.1, 3.2, 24.3, 102.4 seconds per retry
|
95
124
|
retry
|
96
125
|
else
|
97
|
-
raise "
|
126
|
+
raise "Net::OpenTimeout: #{e.message}"
|
98
127
|
end
|
99
128
|
end
|
100
|
-
|
101
129
|
end
|
102
130
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DatadogBackup
|
4
|
-
class Monitors < Core
|
4
|
+
class Monitors < Core
|
5
5
|
def all_monitors
|
6
6
|
@all_monitors ||= get_all
|
7
7
|
end
|
@@ -27,7 +27,8 @@ module DatadogBackup
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def get_by_id(id)
|
30
|
-
|
30
|
+
monitor = all_monitors.select { |monitor| monitor['id'].to_s == id.to_s }.first
|
31
|
+
monitor.nil? ? {} : except(monitor)
|
31
32
|
end
|
32
33
|
|
33
34
|
def initialize(options)
|
@@ -19,10 +19,10 @@ describe DatadogBackup::Cli do
|
|
19
19
|
resources: [DatadogBackup::Dashboards]
|
20
20
|
}
|
21
21
|
end
|
22
|
-
let(:cli) {
|
22
|
+
let(:cli) { described_class.new(options) }
|
23
23
|
let(:dashboards) { DatadogBackup::Dashboards.new(options) }
|
24
24
|
|
25
|
-
before
|
25
|
+
before do
|
26
26
|
allow(cli).to receive(:resource_instances).and_return([dashboards])
|
27
27
|
end
|
28
28
|
|
@@ -39,15 +39,28 @@ describe DatadogBackup::Cli do
|
|
39
39
|
}
|
40
40
|
]
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
|
+
before do
|
43
44
|
dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/stillthere.json")
|
44
45
|
dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/alsostillthere.json")
|
45
46
|
dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/deleted.json")
|
46
47
|
|
47
48
|
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,
|
49
|
-
|
50
|
-
|
49
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get,
|
50
|
+
'/api/v1/dashboard',
|
51
|
+
nil,
|
52
|
+
nil,
|
53
|
+
false).and_return(all_boards)
|
54
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get,
|
55
|
+
'/api/v1/dashboard/stillthere',
|
56
|
+
nil,
|
57
|
+
nil,
|
58
|
+
false).and_return(['200', {}])
|
59
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get,
|
60
|
+
'/api/v1/dashboard/alsostillthere',
|
61
|
+
nil,
|
62
|
+
nil,
|
63
|
+
false).and_return(['200', {}])
|
51
64
|
end
|
52
65
|
|
53
66
|
it 'deletes the file locally as well' do
|
@@ -58,16 +71,18 @@ describe DatadogBackup::Cli do
|
|
58
71
|
end
|
59
72
|
|
60
73
|
describe '#diffs' do
|
61
|
-
|
74
|
+
subject { cli.diffs }
|
75
|
+
|
76
|
+
before do
|
62
77
|
dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/diffs1.json")
|
63
78
|
dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/diffs2.json")
|
64
79
|
dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/diffs3.json")
|
65
80
|
allow(dashboards).to receive(:get_by_id).and_return({ 'text' => 'diff2' })
|
66
81
|
allow(cli).to receive(:initialize_client).and_return(client_double)
|
67
82
|
end
|
68
|
-
|
83
|
+
|
69
84
|
it {
|
70
|
-
|
85
|
+
expect(subject).to include(
|
71
86
|
" ---\n id: diffs1\n ---\n-text: diff2\n+text: diff\n",
|
72
87
|
" ---\n id: diffs3\n ---\n-text: diff2\n+text: diff\n",
|
73
88
|
" ---\n id: diffs2\n ---\n-text: diff2\n+text: diff\n"
|
@@ -76,14 +91,14 @@ describe DatadogBackup::Cli do
|
|
76
91
|
end
|
77
92
|
|
78
93
|
describe '#restore' do
|
79
|
-
|
94
|
+
subject { cli.restore }
|
95
|
+
|
96
|
+
before do
|
80
97
|
dashboards.write_file('{"text": "diff"}', "#{tempdir}/dashboards/diffs1.json")
|
81
98
|
allow(dashboards).to receive(:get_by_id).and_return({ 'text' => 'diff2' })
|
82
99
|
allow(cli).to receive(:initialize_client).and_return(client_double)
|
83
100
|
end
|
84
101
|
|
85
|
-
subject { cli.restore }
|
86
|
-
|
87
102
|
example 'starts interactive restore' do
|
88
103
|
allow($stdin).to receive(:gets).and_return('q')
|
89
104
|
|
@@ -98,21 +113,24 @@ describe DatadogBackup::Cli do
|
|
98
113
|
expect(dashboards).to receive(:update).with('diffs1', { 'text' => 'diff' })
|
99
114
|
subject
|
100
115
|
end
|
116
|
+
|
101
117
|
example 'download' do
|
102
118
|
allow($stdin).to receive(:gets).and_return('d')
|
103
119
|
expect(dashboards).to receive(:write_file).with(%({\n "text": "diff2"\n}), "#{tempdir}/dashboards/diffs1.json")
|
104
120
|
subject
|
105
121
|
end
|
122
|
+
|
106
123
|
example 'skip' do
|
107
124
|
allow($stdin).to receive(:gets).and_return('s')
|
108
|
-
expect(dashboards).
|
109
|
-
expect(dashboards).
|
125
|
+
expect(dashboards).not_to receive(:write_file)
|
126
|
+
expect(dashboards).not_to receive(:update)
|
110
127
|
subject
|
111
128
|
end
|
129
|
+
|
112
130
|
example 'quit' do
|
113
131
|
allow($stdin).to receive(:gets).and_return('q')
|
114
|
-
expect(dashboards).
|
115
|
-
expect(dashboards).
|
132
|
+
expect(dashboards).not_to receive(:write_file)
|
133
|
+
expect(dashboards).not_to receive(:update)
|
116
134
|
expect { subject }.to raise_error(SystemExit)
|
117
135
|
end
|
118
136
|
end
|
@@ -7,7 +7,7 @@ describe DatadogBackup::Core do
|
|
7
7
|
let(:client_double) { double }
|
8
8
|
let(:tempdir) { Dir.mktmpdir }
|
9
9
|
let(:core) do
|
10
|
-
|
10
|
+
described_class.new(
|
11
11
|
action: 'backup',
|
12
12
|
api_service: api_service_double,
|
13
13
|
client: client_double,
|
@@ -21,18 +21,19 @@ describe DatadogBackup::Core do
|
|
21
21
|
|
22
22
|
describe '#client' do
|
23
23
|
subject { core.client }
|
24
|
+
|
24
25
|
it { is_expected.to eq client_double }
|
25
26
|
end
|
26
27
|
|
27
28
|
describe '#with_200' do
|
28
29
|
context 'with 200' do
|
29
|
-
subject { core.with_200 {['200', { foo: :bar }]} }
|
30
|
+
subject { core.with_200 { ['200', { foo: :bar }] } }
|
30
31
|
|
31
32
|
it { is_expected.to eq({ foo: :bar }) }
|
32
33
|
end
|
33
34
|
|
34
35
|
context 'with not 200' do
|
35
|
-
subject { core.with_200 {['400',
|
36
|
+
subject { core.with_200 { ['400', 'Error message'] } }
|
36
37
|
|
37
38
|
it 'raises an error' do
|
38
39
|
expect { subject }.to raise_error(RuntimeError)
|
@@ -41,14 +42,15 @@ describe DatadogBackup::Core do
|
|
41
42
|
end
|
42
43
|
|
43
44
|
describe '#diff' do
|
44
|
-
|
45
|
+
subject { core.diff('diff') }
|
46
|
+
|
47
|
+
before do
|
45
48
|
allow(core).to receive(:get_by_id).and_return({ 'text' => 'diff1', 'extra' => 'diff1' })
|
46
49
|
core.write_file('{"text": "diff2", "extra": "diff2"}', "#{tempdir}/core/diff.json")
|
47
50
|
end
|
48
51
|
|
49
|
-
subject { core.diff('diff') }
|
50
52
|
it {
|
51
|
-
|
53
|
+
expect(subject).to eq <<~EOF
|
52
54
|
---
|
53
55
|
-extra: diff1
|
54
56
|
-text: diff1
|
@@ -60,11 +62,13 @@ describe DatadogBackup::Core do
|
|
60
62
|
|
61
63
|
describe '#except' do
|
62
64
|
subject { core.except({ a: :b, b: :c }) }
|
65
|
+
|
63
66
|
it { is_expected.to eq({ a: :b, b: :c }) }
|
64
67
|
end
|
65
68
|
|
66
69
|
describe '#initialize' do
|
67
70
|
subject { core }
|
71
|
+
|
68
72
|
it 'makes the subdirectories' do
|
69
73
|
expect(FileUtils).to receive(:mkdir_p).with("#{tempdir}/core")
|
70
74
|
subject
|
@@ -73,18 +77,93 @@ describe DatadogBackup::Core do
|
|
73
77
|
|
74
78
|
describe '#myclass' do
|
75
79
|
subject { core.myclass }
|
80
|
+
|
76
81
|
it { is_expected.to eq 'core' }
|
77
82
|
end
|
78
83
|
|
84
|
+
describe '#create' do
|
85
|
+
subject { core.create({ 'a' => 'b' }) }
|
86
|
+
|
87
|
+
example 'it calls Dogapi::APIService.request' do
|
88
|
+
stub_const('Dogapi::APIService::API_VERSION', 'v1')
|
89
|
+
allow(core).to receive(:api_service).and_return(api_service_double)
|
90
|
+
allow(core).to receive(:api_version).and_return('v1')
|
91
|
+
allow(core).to receive(:api_resource_name).and_return('dashboard')
|
92
|
+
expect(api_service_double).to receive(:request).with(Net::HTTP::Post,
|
93
|
+
'/api/v1/dashboard',
|
94
|
+
nil,
|
95
|
+
{ 'a' => 'b' },
|
96
|
+
true).and_return(['200', { 'id' => 'whatever-id-abc' }])
|
97
|
+
subject
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
79
101
|
describe '#update' do
|
80
|
-
subject { core.update('abc-123-def', '
|
102
|
+
subject { core.update('abc-123-def', { 'a' => 'b' }) }
|
103
|
+
|
81
104
|
example 'it calls Dogapi::APIService.request' do
|
82
105
|
stub_const('Dogapi::APIService::API_VERSION', 'v1')
|
83
106
|
allow(core).to receive(:api_service).and_return(api_service_double)
|
84
107
|
allow(core).to receive(:api_version).and_return('v1')
|
85
108
|
allow(core).to receive(:api_resource_name).and_return('dashboard')
|
86
|
-
expect(api_service_double).to receive(:request).with(Net::HTTP::Put,
|
109
|
+
expect(api_service_double).to receive(:request).with(Net::HTTP::Put,
|
110
|
+
'/api/v1/dashboard/abc-123-def',
|
111
|
+
nil,
|
112
|
+
{ 'a' => 'b' },
|
113
|
+
true).and_return(['200', { 'id' => 'whatever-id-abc' }])
|
87
114
|
subject
|
88
115
|
end
|
89
116
|
end
|
117
|
+
|
118
|
+
describe '#restore' do
|
119
|
+
before do
|
120
|
+
allow(core).to receive(:api_service).and_return(api_service_double)
|
121
|
+
allow(core).to receive(:api_version).and_return('api-version-string')
|
122
|
+
allow(core).to receive(:api_resource_name).and_return('api-resource-name-string')
|
123
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get,
|
124
|
+
'/api/api-version-string/api-resource-name-string/abc-123-def',
|
125
|
+
nil,
|
126
|
+
nil,
|
127
|
+
false).and_return(['200', { test: :ok }])
|
128
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get,
|
129
|
+
'/api/api-version-string/api-resource-name-string/bad-123-id',
|
130
|
+
nil,
|
131
|
+
nil,
|
132
|
+
false).and_return(['404', { error: :blahblah_not_found }])
|
133
|
+
allow(core).to receive(:load_from_file_by_id).and_return({ 'load' => 'ok' })
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'when id exists' do
|
137
|
+
subject { core.restore('abc-123-def') }
|
138
|
+
|
139
|
+
example 'it calls out to update' do
|
140
|
+
expect(core).to receive(:update).with('abc-123-def', { 'load' => 'ok' })
|
141
|
+
subject
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'when id does not exist' do
|
146
|
+
subject { core.restore('bad-123-id') }
|
147
|
+
|
148
|
+
before do
|
149
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Put,
|
150
|
+
'/api/api-version-string/api-resource-name-string/bad-123-id',
|
151
|
+
nil, { 'load' => 'ok' },
|
152
|
+
true).and_return(['404', { 'Error' => 'my not found' }])
|
153
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Post,
|
154
|
+
'/api/api-version-string/api-resource-name-string',
|
155
|
+
nil,
|
156
|
+
{ 'load' => 'ok' },
|
157
|
+
true).and_return(['200', { 'id' => 'my-new-id' }])
|
158
|
+
end
|
159
|
+
|
160
|
+
example 'it calls out to create then saves the new file and deletes the new file' do
|
161
|
+
expect(core).to receive(:create).with({ 'load' => 'ok' }).and_return({ 'id' => 'my-new-id' })
|
162
|
+
expect(core).to receive(:get_and_write_file).with('my-new-id')
|
163
|
+
allow(core).to receive(:find_file_by_id).with('bad-123-id').and_return('/path/to/bad-123-id.json')
|
164
|
+
expect(FileUtils).to receive(:rm).with('/path/to/bad-123-id.json')
|
165
|
+
subject
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
90
169
|
end
|
@@ -7,7 +7,7 @@ describe DatadogBackup::Dashboards do
|
|
7
7
|
let(:client_double) { double }
|
8
8
|
let(:tempdir) { Dir.mktmpdir }
|
9
9
|
let(:dashboards) do
|
10
|
-
|
10
|
+
described_class.new(
|
11
11
|
action: 'backup',
|
12
12
|
client: client_double,
|
13
13
|
backup_dir: tempdir,
|
@@ -59,10 +59,13 @@ describe DatadogBackup::Dashboards do
|
|
59
59
|
'title' => 'example dashboard'
|
60
60
|
}
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
|
+
before do
|
63
64
|
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,
|
65
|
-
|
65
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get, '/api/v1/dashboard', nil, nil,
|
66
|
+
false).and_return(all_boards)
|
67
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get, '/api/v1/dashboard/abc-123-def', nil, nil,
|
68
|
+
false).and_return(example_dashboard)
|
66
69
|
end
|
67
70
|
|
68
71
|
describe '#backup' do
|
@@ -100,17 +103,19 @@ describe DatadogBackup::Dashboards do
|
|
100
103
|
-title: example dashboard
|
101
104
|
+a: b
|
102
105
|
EOF
|
103
|
-
|
106
|
+
)
|
104
107
|
end
|
105
108
|
end
|
106
109
|
|
107
110
|
describe '#except' do
|
108
111
|
subject { dashboards.except({ :a => :b, 'modified_at' => :c, 'url' => :d }) }
|
112
|
+
|
109
113
|
it { is_expected.to eq({ a: :b }) }
|
110
114
|
end
|
111
115
|
|
112
116
|
describe '#get_by_id' do
|
113
117
|
subject { dashboards.get_by_id('abc-123-def') }
|
118
|
+
|
114
119
|
it { is_expected.to eq board_abc_123_def }
|
115
120
|
end
|
116
121
|
end
|
@@ -27,55 +27,61 @@ describe DatadogBackup::LocalFilesystem do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
describe '#all_files' do
|
30
|
-
|
30
|
+
subject { core.all_files }
|
31
|
+
|
32
|
+
before do
|
31
33
|
File.new("#{tempdir}/all_files.json", 'w')
|
32
34
|
end
|
33
35
|
|
34
|
-
after
|
36
|
+
after do
|
35
37
|
FileUtils.rm "#{tempdir}/all_files.json"
|
36
38
|
end
|
37
39
|
|
38
|
-
subject { core.all_files }
|
39
40
|
it { is_expected.to eq(["#{tempdir}/all_files.json"]) }
|
40
41
|
end
|
41
42
|
|
42
43
|
describe '#all_file_ids_for_selected_resources' do
|
43
|
-
|
44
|
+
subject { core.all_file_ids_for_selected_resources }
|
45
|
+
|
46
|
+
before do
|
44
47
|
Dir.mkdir("#{tempdir}/dashboards")
|
45
48
|
Dir.mkdir("#{tempdir}/monitors")
|
46
49
|
File.new("#{tempdir}/dashboards/all_files.json", 'w')
|
47
50
|
File.new("#{tempdir}/monitors/12345.json", 'w')
|
48
51
|
end
|
49
52
|
|
50
|
-
after
|
53
|
+
after do
|
51
54
|
FileUtils.rm "#{tempdir}/dashboards/all_files.json"
|
52
55
|
FileUtils.rm "#{tempdir}/monitors/12345.json"
|
53
56
|
end
|
54
57
|
|
55
|
-
subject { core.all_file_ids_for_selected_resources }
|
56
58
|
it { is_expected.to eq(['all_files']) }
|
57
59
|
end
|
58
60
|
|
59
61
|
describe '#class_from_id' do
|
60
|
-
|
62
|
+
subject { core.class_from_id('abc-123-def') }
|
63
|
+
|
64
|
+
before do
|
61
65
|
core.write_file('abc', "#{tempdir}/core/abc-123-def.json")
|
62
66
|
end
|
63
67
|
|
64
|
-
after
|
68
|
+
after do
|
65
69
|
FileUtils.rm "#{tempdir}/core/abc-123-def.json"
|
66
70
|
end
|
67
|
-
|
71
|
+
|
68
72
|
it { is_expected.to eq DatadogBackup::Core }
|
69
73
|
end
|
70
74
|
|
71
75
|
describe '#dump' do
|
72
76
|
context ':json' do
|
73
77
|
subject { core.dump({ a: :b }) }
|
78
|
+
|
74
79
|
it { is_expected.to eq(%({\n "a": "b"\n})) }
|
75
80
|
end
|
76
81
|
|
77
82
|
context ':yaml' do
|
78
83
|
subject { core_yaml.dump({ 'a' => 'b' }) }
|
84
|
+
|
79
85
|
it { is_expected.to eq(%(---\na: b\n)) }
|
80
86
|
end
|
81
87
|
end
|
@@ -83,80 +89,94 @@ describe DatadogBackup::LocalFilesystem do
|
|
83
89
|
describe '#filename' do
|
84
90
|
context ':json' do
|
85
91
|
subject { core.filename('abc-123-def') }
|
92
|
+
|
86
93
|
it { is_expected.to eq("#{tempdir}/core/abc-123-def.json") }
|
87
94
|
end
|
88
95
|
|
89
96
|
context ':yaml' do
|
90
97
|
subject { core_yaml.filename('abc-123-def') }
|
98
|
+
|
91
99
|
it { is_expected.to eq("#{tempdir}/core/abc-123-def.yaml") }
|
92
100
|
end
|
93
101
|
end
|
94
102
|
|
95
103
|
describe '#file_type' do
|
96
|
-
|
104
|
+
subject { core.file_type("#{tempdir}/file_type.json") }
|
105
|
+
|
106
|
+
before do
|
97
107
|
File.new("#{tempdir}/file_type.json", 'w')
|
98
108
|
end
|
99
109
|
|
100
|
-
after
|
110
|
+
after do
|
101
111
|
FileUtils.rm "#{tempdir}/file_type.json"
|
102
112
|
end
|
103
113
|
|
104
|
-
subject { core.file_type("#{tempdir}/file_type.json") }
|
105
114
|
it { is_expected.to eq :json }
|
106
115
|
end
|
107
116
|
|
108
117
|
describe '#find_file_by_id' do
|
109
|
-
|
118
|
+
subject { core.find_file_by_id('find_file') }
|
119
|
+
|
120
|
+
before do
|
110
121
|
File.new("#{tempdir}/find_file.json", 'w')
|
111
122
|
end
|
112
123
|
|
113
|
-
after
|
124
|
+
after do
|
114
125
|
FileUtils.rm "#{tempdir}/find_file.json"
|
115
126
|
end
|
116
127
|
|
117
|
-
subject { core.find_file_by_id('find_file') }
|
118
128
|
it { is_expected.to eq "#{tempdir}/find_file.json" }
|
119
129
|
end
|
120
130
|
|
121
131
|
describe '#load_from_file' do
|
122
132
|
context ':json' do
|
123
133
|
subject { core.load_from_file(%({\n "a": "b"\n}), :json) }
|
134
|
+
|
124
135
|
it { is_expected.to eq('a' => 'b') }
|
125
136
|
end
|
126
137
|
|
127
138
|
context ':yaml' do
|
128
139
|
subject { core.load_from_file(%(---\na: b\n), :yaml) }
|
140
|
+
|
129
141
|
it { is_expected.to eq('a' => 'b') }
|
130
142
|
end
|
131
143
|
end
|
132
144
|
|
133
145
|
describe '#load_from_file_by_id' do
|
134
146
|
context 'written in json read in yaml mode' do
|
135
|
-
before(:example) { core.write_file(%({"a": "b"}), "#{tempdir}/core/abc-123-def.json") }
|
136
|
-
after(:example) { FileUtils.rm "#{tempdir}/core/abc-123-def.json" }
|
137
|
-
|
138
147
|
subject { core_yaml.load_from_file_by_id('abc-123-def') }
|
148
|
+
|
149
|
+
before { core.write_file(%({"a": "b"}), "#{tempdir}/core/abc-123-def.json") }
|
150
|
+
|
151
|
+
after { FileUtils.rm "#{tempdir}/core/abc-123-def.json" }
|
152
|
+
|
139
153
|
it { is_expected.to eq('a' => 'b') }
|
140
154
|
end
|
141
|
-
context 'written in yaml read in json mode' do
|
142
|
-
before(:example) { core.write_file(%(---\na: b), "#{tempdir}/core/abc-123-def.yaml") }
|
143
|
-
after(:example) { FileUtils.rm "#{tempdir}/core/abc-123-def.yaml" }
|
144
155
|
|
156
|
+
context 'written in yaml read in json mode' do
|
145
157
|
subject { core.load_from_file_by_id('abc-123-def') }
|
158
|
+
|
159
|
+
before { core.write_file(%(---\na: b), "#{tempdir}/core/abc-123-def.yaml") }
|
160
|
+
|
161
|
+
after { FileUtils.rm "#{tempdir}/core/abc-123-def.yaml" }
|
162
|
+
|
146
163
|
it { is_expected.to eq('a' => 'b') }
|
147
164
|
end
|
148
165
|
|
149
166
|
context 'Integer as parameter' do
|
150
|
-
before(:example) { core.write_file(%(---\na: b), "#{tempdir}/core/12345.yaml") }
|
151
|
-
after(:example) { FileUtils.rm "#{tempdir}/core/12345.yaml" }
|
152
|
-
|
153
167
|
subject { core.load_from_file_by_id(12_345) }
|
168
|
+
|
169
|
+
before { core.write_file(%(---\na: b), "#{tempdir}/core/12345.yaml") }
|
170
|
+
|
171
|
+
after { FileUtils.rm "#{tempdir}/core/12345.yaml" }
|
172
|
+
|
154
173
|
it { is_expected.to eq('a' => 'b') }
|
155
174
|
end
|
156
175
|
end
|
157
176
|
|
158
177
|
describe '#write_file' do
|
159
178
|
subject { core.write_file('abc123', "#{tempdir}/core/abc-123-def.json") }
|
179
|
+
|
160
180
|
let(:file_like_object) { double }
|
161
181
|
|
162
182
|
it 'writes a file to abc-123-def.json' do
|
@@ -7,7 +7,7 @@ describe DatadogBackup::Monitors do
|
|
7
7
|
let(:client_double) { double }
|
8
8
|
let(:tempdir) { Dir.mktmpdir }
|
9
9
|
let(:monitors) do
|
10
|
-
|
10
|
+
described_class.new(
|
11
11
|
action: 'backup',
|
12
12
|
client: client_double,
|
13
13
|
backup_dir: tempdir,
|
@@ -49,14 +49,17 @@ describe DatadogBackup::Monitors do
|
|
49
49
|
]
|
50
50
|
end
|
51
51
|
|
52
|
-
before
|
52
|
+
before do
|
53
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,
|
55
|
-
|
54
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get, '/api/v1/monitor', nil, nil,
|
55
|
+
false).and_return(all_monitors)
|
56
|
+
allow(api_service_double).to receive(:request).with(Net::HTTP::Get, '/api/v1/dashboard/123455', nil, nil,
|
57
|
+
false).and_return(example_monitor)
|
56
58
|
end
|
57
59
|
|
58
60
|
describe '#all_monitors' do
|
59
61
|
subject { monitors.all_monitors }
|
62
|
+
|
60
63
|
it { is_expected.to eq [monitor_description] }
|
61
64
|
end
|
62
65
|
|
@@ -100,16 +103,20 @@ describe DatadogBackup::Monitors do
|
|
100
103
|
|
101
104
|
describe '#filename' do
|
102
105
|
subject { monitors.filename(123_455) }
|
106
|
+
|
103
107
|
it { is_expected.to eq("#{tempdir}/monitors/123455.json") }
|
104
108
|
end
|
105
109
|
|
106
110
|
describe '#get_by_id' do
|
107
111
|
context 'Integer' do
|
108
112
|
subject { monitors.get_by_id(123_455) }
|
113
|
+
|
109
114
|
it { is_expected.to eq monitor_description }
|
110
115
|
end
|
116
|
+
|
111
117
|
context 'String' do
|
112
118
|
subject { monitors.get_by_id('123455') }
|
119
|
+
|
113
120
|
it { is_expected.to eq monitor_description }
|
114
121
|
end
|
115
122
|
end
|
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.
|
4
|
+
version: 1.0.0
|
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:
|
12
|
+
date: 2021-03-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: amazing_print
|
@@ -87,14 +87,14 @@ dependencies:
|
|
87
87
|
requirements:
|
88
88
|
- - '='
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version: 1.
|
90
|
+
version: 1.44.0
|
91
91
|
type: :runtime
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
95
|
- - '='
|
96
96
|
- !ruby/object:Gem::Version
|
97
|
-
version: 1.
|
97
|
+
version: 1.44.0
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: bundler
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -135,6 +135,7 @@ files:
|
|
135
135
|
- ".github/dependabot.yml"
|
136
136
|
- ".github/workflows/rspec_and_release.yml"
|
137
137
|
- ".gitignore"
|
138
|
+
- ".rubocop.yml"
|
138
139
|
- CHANGELOG.md
|
139
140
|
- CODE_OF_CONDUCT.md
|
140
141
|
- Gemfile
|