Class: DatadogBackup::Core

Inherits:
Object
  • Object
show all
Includes:
LocalFilesystem, Options
Defined in:
lib/datadog_backup/core.rb

Direct Known Subclasses

Dashboards, Monitors

Constant Summary collapse

@@retry_options =
{
  max: 5,
  interval: 0.05,
  interval_randomness: 0.5,
  backoff_factor: 2
}

Instance Method Summary collapse

Methods included from Options

#action, #backup_dir, #concurrency_limit, #diff_format, #force_restore, #output_format, #resources

Methods included from LocalFilesystem

#all_file_ids, #all_file_ids_for_selected_resources, #all_files, #class_from_id, #dump, #file_type, #filename, #find_file_by_id, #load_from_file, #load_from_file_by_id, #mydir, #purge, #write_file

Constructor Details

#initialize(options) ⇒ Core

Returns a new instance of Core.



99
100
101
102
103
# File 'lib/datadog_backup/core.rb', line 99

def initialize(options)
  @options = options
  @banlist = []
  ::FileUtils.mkdir_p(mydir)
end

Instance Method Details

#api_resource_nameObject



50
51
52
# File 'lib/datadog_backup/core.rb', line 50

def api_resource_name
  raise 'subclass is expected to implement #api_resource_name'
end

#api_serviceObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/datadog_backup/core.rb', line 22

def api_service
  conn ||= Faraday.new(
      url: api_url,
      headers: {
        'DD-API-KEY' => ENV.fetch('DD_API_KEY'),
        'DD-APPLICATION-KEY' => ENV.fetch('DD_APP_KEY')
      }
    ) do |faraday|
        faraday.request :json
        faraday.request :retry, @@retry_options
        faraday.response(:logger, LOGGER, {headers: true, bodies: LOGGER.debug?, log_level: :debug}) do | logger |
          logger.filter(/(DD-API-KEY:)([^&]+)/, '\1[REDACTED]')
          logger.filter(/(DD-APPLICATION-KEY:)([^&]+)/, '\1[REDACTED]')
        end
        faraday.response :raise_error
        faraday.response :json
        faraday.adapter Faraday.default_adapter
      end
end

#api_urlObject



42
43
44
# File 'lib/datadog_backup/core.rb', line 42

def api_url
  ENV.fetch('DD_SITE_URL', "https://api.datadoghq.com/")
end

#api_versionObject



46
47
48
# File 'lib/datadog_backup/core.rb', line 46

def api_version
  raise 'subclass is expected to implement #api_version'
end

#backupObject



54
55
56
# File 'lib/datadog_backup/core.rb', line 54

def backup
  raise 'subclass is expected to implement #backup'
end

#body_with_2xx(response) ⇒ Object



143
144
145
146
# File 'lib/datadog_backup/core.rb', line 143

def body_with_2xx(response)
  raise "#{caller_locations(1,1)[0].label} failed with error #{response.status}" unless response.status.to_s =~ /^2/
  response.body
end

#create(body) ⇒ Object

Calls out to Datadog and checks for a ‘200’ response



110
111
112
113
114
115
116
# File 'lib/datadog_backup/core.rb', line 110

def create(body)
  headers = {}
  response =  api_service.post("/api/#{api_version}/#{api_resource_name}", body, headers)
  body = body_with_2xx(response)
  LOGGER.warn "Successfully created #{body.fetch('id')} in datadog."
  body
end

#diff(id) ⇒ Object

Returns the diffy diff. Optionally, supply an array of keys to remove from comparison



60
61
62
63
64
65
66
# File 'lib/datadog_backup/core.rb', line 60

def diff(id)
  current = except(get_by_id(id)).deep_sort.to_yaml
  filesystem = except(load_from_file_by_id(id)).deep_sort.to_yaml
  result = ::Diffy::Diff.new(current, filesystem, include_plus_and_minus_in_html: true).to_s(diff_format)
  LOGGER.debug("Compared ID #{id} and found #{result}")
  result
end

#except(hash) ⇒ Object

Returns a hash with banlist elements removed



69
70
71
72
73
74
75
# File 'lib/datadog_backup/core.rb', line 69

def except(hash)
  hash.tap do # tap returns self
    @banlist.each do |key|
      hash.delete(key) # delete returns the value at the deleted key, hence the tap wrapper
    end
  end
end

#get(id) ⇒ Object



77
78
79
80
81
82
# File 'lib/datadog_backup/core.rb', line 77

def get(id)
  params = {}
  headers = {}
  response = api_service.get("/api/#{api_version}/#{api_resource_name}/#{id}", params, headers)
  body_with_2xx(response)
end

#get_allObject



84
85
86
87
88
89
# File 'lib/datadog_backup/core.rb', line 84

def get_all
  params = {}
  headers = {}
  response = api_service.get("/api/#{api_version}/#{api_resource_name}", params, headers)
  body_with_2xx(response)
end

#get_and_write_file(id) ⇒ Object



91
92
93
# File 'lib/datadog_backup/core.rb', line 91

def get_and_write_file(id)
  write_file(dump(get_by_id(id)), filename(id))
end

#get_by_id(id) ⇒ Object



95
96
97
# File 'lib/datadog_backup/core.rb', line 95

def get_by_id(id)
  except(get(id))
end

#myclassObject



105
106
107
# File 'lib/datadog_backup/core.rb', line 105

def myclass
  self.class.to_s.split(':').last.downcase
end

#restore(id) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/datadog_backup/core.rb', line 127

def restore(id)
  body = load_from_file_by_id(id)
  begin
    update(id, body)
  rescue RuntimeError => e
    if e.message.include?('update failed with error 404')
      new_id = create(body).fetch('id')

      FileUtils.rm(find_file_by_id(id))
      get_and_write_file(new_id)
    else
      raise e.message
    end
  end
end

#update(id, body) ⇒ Object

Calls out to Datadog and checks for a ‘200’ response



119
120
121
122
123
124
125
# File 'lib/datadog_backup/core.rb', line 119

def update(id, body)
  headers = {}
  response = api_service.put("/api/#{api_version}/#{api_resource_name}/#{id}", body, headers)
  body = body_with_2xx(response)
  LOGGER.warn 'Successfully restored #{id} to datadog.'
  body
end