Skip to content

Commit 5f41626

Browse files
committed
Make gem
1 parent d472426 commit 5f41626

7 files changed

+181
-174
lines changed

LICENSE

-21
This file was deleted.

bin/mongo_masker

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'mongo_masker'
4+
require 'thor'
5+
6+
class MongoMasker::Cli < Thor
7+
include Thor::Actions
8+
9+
desc 'mask MASKER_FILE', 'Mask database'
10+
def mask(masker_file)
11+
masker = MongoMasker::Main.new(masker_file)
12+
masker.mask
13+
end
14+
end
15+
16+
MongoMasker::Cli.start

docker-compose.yml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ services:
1212
- mongodb
1313
volumes:
1414
- ./lib:/masking/lib
15+
- ./bin:/masking/bin
1516
stdin_open: true
1617
tty: true
1718

lib/masker.rb

-139
This file was deleted.

lib/mongo_masker.rb

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
require 'yaml'
2+
require 'ffaker'
3+
require 'mongo'
4+
5+
Mongo::Logger.logger.level = Logger::FATAL
6+
7+
module MongoMasker
8+
class Main
9+
def initialize(config = nil)
10+
configure config unless config.nil?
11+
@sequence = 0
12+
end
13+
14+
def db
15+
@db ||= Mongo::Client.new(@config['db_url'] || 'mongodb://mongodb:27017/development')
16+
end
17+
18+
def mask(config = nil)
19+
configure config unless config.nil?
20+
raise 'Please provide mask' if @config.nil?
21+
22+
track_time do
23+
@config['models'].each do |model|
24+
mask_document model
25+
end
26+
puts 'Done!' unless @config['silent']
27+
end
28+
end
29+
30+
def configure(config)
31+
@config = config.is_a?(String) ? load_from_yaml(config) : config
32+
end
33+
34+
def seq
35+
@sequence += 1
36+
end
37+
38+
private
39+
40+
def track_time
41+
start_at = Time.now
42+
yield
43+
finish_at = Time.now
44+
puts "Elapsed time: #{format_time_diff(start_at, finish_at)}" unless @config['silent']
45+
end
46+
47+
def format_time_diff(start_at, finish_at)
48+
output = Time.at(finish_at - start_at).strftime '%H hours %M minutes %S seconds'
49+
output.gsub(/^0+ hours /, '').gsub(/^0+ minutes /, '')
50+
end
51+
52+
def mask_document(model)
53+
scope = prepair_scope model
54+
55+
if model['delete']
56+
delete_documents scope, model
57+
else
58+
mask_each_document scope, model
59+
end
60+
rescue StandardError => e
61+
puts "\nCan't mask #{model['name']}" unless @config['silent']
62+
raise e
63+
ensure
64+
puts '' unless @config['silent']
65+
end
66+
67+
def delete_documents(scope, model)
68+
puts "Deleting #{model['name']}"
69+
scope.delete_many
70+
end
71+
72+
def mask_each_document(scope, model)
73+
total = scope.count()
74+
75+
scope.each_with_index do |document, index|
76+
print "Masking #{model['name']} (#{index + 1}/#{total})\r" unless @config['silent']
77+
mask = create_mask model['fields']
78+
79+
apply_mask(document, mask)
80+
db[model['name']].find({_id: document['_id']}).update_one(document)
81+
end
82+
end
83+
84+
def prepair_scope(model)
85+
scope = db[model['name']]
86+
scope.find(parse_condition(model['condition']))
87+
end
88+
89+
def parse_condition condition
90+
if condition.is_a?(String) && condition.match?(/^BSON::ObjectId\('[A-Za-z0-9]+'\)$/)
91+
return eval(condition)
92+
end
93+
94+
if condition.is_a?(Hash)
95+
condition.each do |op, value|
96+
condition[op] = parse_condition value
97+
end
98+
return condition
99+
end
100+
101+
if condition.is_a?(Array)
102+
return condition.map do |value|
103+
parse_condition value
104+
end
105+
end
106+
107+
condition
108+
end
109+
110+
def create_mask(fields)
111+
mask = {}
112+
fields.each do |field, value|
113+
if value.is_a?(Symbol)
114+
sub_mask = create_mask @config['models'].find{|model| model['name'] == value.to_s}['fields']
115+
mask[field] = sub_mask
116+
next
117+
end
118+
119+
mask[field] = evalute_field_value(value)
120+
end
121+
mask
122+
end
123+
124+
def apply_mask(document, mask)
125+
mask = mask.reject do |field, _value|
126+
document[field].nil?
127+
end
128+
document.update(mask)
129+
end
130+
131+
def evalute_field_value(value)
132+
eval(value)
133+
rescue StandardError
134+
raise "Can't eval `#{value}`"
135+
end
136+
137+
def load_from_yaml(config_path)
138+
YAML.load_file config_path
139+
end
140+
end
141+
end

masker.rb

-14
This file was deleted.

mongo_masker.gemspec

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Gem::Specification.new do |s|
2+
s.name = 'mongo_masker'
3+
s.version = '1.0.0'
4+
s.date = '2019-02-19'
5+
s.summary = 'Mongo masker'
6+
s.description = 'Masking production data mongodb for testing/development'
7+
s.authors = ['Clicia Scarlet']
8+
s.email = ['[email protected]']
9+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
10+
s.bindir = 'bin'
11+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
12+
s.require_paths = ['lib']
13+
s.homepage = 'https://github.com/basicinc/Masker'
14+
s.license = 'MIT'
15+
16+
s.add_runtime_dependency 'thor'
17+
s.add_runtime_dependency 'mongo'
18+
s.add_runtime_dependency 'ffaker'
19+
s.add_runtime_dependency 'irb'
20+
21+
s.add_development_dependency 'bundler'
22+
s.add_development_dependency 'rake'
23+
end

0 commit comments

Comments
 (0)