class Brillo::Scrubber

Responsible for creating a fresh scrubbed SQL copy of the database, as specified via config, and uploading to S3

Responsible for asserting that the config file is valid

Constants

JUMBLE_PRNG
LATEST_LIMIT
SCRUBBERS

Define some procs as scrubbing strategies for Polo

TACTICS

Attributes

adapter[R]
config[R]
transferrer[R]

Public Class Methods

new(config) click to toggle source
# File lib/brillo/scrubber.rb, line 30
def initialize(config)
  @config = config
  @adapter = config.adapter
end

Public Instance Methods

dump_structure_and_migrations() click to toggle source
# File lib/brillo/scrubber.rb, line 44
def dump_structure_and_migrations
  return unless config.recreate_db
  adapter.dump_structure_and_migrations(config)
end
explore_all_classes() click to toggle source
# File lib/brillo/scrubber.rb, line 49
def explore_all_classes
  File.open(config.dump_path, "a") do |sql_file|
    sql_file.puts(adapter.header)
    klass_association_map.each do |klass, options|
      begin
        klass = deserialize_class(klass)
        tactic = deserialize_tactic(klass, options)
      rescue ConfigParseError => e
        logger.error "Error in brillo.yml: #{e.message}"
        next
      end
      associations = options.fetch(:associations, [])
      explore_class(klass, tactic, associations) do |insert|
        sql_file.puts(insert)
      end
    end
    ActiveRecord::Base.descendants.each do |klass|
      sql_file.puts(adapter.table_footer(klass))
    end
    sql_file.puts(adapter.footer)
  end
end
scrub!() click to toggle source
# File lib/brillo/scrubber.rb, line 35
def scrub!
  FileUtils.rm config.compressed_filename, force: true
  configure_polo
  dump_structure_and_migrations
  explore_all_classes
  compress
  config.transferrer.upload
end
validate() click to toggle source
# File lib/brillo/validator.rb, line 12
def validate
  errors = Hash.new({}.freeze)
  klass_association_map.each do |klass, options|
    begin
      real_klass = deserialize_class(klass)
    rescue
      errors[klass][:name] = "No such class #{klass.camelize}, did you use the singular?"
    end
    begin
      tactic = options.fetch("tactic").to_sym
    rescue KeyError
      errors[klass][:tactic] "Tactic not specified"
    end
  end
end

Private Instance Methods

compress() click to toggle source
# File lib/brillo/scrubber.rb, line 74
def compress
  return unless config.compress
  execute!("gzip -f #{config.dump_path}")
end
configure_polo() click to toggle source
# File lib/brillo/scrubber.rb, line 99
def configure_polo
  obfs = obfuscations
  adapter = config.db["adapter"]
  Polo.configure do
    obfuscate obfs
    if adapter == "mysql2"
      on_duplicate :ignore
    end
  end
end
deserialize_class(klass) click to toggle source
# File lib/brillo/scrubber.rb, line 110
def deserialize_class(klass)
  klass.to_s.camelize.constantize
rescue
  raise ConfigParseError, "Could not process class '#{klass}'"
end
deserialize_tactic(klass, options) click to toggle source
# File lib/brillo/scrubber.rb, line 116
def deserialize_tactic(klass, options)
  options.fetch(:tactic).to_sym
rescue KeyError
  raise ConfigParseError, "Tactic not specified for class #{klass}"
end
explore_class(klass, tactic_or_ids, associations) { |"#{row};"| ... } click to toggle source
# File lib/brillo/scrubber.rb, line 79
def explore_class(klass, tactic_or_ids, associations)
  ids = tactic_or_ids.is_a?(Symbol) ? TACTICS.fetch(tactic_or_ids).call(klass) : tactic_or_ids
  logger.info("Scrubbing #{ids.length} #{klass} rows with associations #{associations}")
  ActiveRecord::Base.connection.uncached do
    Polo.explore(klass, ids, associations).each do |row|
      yield "#{row};"
    end
  end
end
klass_association_map() click to toggle source
# File lib/brillo/scrubber.rb, line 89
def klass_association_map
  config.klass_association_map
end
obfuscations() click to toggle source
# File lib/brillo/scrubber.rb, line 93
def obfuscations
  config.obfuscations.map do |field, strategy|
    [field, SCRUBBERS.fetch(strategy)]
  end.to_h
end