Commit 2e2bd9b2 authored by Mike Kozono's avatar Mike Kozono

Feature flag Geo framework verification

For replicables in the Geo self-service framework, by default, this:

- hides primary checksum progress bars
- stops the primary from enqueuing checksum jobs for new records

The above is appropriate and should have been the case before, because
verification is still under development.

Package file verification gets its own feature flag so we can release it
first by itself. Package file verification can be enabled by running in
Rails console:

- `Feature.enabled?(:geo_package_file_verification)`

Verification of non-package files (MR diffs, Terraform states, Snippet
repositories) can be enabled with:

- `Feature.enabled?(:geo_framework_verification)`
parent d4817475
...@@ -7,15 +7,41 @@ module Geo ...@@ -7,15 +7,41 @@ module Geo
include Delay include Delay
class_methods do class_methods do
# If replication is disabled, then so is verification.
def verification_enabled?
enabled? && verification_feature_flag_enabled?
end
# Overridden by PackageFileReplicator with its own feature flag so we can
# release verification for PackageFileReplicator alone, at first.
# This feature flag name is not dynamic like the replication feature flag,
# because Geo is proliferating too many permanent feature flags, and if
# there is a serious bug with verification that needs to be shut off
# immediately, then the replication feature flag can be disabled until it
# is fixed. This feature flag is intended to be removed after it is
# defaulted on.
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46998 for more
def verification_feature_flag_enabled?
Feature.enabled?(:geo_framework_verification)
end
def checksummed def checksummed
model.available_replicables.checksummed model.available_replicables.checksummed
end end
def checksummed_count def checksummed_count
# When verification is disabled, this returns nil.
# Bonus: This causes the progress bar to be hidden.
return unless verification_enabled?
model.available_replicables.checksummed.count model.available_replicables.checksummed.count
end end
def checksum_failed_count def checksum_failed_count
# When verification is disabled, this returns nil.
# Bonus: This causes the progress bar to be hidden.
return unless verification_enabled?
model.available_replicables.checksum_failed.count model.available_replicables.checksum_failed.count
end end
end end
...@@ -41,6 +67,7 @@ module Geo ...@@ -41,6 +67,7 @@ module Geo
end end
def needs_checksum? def needs_checksum?
return false unless self.class.verification_enabled?
return true unless model_record.respond_to?(:needs_checksum?) return true unless model_record.respond_to?(:needs_checksum?)
model_record.needs_checksum? model_record.needs_checksum?
......
...@@ -8,6 +8,12 @@ module Geo ...@@ -8,6 +8,12 @@ module Geo
::Packages::PackageFile ::Packages::PackageFile
end end
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46998 for
# reasoning about this override.
def self.verification_feature_flag_enabled?
Feature.enabled?(:geo_package_file_verification)
end
def carrierwave_uploader def carrierwave_uploader
model_record.file model_record.file
end end
......
---
name: geo_framework_verification
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46998
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/277400
milestone: '13.6'
type: development
group: group::geo
default_enabled: false
---
name: geo_package_file_verification
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46998
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/271680
milestone: '13.6'
type: development
group: group::geo
default_enabled: false
...@@ -82,7 +82,10 @@ module Gitlab ...@@ -82,7 +82,10 @@ module Gitlab
[].tap do |status| [].tap do |status|
Gitlab::Geo.enabled_replicator_classes.each do |replicator_class| Gitlab::Geo.enabled_replicator_classes.each do |replicator_class|
status.push current_node_status.synced_in_percentage_for(replicator_class) status.push current_node_status.synced_in_percentage_for(replicator_class)
status.push current_node_status.checksummed_in_percentage_for(replicator_class)
if replicator_class.verification_enabled?
status.push current_node_status.checksummed_in_percentage_for(replicator_class)
end
end end
if Gitlab::Geo.repository_verification_enabled? if Gitlab::Geo.repository_verification_enabled?
...@@ -280,7 +283,9 @@ module Gitlab ...@@ -280,7 +283,9 @@ module Gitlab
end end
def print_replicators_checked_status def print_replicators_checked_status
Gitlab::Geo.enabled_replicator_classes.each do |replicator_class| verifiable_replicator_classes = Gitlab::Geo.enabled_replicator_classes.select(&:verification_enabled?)
verifiable_replicator_classes.each do |replicator_class|
print "#{replicator_class.replicable_title_plural} Checked: ".rjust(GEO_STATUS_COLUMN_WIDTH) print "#{replicator_class.replicable_title_plural} Checked: ".rjust(GEO_STATUS_COLUMN_WIDTH)
show_failed_value(replicator_class.checksum_failed_count) show_failed_value(replicator_class.checksum_failed_count)
print "#{replicator_class.checksummed_count}/#{replicator_class.registry_count} " print "#{replicator_class.checksummed_count}/#{replicator_class.registry_count} "
......
...@@ -15,7 +15,7 @@ RSpec.describe Gitlab::Geo::GeoNodeStatusCheck do ...@@ -15,7 +15,7 @@ RSpec.describe Gitlab::Geo::GeoNodeStatusCheck do
allow(Gitlab.config.geo.registry_replication).to receive(:enabled).and_return(true) allow(Gitlab.config.geo.registry_replication).to receive(:enabled).and_return(true)
end end
it 'prints messages for all verification checks' do it 'prints messages for all legacy replication and verification checks' do
checks = [ checks = [
/Repositories: /, /Repositories: /,
/Verified Repositories: /, /Verified Repositories: /,
...@@ -27,14 +27,55 @@ RSpec.describe Gitlab::Geo::GeoNodeStatusCheck do ...@@ -27,14 +27,55 @@ RSpec.describe Gitlab::Geo::GeoNodeStatusCheck do
/Container repositories: /, /Container repositories: /,
/Design repositories: /, /Design repositories: /,
/Repositories Checked: / /Repositories Checked: /
] + Gitlab::Geo.enabled_replicator_classes.map { |k| /#{k.replicable_title_plural} Checked:/ } + ]
Gitlab::Geo.enabled_replicator_classes.map { |k| /#{k.replicable_title_plural}:/ }
checks.each do |text| checks.each do |text|
expect { subject.print_replication_verification_status }.to output(text).to_stdout expect { subject.print_replication_verification_status }.to output(text).to_stdout
end end
end end
context 'Replicators' do
let(:replicators) { Gitlab::Geo.enabled_replicator_classes }
context 'replication' do
let(:checks) do
replicators.map { |k| /#{k.replicable_title_plural}:/ }
end
it 'prints messages for replication' do
checks.each do |text|
expect { subject.print_replication_verification_status }.to output(text).to_stdout
end
end
end
context 'verification' do
let(:checks) do
replicators.map { |k| /#{k.replicable_title_plural} Checked:/ }
end
context 'when verification is enabled' do
it 'prints messages for verification checks' do
checks.each do |text|
expect { subject.print_replication_verification_status }.to output(text).to_stdout
end
end
end
context 'when verification is disabled' do
it 'does not print messages for verification checks' do
replicators.each do |replicator|
allow(replicator).to receive(:verification_enabled?).and_return(false)
end
checks.each do |text|
expect { subject.print_replication_verification_status }.not_to output(text).to_stdout
end
end
end
end
end
context 'when replication is up-to-date' do context 'when replication is up-to-date' do
it 'returns true' do it 'returns true' do
expect(subject.replication_verification_complete?).to be_truthy expect(subject.replication_verification_complete?).to be_truthy
......
...@@ -1146,101 +1146,140 @@ RSpec.describe GeoNodeStatus, :geo do ...@@ -1146,101 +1146,140 @@ RSpec.describe GeoNodeStatus, :geo do
end end
end end
where(:replicator, :model_factory, :registry_factory) do context 'Replicator stats' do
Geo::MergeRequestDiffReplicator | :external_merge_request_diff | :geo_merge_request_diff_registry where(:replicator, :model_factory, :registry_factory) do
Geo::PackageFileReplicator | :package_file | :geo_package_file_registry Geo::MergeRequestDiffReplicator | :external_merge_request_diff | :geo_merge_request_diff_registry
Geo::TerraformStateVersionReplicator | :terraform_state_version | :geo_terraform_state_version_registry Geo::PackageFileReplicator | :package_file | :geo_package_file_registry
Geo::SnippetRepositoryReplicator | :snippet_repository | :geo_snippet_repository_registry Geo::TerraformStateVersionReplicator | :terraform_state_version | :geo_terraform_state_version_registry
end Geo::SnippetRepositoryReplicator | :snippet_repository | :geo_snippet_repository_registry
end
with_them do
let(:replicable_name) { replicator.replicable_name_plural } with_them do
let(:checksummed_count_method) { "#{replicable_name}_checksummed_count" } let(:replicable_name) { replicator.replicable_name_plural }
let(:checksum_failed_count_method) { "#{replicable_name}_checksum_failed_count" }
let(:checksummed_in_percentage_method) { "#{replicable_name}_checksummed_in_percentage" } context 'replication' do
let(:registry_count_method) { "#{replicable_name}_registry_count" } let(:registry_count_method) { "#{replicable_name}_registry_count" }
let(:failed_count_method) { "#{replicable_name}_failed_count" } let(:failed_count_method) { "#{replicable_name}_failed_count" }
let(:synced_count_method) { "#{replicable_name}_synced_count" } let(:synced_count_method) { "#{replicable_name}_synced_count" }
let(:synced_in_percentage_method) { "#{replicable_name}_synced_in_percentage" } let(:synced_in_percentage_method) { "#{replicable_name}_synced_in_percentage" }
describe '#<replicable_name>_checksummed_count' do describe '#<replicable_name>_[registry|synced|failed]_count' do
before do context 'when package registries available' do
stub_current_geo_node(primary) before do
end create(registry_factory, :failed)
create(registry_factory, :failed)
it 'returns the right number of checksummed replicables' do create(registry_factory, :synced)
create(model_factory, :checksummed) end
create(model_factory, :checksummed)
create(model_factory, :checksum_failure) it 'returns the right number of repos in registry' do
expect(subject.send(registry_count_method)).to eq(3)
expect(subject.send(checksummed_count_method)).to eq(2) end
end
end it 'returns the right number of failed and synced repos' do
expect(subject.send(failed_count_method)).to eq(2)
describe '#<replicable_name>_checksum_failed_count' do expect(subject.send(synced_count_method)).to eq(1)
before do end
stub_current_geo_node(primary)
end it 'returns the percent of synced replicables' do
expect(subject.send(synced_in_percentage_method)).to be_within(0.01).of(33.33)
it 'returns the right number of failed replicables' do end
create(model_factory, :checksummed) end
create(model_factory, :checksum_failure)
create(model_factory, :checksum_failure) context 'when no package registries available' do
it 'returns 0' do
expect(subject.send(checksum_failed_count_method)).to eq(2) expect(subject.send(registry_count_method)).to eq(0)
end expect(subject.send(failed_count_method)).to eq(0)
end expect(subject.send(synced_count_method)).to eq(0)
end
describe '#<replicable_name>_checksummed_in_percentage' do
before do it 'returns 0' do
stub_current_geo_node(primary) expect(subject.send(synced_in_percentage_method)).to eq(0)
end end
end
it 'returns 0 when no replicables available' do
expect(subject.send(checksummed_in_percentage_method)).to eq(0)
end
it 'returns the right percentage' do
create(model_factory, :checksummed)
create(model_factory, :checksummed)
create(model_factory, :checksummed)
create(model_factory, :checksum_failure)
expect(subject.send(checksummed_in_percentage_method)).to be_within(0.0001).of(75)
end
end
describe '#<replicable_name>_[registry|synced|failed]_count' do
context 'when package registries available' do
before do
create(registry_factory, :failed)
create(registry_factory, :failed)
create(registry_factory, :synced)
end
it 'returns the right number of repos in registry' do
expect(subject.send(registry_count_method)).to eq(3)
end
it 'returns the right number of failed and synced repos' do
expect(subject.send(failed_count_method)).to eq(2)
expect(subject.send(synced_count_method)).to eq(1)
end
it 'returns the percent of synced replicables' do
expect(subject.send(synced_in_percentage_method)).to be_within(0.01).of(33.33)
end end
end end
context 'when no package registries available' do context 'verification' do
it 'returns 0' do let(:checksummed_count_method) { "#{replicable_name}_checksummed_count" }
expect(subject.send(registry_count_method)).to eq(0) let(:checksum_failed_count_method) { "#{replicable_name}_checksum_failed_count" }
expect(subject.send(failed_count_method)).to eq(0) let(:checksummed_in_percentage_method) { "#{replicable_name}_checksummed_in_percentage" }
expect(subject.send(synced_count_method)).to eq(0)
context 'when verification is enabled' do
before do
stub_current_geo_node(primary)
allow(replicator).to receive(:verification_enabled?).and_return(true)
end
context 'when there are replicables' do
before do
create(model_factory, :checksummed)
create(model_factory, :checksummed)
create(model_factory, :checksum_failure)
end
describe '#<replicable_name>_checksummed_count' do
it 'returns the right number of checksummed replicables' do
expect(subject.send(checksummed_count_method)).to eq(2)
end
end
describe '#<replicable_name>_checksum_failed_count' do
it 'returns the right number of failed replicables' do
expect(subject.send(checksum_failed_count_method)).to eq(1)
end
end
describe '#<replicable_name>_checksummed_in_percentage' do
it 'returns the right percentage' do
expect(subject.send(checksummed_in_percentage_method)).to be_within(0.01).of(66.67)
end
end
end
context 'when there are no replicables' do
describe '#<replicable_name>_checksummed_count' do
it 'returns 0' do
expect(subject.send(checksummed_count_method)).to eq(0)
end
end
describe '#<replicable_name>_checksum_failed_count' do
it 'returns 0' do
expect(subject.send(checksum_failed_count_method)).to eq(0)
end
end
describe '#<replicable_name>_checksummed_in_percentage' do
it 'returns 0' do
expect(subject.send(checksummed_in_percentage_method)).to eq(0)
end
end
end
end end
it 'returns 0' do context 'when verification is disabled' do
expect(subject.send(synced_in_percentage_method)).to eq(0) before do
stub_current_geo_node(primary)
allow(replicator).to receive(:verification_enabled?).and_return(false)
end
describe '#<replicable_name>_checksummed_count' do
it 'returns nil' do
expect(subject.send(checksummed_count_method)).to be_nil
end
end
describe '#<replicable_name>_checksum_failed_count' do
it 'returns nil' do
expect(subject.send(checksum_failed_count_method)).to be_nil
end
end
describe '#<replicable_name>_checksummed_in_percentage' do
it 'returns 0' do
expect(subject.send(checksummed_in_percentage_method)).to eq(0)
end
end
end end
end end
end end
......
...@@ -5,6 +5,40 @@ ...@@ -5,6 +5,40 @@
RSpec.shared_examples 'a verifiable replicator' do RSpec.shared_examples 'a verifiable replicator' do
include EE::GeoHelpers include EE::GeoHelpers
describe '.verification_enabled?' do
context 'when replication is enabled' do
before do
expect(described_class).to receive(:enabled?).and_return(true)
end
context 'when the verification feature flag is enabled' do
it 'returns true' do
allow(described_class).to receive(:verification_feature_flag_enabled?).and_return(true)
expect(described_class.verification_enabled?).to be_truthy
end
end
context 'when geo_framework_verification feature flag is disabled' do
it 'returns false' do
allow(described_class).to receive(:verification_feature_flag_enabled?).and_return(false)
expect(described_class.verification_enabled?).to be_falsey
end
end
end
context 'when replication is disabled' do
before do
expect(described_class).to receive(:enabled?).and_return(false)
end
it 'returns false' do
expect(described_class.verification_enabled?).to be_falsey
end
end
end
describe '#after_verifiable_update' do describe '#after_verifiable_update' do
it 'schedules the checksum calculation if needed' do it 'schedules the checksum calculation if needed' do
expect(replicator).to receive(:schedule_checksum_calculation) expect(replicator).to receive(:schedule_checksum_calculation)
......
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