Commit e855f37f authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch 'mk/remove-local-method-requirement' into 'master'

Geo: Minor refactors to verification

See merge request gitlab-org/gitlab!53340
parents f1df59c6 e8edb60d
...@@ -55,10 +55,6 @@ class Packages::PackageFile < ApplicationRecord ...@@ -55,10 +55,6 @@ class Packages::PackageFile < ApplicationRecord
Gitlab::Routing.url_helpers.download_project_package_file_path(project, self) Gitlab::Routing.url_helpers.download_project_package_file_path(project, self)
end end
def local?
file_store == ::Packages::PackageFileUploader::Store::LOCAL
end
private private
def update_size_from_file def update_size_from_file
......
...@@ -17,10 +17,6 @@ module Terraform ...@@ -17,10 +17,6 @@ module Terraform
mount_file_store_uploader StateUploader mount_file_store_uploader StateUploader
delegate :project_id, :uuid, to: :terraform_state, allow_nil: true delegate :project_id, :uuid, to: :terraform_state, allow_nil: true
def local?
file_store == ObjectStorage::Store::LOCAL
end
end end
end end
......
...@@ -189,11 +189,6 @@ For example, to add support for files referenced by a `Widget` model with a ...@@ -189,11 +189,6 @@ For example, to add support for files referenced by a `Widget` model with a
mount_uploader :file, WidgetUploader mount_uploader :file, WidgetUploader
def local?
# Must to be implemented, Check the uploader's storage types
file_store == ObjectStorage::Store::LOCAL
end
# @param primary_key_in [Range, Widget] arg to pass to primary_key_in scope # @param primary_key_in [Range, Widget] arg to pass to primary_key_in scope
# @return [ActiveRecord::Relation<Widget>] everything that should be synced to this node, restricted by primary key # @return [ActiveRecord::Relation<Widget>] everything that should be synced to this node, restricted by primary key
def self.replicables_for_current_secondary(primary_key_in) def self.replicables_for_current_secondary(primary_key_in)
......
...@@ -56,6 +56,26 @@ module Geo ...@@ -56,6 +56,26 @@ module Geo
).execute ).execute
end end
# Returns a checksum of the file
#
# @return [String] SHA256 hash of the carrierwave file
def calculate_checksum
raise 'File is not checksummable' unless checksummable?
model.hexdigest(carrierwave_uploader.path)
end
# Returns whether the file exists on disk or in remote storage
#
# Does a hard check because we are doing these checks for replication or
# verification purposes, so we should not just trust the data in the DB if
# we don't absolutely have to.
#
# @return [Boolean] whether the file exists on disk or in remote storage
def file_exists?
carrierwave_uploader.file.exists?
end
private private
def download def download
...@@ -65,5 +85,12 @@ module Geo ...@@ -65,5 +85,12 @@ module Geo
def deleted_params def deleted_params
{ model_record_id: model_record.id, blob_path: blob_path } { model_record_id: model_record.id, blob_path: blob_path }
end end
# Return whether it's capable of generating a checksum of itself
#
# @return [Boolean] whether it can generate a checksum
def checksummable?
carrierwave_uploader.file_storage? && file_exists?
end
end end
end end
...@@ -118,8 +118,9 @@ module Geo ...@@ -118,8 +118,9 @@ module Geo
end end
end end
# Schedules a verification job after a model record is created/updated
def after_verifiable_update def after_verifiable_update
verify_async if needs_checksum? verify_async if should_primary_verify?
end end
def verify_async def verify_async
...@@ -137,7 +138,7 @@ module Geo ...@@ -137,7 +138,7 @@ module Geo
# state. # state.
def verify def verify
verification_state_tracker.track_checksum_attempt! do verification_state_tracker.track_checksum_attempt! do
model_record.calculate_checksum calculate_checksum
end end
end end
...@@ -146,14 +147,7 @@ module Geo ...@@ -146,14 +147,7 @@ module Geo
# @param [String] checksum # @param [String] checksum
# @return [Boolean] whether checksum matches # @return [Boolean] whether checksum matches
def matches_checksum?(checksum) def matches_checksum?(checksum)
model_record.verification_checksum == checksum primary_checksum == checksum
end
def needs_checksum?
return false unless self.class.verification_enabled?
return true unless model_record.respond_to?(:needs_checksum?)
model_record.needs_checksum?
end end
# Checksum value from the main database # Checksum value from the main database
...@@ -170,5 +164,25 @@ module Geo ...@@ -170,5 +164,25 @@ module Geo
def verification_state_tracker def verification_state_tracker
Gitlab::Geo.secondary? ? registry : model_record Gitlab::Geo.secondary? ? registry : model_record
end end
# @abstract
# @return [String] a checksum representing the data
def calculate_checksum
raise NotImplementedError, "#{self.class} does not implement #{__method__}"
end
private
def should_primary_verify?
self.class.verification_enabled? &&
primary_checksum.nil? && # Some models may populate this as part of creating the record
checksummable?
end
# @abstract
# @return [Boolean] whether the replicable is capable of checksumming itself
def checksummable?
raise NotImplementedError, "#{self.class} does not implement #{__method__}"
end
end end
end end
...@@ -59,10 +59,6 @@ module EE ...@@ -59,10 +59,6 @@ module EE
super || build_merge_request_diff_detail super || build_merge_request_diff_detail
end end
def local?
stored_externally? && external_diff_store == ExternalDiffUploader::Store::LOCAL
end
def log_geo_deleted_event def log_geo_deleted_event
# Keep empty for now. Should be addressed in future # Keep empty for now. Should be addressed in future
# by https://gitlab.com/gitlab-org/gitlab/issues/33817 # by https://gitlab.com/gitlab-org/gitlab/issues/33817
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
module Geo module Geo
class MergeRequestDiffReplicator < Gitlab::Geo::Replicator class MergeRequestDiffReplicator < Gitlab::Geo::Replicator
include ::Geo::BlobReplicatorStrategy include ::Geo::BlobReplicatorStrategy
extend ::Gitlab::Utils::Override
def self.model def self.model
::MergeRequestDiff ::MergeRequestDiff
...@@ -16,8 +17,12 @@ module Geo ...@@ -16,8 +17,12 @@ module Geo
model_record.external_diff model_record.external_diff
end end
def needs_checksum? private
false
# Only external diffs can be checksummed
override :checksummable?
def checksummable?
model_record.stored_externally? && super
end end
end end
end end
...@@ -12,10 +12,6 @@ module Geo ...@@ -12,10 +12,6 @@ module Geo
::Gitlab::GitAccessSnippet ::Gitlab::GitAccessSnippet
end end
def needs_checksum?
false
end
def repository def repository
model_record.repository model_record.repository
end end
......
...@@ -11,9 +11,5 @@ module Geo ...@@ -11,9 +11,5 @@ module Geo
def self.model def self.model
::Terraform::StateVersion ::Terraform::StateVersion
end end
def needs_checksum?
false
end
end end
end end
...@@ -48,44 +48,6 @@ module Gitlab ...@@ -48,44 +48,6 @@ module Gitlab
raise NotImplementedError, 'There is no Replicator defined for this model' raise NotImplementedError, 'There is no Replicator defined for this model'
end end
# Returns a checksum of the file (assumed to be a "blob" type)
#
# @return [String] SHA256 hash of the carrierwave file
def calculate_checksum
return unless checksummable?
self.class.hexdigest(replicator.carrierwave_uploader.path)
end
# Checks whether model needs checksum to be performed
#
# Conditions:
# - No checksum is present
# - It's capable of generating a checksum of itself
#
# @return [Boolean]
def needs_checksum?
verification_checksum.nil? && checksummable?
end
# Return whether its capable of generating a checksum of itself
#
# @return [Boolean] whether it can generate a checksum
def checksummable?
local? && file_exist?
end
# This checks for existence of the file on storage
#
# @return [Boolean] whether the file exists on storage
def file_exist?
if local?
File.exist?(replicator.carrierwave_uploader.path)
else
replicator.carrierwave_uploader.exists?
end
end
def in_replicables_for_current_secondary? def in_replicables_for_current_secondary?
self.class.replicables_for_current_secondary(self).exists? self.class.replicables_for_current_secondary(self).exists?
end end
......
...@@ -19,7 +19,7 @@ module Gitlab ...@@ -19,7 +19,7 @@ module Gitlab
def execute def execute
return error("#{replicator.replicable_name} not found") unless recorded_file return error("#{replicator.replicable_name} not found") unless recorded_file
return file_not_found(recorded_file) unless recorded_file.file_exist? return file_not_found(recorded_file) unless replicator.file_exists?
return error('Checksum mismatch') unless matches_checksum? return error('Checksum mismatch') unless matches_checksum?
success(replicator.carrierwave_uploader) success(replicator.carrierwave_uploader)
......
...@@ -4,22 +4,6 @@ require 'spec_helper' ...@@ -4,22 +4,6 @@ require 'spec_helper'
RSpec.describe Packages::PackageFile, type: :model do RSpec.describe Packages::PackageFile, type: :model do
include ::EE::GeoHelpers include ::EE::GeoHelpers
describe '#calculate_checksum' do
let(:package_file) { create(:conan_package_file, :conan_recipe_file) }
it 'returns SHA256 sum of the file' do
expected = Digest::SHA256.file(package_file.file.path).hexdigest
expect(package_file.calculate_checksum).to eq(expected)
end
it 'returns nil for a non-existent file' do
allow(package_file).to receive(:file_exist?).and_return(false)
expect(package_file.calculate_checksum).to eq(nil)
end
end
context 'new file' do context 'new file' do
it 'calls checksum worker' do it 'calls checksum worker' do
stub_primary_node stub_primary_node
......
...@@ -23,7 +23,7 @@ RSpec.describe Geo::EventService do ...@@ -23,7 +23,7 @@ RSpec.describe Geo::EventService do
it 'executes the consume part of the replication' do it 'executes the consume part of the replication' do
subject.execute subject.execute
expect(model_record.file_exist?).to be_truthy expect(model_record.file.exists?).to be_truthy
end end
end end
end end
...@@ -169,4 +169,32 @@ RSpec.shared_examples 'a blob replicator' do ...@@ -169,4 +169,32 @@ RSpec.shared_examples 'a blob replicator' do
end end
end end
end end
describe '#calculate_checksum' do
context 'when the file is locally stored' do
context 'when the file exists' do
it 'returns hexdigest of the file' do
expected = described_class.model.hexdigest(subject.carrierwave_uploader.path)
expect(subject.calculate_checksum).to eq(expected)
end
end
context 'when the file does not exist' do
it 'raises an error' do
allow(subject).to receive(:file_exists?).and_return(false)
expect { subject.calculate_checksum }.to raise_error('File is not checksummable')
end
end
end
context 'when the file is remotely stored' do
it 'raises an error' do
allow(subject.carrierwave_uploader).to receive(:file_storage?).and_return(false)
expect { subject.calculate_checksum }.to raise_error('File is not checksummable')
end
end
end
end end
...@@ -299,8 +299,11 @@ RSpec.shared_examples 'a verifiable replicator' do ...@@ -299,8 +299,11 @@ RSpec.shared_examples 'a verifiable replicator' do
describe '#after_verifiable_update' do describe '#after_verifiable_update' do
it 'calls verify_async if needed' do it 'calls verify_async if needed' do
allow(described_class).to receive(:verification_enabled?).and_return(true)
allow(replicator).to receive(:primary_checksum).and_return(nil)
allow(replicator).to receive(:checksummable?).and_return(true)
expect(replicator).to receive(:verify_async) expect(replicator).to receive(:verify_async)
expect(replicator).to receive(:needs_checksum?).and_return(true)
replicator.after_verifiable_update replicator.after_verifiable_update
end end
...@@ -329,8 +332,8 @@ RSpec.shared_examples 'a verifiable replicator' do ...@@ -329,8 +332,8 @@ RSpec.shared_examples 'a verifiable replicator' do
it 'wraps the checksum calculation in track_checksum_attempt!' do it 'wraps the checksum calculation in track_checksum_attempt!' do
tracker = double('tracker') tracker = double('tracker')
allow(replicator).to receive(:verification_state_tracker).and_return(tracker) allow(replicator).to receive(:verification_state_tracker).and_return(tracker)
allow(replicator).to receive(:calculate_checksum).and_return('abc123')
expect(model_record).to receive(:calculate_checksum)
expect(tracker).to receive(:track_checksum_attempt!).and_yield expect(tracker).to receive(:track_checksum_attempt!).and_yield
replicator.verify replicator.verify
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment