2016-10-19 03:11:36 +00:00
|
|
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
class Store
|
|
|
|
class File < ApplicationModel
|
|
|
|
include ApplicationLib
|
|
|
|
after_destroy :destroy_provider
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-07-26 21:35:56 +00:00
|
|
|
=begin
|
2015-07-26 21:21:51 +00:00
|
|
|
|
|
|
|
add new file to store
|
|
|
|
|
2016-05-30 23:15:01 +00:00
|
|
|
store_file_id = Store::File.add(binary_data)
|
2015-07-26 21:21:51 +00:00
|
|
|
|
2016-02-07 15:36:10 +00:00
|
|
|
do also verify of written data
|
|
|
|
|
2016-05-30 23:15:01 +00:00
|
|
|
store_file_id = Store::File.add(binary_data, true)
|
2016-02-07 15:36:10 +00:00
|
|
|
|
2015-07-26 21:21:51 +00:00
|
|
|
=end
|
|
|
|
|
2016-02-07 15:36:10 +00:00
|
|
|
def self.add(data, verify = true)
|
2016-02-02 12:50:49 +00:00
|
|
|
sha = Digest::SHA256.hexdigest(data)
|
2014-05-03 14:52:37 +00:00
|
|
|
|
2016-02-02 12:50:49 +00:00
|
|
|
file = Store::File.find_by(sha: sha)
|
2015-05-07 10:11:45 +00:00
|
|
|
if file.nil?
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
# load backend based on config
|
|
|
|
adapter_name = Setting.get('storage_provider') || 'DB'
|
|
|
|
if !adapter_name
|
2016-03-01 14:26:46 +00:00
|
|
|
raise 'Missing storage_provider setting option'
|
2015-04-27 21:44:41 +00:00
|
|
|
end
|
2016-02-02 12:50:49 +00:00
|
|
|
adapter = load_adapter("Store::Provider::#{adapter_name}")
|
|
|
|
adapter.add(data, sha)
|
2015-04-27 21:44:41 +00:00
|
|
|
file = Store::File.create(
|
|
|
|
provider: adapter_name,
|
|
|
|
sha: sha,
|
|
|
|
)
|
2016-02-07 15:36:10 +00:00
|
|
|
|
|
|
|
# verify
|
|
|
|
if verify
|
|
|
|
read_data = adapter.get(sha)
|
|
|
|
read_sha = Digest::SHA256.hexdigest(read_data)
|
|
|
|
if sha != read_sha
|
2016-03-01 14:26:46 +00:00
|
|
|
raise "Content not written correctly (provider #{adapter_name})."
|
2016-02-07 15:36:10 +00:00
|
|
|
end
|
|
|
|
end
|
2014-05-03 12:34:36 +00:00
|
|
|
end
|
2015-04-27 21:44:41 +00:00
|
|
|
file
|
2014-05-03 12:34:36 +00:00
|
|
|
end
|
|
|
|
|
2015-07-26 21:21:51 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
read content of a file
|
|
|
|
|
2016-05-30 23:15:01 +00:00
|
|
|
store = Store::File.find(123)
|
2015-07-26 21:21:51 +00:00
|
|
|
|
2016-05-30 23:15:01 +00:00
|
|
|
store.content # returns binary
|
2015-07-26 21:21:51 +00:00
|
|
|
|
|
|
|
=end
|
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
def content
|
2015-07-03 15:18:01 +00:00
|
|
|
adapter = self.class.load_adapter("Store::Provider::#{provider}")
|
2016-02-02 13:08:27 +00:00
|
|
|
adapter.get(sha)
|
2014-05-03 19:02:38 +00:00
|
|
|
end
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-07-26 21:21:51 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
file system check of store, check data and sha (in case fix it)
|
|
|
|
|
2016-05-30 23:15:01 +00:00
|
|
|
Store::File.verify
|
2015-07-26 21:21:51 +00:00
|
|
|
|
|
|
|
read each file which should be in backend and verify agsinst sha hash
|
|
|
|
|
|
|
|
in case of fixing sha hash use:
|
|
|
|
|
2016-05-30 23:15:01 +00:00
|
|
|
Store::File.verify(true)
|
2015-07-26 21:21:51 +00:00
|
|
|
|
|
|
|
=end
|
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
def self.verify(fix_it = nil)
|
|
|
|
success = true
|
2017-06-19 06:23:07 +00:00
|
|
|
file_ids = Store::File.all.pluck(:id)
|
2017-10-01 12:25:52 +00:00
|
|
|
file_ids.each do |item_id|
|
2017-06-19 06:23:07 +00:00
|
|
|
item = Store::File.find(item_id)
|
2015-04-27 21:44:41 +00:00
|
|
|
content = item.content
|
2016-02-02 12:50:49 +00:00
|
|
|
sha = Digest::SHA256.hexdigest(content)
|
|
|
|
logger.info "CHECK: Store::File.find(#{item.id})"
|
2015-05-07 09:04:40 +00:00
|
|
|
next if sha == item.sha
|
|
|
|
success = false
|
2016-02-02 12:50:49 +00:00
|
|
|
logger.error "DIFF: sha diff of Store::File.find(#{item.id}) current:#{sha}/db:#{item.sha}/provider:#{item.provider}"
|
2016-02-02 13:08:27 +00:00
|
|
|
store = Store.find_by(store_file_id: item.id)
|
2016-02-02 12:50:49 +00:00
|
|
|
logger.error "STORE: #{store.inspect}"
|
2015-05-07 09:04:40 +00:00
|
|
|
if fix_it
|
2016-02-02 12:50:49 +00:00
|
|
|
item.update_attribute(:sha, sha)
|
2014-05-03 12:34:36 +00:00
|
|
|
end
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-04-27 21:44:41 +00:00
|
|
|
success
|
|
|
|
end
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-07-26 21:21:51 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
move file from one to other provider
|
|
|
|
|
|
|
|
move files from file backend to db
|
|
|
|
|
|
|
|
Store::File.move('File', 'DB')
|
|
|
|
|
|
|
|
move files from db backend to fs
|
|
|
|
|
|
|
|
Store::File.move('DB', 'File')
|
|
|
|
|
2017-03-06 11:18:04 +00:00
|
|
|
nice move to keep system responsive
|
|
|
|
|
|
|
|
Store::File.move('DB', 'File', delay_in_sec) # e. g. 1
|
|
|
|
|
2015-07-26 21:21:51 +00:00
|
|
|
=end
|
|
|
|
|
2017-03-06 11:18:04 +00:00
|
|
|
def self.move(source, target, delay = nil)
|
2015-07-03 15:18:01 +00:00
|
|
|
adapter_source = load_adapter("Store::Provider::#{source}")
|
|
|
|
adapter_target = load_adapter("Store::Provider::#{target}")
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2017-06-16 22:54:20 +00:00
|
|
|
file_ids = Store::File.all.pluck(:id)
|
2017-10-01 12:25:52 +00:00
|
|
|
file_ids.each do |item_id|
|
2017-06-16 22:54:20 +00:00
|
|
|
item = Store::File.find(item_id)
|
2015-04-27 21:44:41 +00:00
|
|
|
next if item.provider == target
|
|
|
|
content = item.content
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
# add to new provider
|
2016-02-02 12:50:49 +00:00
|
|
|
adapter_target.add(content, item.sha)
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
# update meta data
|
2016-02-02 12:50:49 +00:00
|
|
|
item.update_attribute(:provider, target)
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
# remove from old provider
|
2016-02-02 12:50:49 +00:00
|
|
|
adapter_source.delete(item.sha)
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-05-05 08:11:31 +00:00
|
|
|
logger.info "Moved file #{item.sha} from #{source} to #{target}"
|
2017-03-06 11:18:04 +00:00
|
|
|
|
|
|
|
sleep delay if delay
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-04-27 21:44:41 +00:00
|
|
|
true
|
|
|
|
end
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
private
|
2014-05-03 12:34:36 +00:00
|
|
|
|
2015-04-27 21:44:41 +00:00
|
|
|
def destroy_provider
|
2015-07-03 15:18:01 +00:00
|
|
|
adapter = self.class.load_adapter("Store::Provider::#{provider}")
|
2016-02-02 12:50:49 +00:00
|
|
|
adapter.delete(sha)
|
2015-04-27 21:44:41 +00:00
|
|
|
end
|
2014-05-03 12:34:36 +00:00
|
|
|
end
|
2015-04-27 14:15:29 +00:00
|
|
|
end
|