Commit 3f93c12b authored by Stan Hu's avatar Stan Hu

Merge branch 'master' into ce-to-ee-2018-03-28

parents a15a7956 8e8c03f4
...@@ -15,6 +15,7 @@ app/models/project_services/packagist_service.rb ...@@ -15,6 +15,7 @@ app/models/project_services/packagist_service.rb
lib/gitlab/background_migration/normalize_ldap_extern_uids_range.rb lib/gitlab/background_migration/normalize_ldap_extern_uids_range.rb
lib/gitlab/background_migration/* lib/gitlab/background_migration/*
app/models/project_services/kubernetes_service.rb app/models/project_services/kubernetes_service.rb
lib/gitlab/workhorse.rb
ee/db/**/* ee/db/**/*
ee/app/serializers/ee/merge_request_widget_entity.rb ee/app/serializers/ee/merge_request_widget_entity.rb
......
...@@ -436,7 +436,7 @@ group :ed25519 do ...@@ -436,7 +436,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 0.88.0', require: 'gitaly' gem 'gitaly-proto', '~> 0.91.0', require: 'gitaly'
gem 'grpc', '~> 1.10.0' gem 'grpc', '~> 1.10.0'
# Locked until https://github.com/google/protobuf/issues/4210 is closed # Locked until https://github.com/google/protobuf/issues/4210 is closed
......
...@@ -314,7 +314,7 @@ GEM ...@@ -314,7 +314,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
gitaly-proto (0.88.0) gitaly-proto (0.91.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.0) grpc (~> 1.0)
github-linguist (5.3.3) github-linguist (5.3.3)
...@@ -1096,7 +1096,7 @@ DEPENDENCIES ...@@ -1096,7 +1096,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.88.0) gitaly-proto (~> 0.91.0)
github-linguist (~> 5.3.3) github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
......
---
title: Make all workhorse gitaly calls opt-out, take 2
merge_request: 18043
author:
type: other
---
title: Test if remote repository exists when importing wikis
merge_request:
author:
type: fixed
...@@ -204,6 +204,7 @@ ...@@ -204,6 +204,7 @@
<template v-if="showAdvanceItems"> <template v-if="showAdvanceItems">
<template v-if="node.primary"> <template v-if="node.primary">
<geo-node-detail-item <geo-node-detail-item
v-if="nodeDetails.repositoryVerificationEnabled"
:item-title="s__('GeoNodes|Repositories checksummed:')" :item-title="s__('GeoNodes|Repositories checksummed:')"
:success-label="s__('GeoNodes|Checksummed')" :success-label="s__('GeoNodes|Checksummed')"
:neutral-label="s__('GeoNodes|Not checksummed')" :neutral-label="s__('GeoNodes|Not checksummed')"
...@@ -212,6 +213,7 @@ ...@@ -212,6 +213,7 @@
:item-value-type="valueType.GRAPH" :item-value-type="valueType.GRAPH"
/> />
<geo-node-detail-item <geo-node-detail-item
v-if="nodeDetails.repositoryVerificationEnabled"
:item-title="s__('GeoNodes|Wikis checksummed:')" :item-title="s__('GeoNodes|Wikis checksummed:')"
:success-label="s__('GeoNodes|Checksummed')" :success-label="s__('GeoNodes|Checksummed')"
:neutral-label="s__('GeoNodes|Not checksummed')" :neutral-label="s__('GeoNodes|Not checksummed')"
...@@ -236,6 +238,7 @@ ...@@ -236,6 +238,7 @@
</template> </template>
<template v-else> <template v-else>
<geo-node-detail-item <geo-node-detail-item
v-if="nodeDetails.repositoryVerificationEnabled"
:item-title="s__('GeoNodes|Repository checksums verified:')" :item-title="s__('GeoNodes|Repository checksums verified:')"
:success-label="s__('GeoNodes|Verified')" :success-label="s__('GeoNodes|Verified')"
:neutral-label="s__('GeoNodes|Unverified')" :neutral-label="s__('GeoNodes|Unverified')"
...@@ -244,6 +247,7 @@ ...@@ -244,6 +247,7 @@
:item-value-type="valueType.GRAPH" :item-value-type="valueType.GRAPH"
/> />
<geo-node-detail-item <geo-node-detail-item
v-if="nodeDetails.repositoryVerificationEnabled"
:item-title="s__('GeoNodes|Wiki checksums verified:')" :item-title="s__('GeoNodes|Wiki checksums verified:')"
:success-label="s__('GeoNodes|Verified')" :success-label="s__('GeoNodes|Verified')"
:neutral-label="s__('GeoNodes|Unverified')" :neutral-label="s__('GeoNodes|Unverified')"
......
...@@ -87,6 +87,7 @@ export default class GeoNodesStore { ...@@ -87,6 +87,7 @@ export default class GeoNodesStore {
successCount: rawNodeDetails.wikis_synced_count || 0, successCount: rawNodeDetails.wikis_synced_count || 0,
failureCount: rawNodeDetails.wikis_failed_count || 0, failureCount: rawNodeDetails.wikis_failed_count || 0,
}, },
repositoryVerificationEnabled: rawNodeDetails.repository_verification_enabled,
verifiedRepositories: { verifiedRepositories: {
totalCount: rawNodeDetails.repositories_count || 0, totalCount: rawNodeDetails.repositories_count || 0,
successCount: rawNodeDetails.repositories_verified_count || 0, successCount: rawNodeDetails.repositories_verified_count || 0,
......
...@@ -3,11 +3,15 @@ class GeoNodeStatus < ActiveRecord::Base ...@@ -3,11 +3,15 @@ class GeoNodeStatus < ActiveRecord::Base
delegate :selective_sync_type, to: :geo_node delegate :selective_sync_type, to: :geo_node
after_initialize :initialize_feature_flags
# Whether we were successful in reaching this node # Whether we were successful in reaching this node
attr_accessor :success attr_accessor :success
attr_writer :health_status attr_writer :health_status
attr_accessor :storage_shards attr_accessor :storage_shards
attr_accessor :repository_verification_enabled
# Prometheus metrics, no need to store them in the database # Prometheus metrics, no need to store them in the database
attr_accessor :event_log_count, :event_log_max_id, attr_accessor :event_log_count, :event_log_max_id,
:repository_created_max_id, :repository_updated_max_id, :repository_created_max_id, :repository_updated_max_id,
...@@ -98,6 +102,10 @@ class GeoNodeStatus < ActiveRecord::Base ...@@ -98,6 +102,10 @@ class GeoNodeStatus < ActiveRecord::Base
self.column_names - EXCLUDED_PARAMS + EXTRA_PARAMS self.column_names - EXCLUDED_PARAMS + EXTRA_PARAMS
end end
def initialize_feature_flags
self.repository_verification_enabled = Feature.enabled?('geo_repository_verification')
end
def load_data_from_current_node def load_data_from_current_node
self.status_message = self.status_message =
begin begin
...@@ -135,6 +143,7 @@ class GeoNodeStatus < ActiveRecord::Base ...@@ -135,6 +143,7 @@ class GeoNodeStatus < ActiveRecord::Base
load_primary_data load_primary_data
load_secondary_data load_secondary_data
load_verification_data
self self
end end
...@@ -144,10 +153,6 @@ class GeoNodeStatus < ActiveRecord::Base ...@@ -144,10 +153,6 @@ class GeoNodeStatus < ActiveRecord::Base
self.replication_slots_count = geo_node.replication_slots_count self.replication_slots_count = geo_node.replication_slots_count
self.replication_slots_used_count = geo_node.replication_slots_used_count self.replication_slots_used_count = geo_node.replication_slots_used_count
self.replication_slots_max_retained_wal_bytes = geo_node.replication_slots_max_retained_wal_bytes self.replication_slots_max_retained_wal_bytes = geo_node.replication_slots_max_retained_wal_bytes
self.repositories_verified_count = repository_verification_finder.count_verified_repositories
self.repositories_verification_failed_count = repository_verification_finder.count_verification_failed_repositories
self.wikis_verified_count = repository_verification_finder.count_verified_wikis
self.wikis_verification_failed_count = repository_verification_finder.count_verification_failed_wikis
end end
end end
...@@ -160,10 +165,6 @@ class GeoNodeStatus < ActiveRecord::Base ...@@ -160,10 +165,6 @@ class GeoNodeStatus < ActiveRecord::Base
self.repositories_failed_count = projects_finder.count_failed_repositories self.repositories_failed_count = projects_finder.count_failed_repositories
self.wikis_synced_count = projects_finder.count_synced_wikis self.wikis_synced_count = projects_finder.count_synced_wikis
self.wikis_failed_count = projects_finder.count_failed_wikis self.wikis_failed_count = projects_finder.count_failed_wikis
self.repositories_verified_count = projects_finder.count_verified_repositories
self.repositories_verification_failed_count = projects_finder.count_verification_failed_repositories
self.wikis_verified_count = projects_finder.count_verified_wikis
self.wikis_verification_failed_count = projects_finder.count_verification_failed_wikis
self.lfs_objects_synced_count = lfs_objects_finder.count_synced_lfs_objects self.lfs_objects_synced_count = lfs_objects_finder.count_synced_lfs_objects
self.lfs_objects_failed_count = lfs_objects_finder.count_failed_lfs_objects self.lfs_objects_failed_count = lfs_objects_finder.count_failed_lfs_objects
self.lfs_objects_registry_count = lfs_objects_finder.count_registry_lfs_objects self.lfs_objects_registry_count = lfs_objects_finder.count_registry_lfs_objects
...@@ -176,6 +177,16 @@ class GeoNodeStatus < ActiveRecord::Base ...@@ -176,6 +177,16 @@ class GeoNodeStatus < ActiveRecord::Base
end end
end end
def load_verification_data
return unless repository_verification_enabled
finder = Gitlab::Geo.primary? ? repository_verification_finder : projects_finder
self.repositories_verified_count = finder.count_verified_repositories
self.repositories_verification_failed_count = finder.count_verification_failed_repositories
self.wikis_verified_count = finder.count_verified_wikis
self.wikis_verification_failed_count = finder.count_verification_failed_wikis
end
alias_attribute :health, :status_message alias_attribute :health, :status_message
def healthy? def healthy?
......
---
title: Skip repository-changing events on Geo secondaries if the repository hasn't
been backfilled yet
merge_request:
author:
type: fixed
---
title: Show repository checksum UI elements only when feature is enabled
merge_request: 5341
author:
type: fixed
...@@ -293,6 +293,8 @@ module EE ...@@ -293,6 +293,8 @@ module EE
number_to_percentage(node.wikis_synced_in_percentage, precision: 2) number_to_percentage(node.wikis_synced_in_percentage, precision: 2)
end end
expose :repository_verification_enabled
expose :repositories_verification_failed_count expose :repositories_verification_failed_count
expose :repositories_verified_count expose :repositories_verified_count
expose :repositories_verified_in_percentage do |node| expose :repositories_verified_in_percentage do |node|
......
...@@ -106,34 +106,43 @@ module Gitlab ...@@ -106,34 +106,43 @@ module Gitlab
registry = find_or_initialize_registry(event.project_id, registry = find_or_initialize_registry(event.project_id,
"resync_#{event.source}" => true, "#{event.source}_verification_checksum" => nil) "resync_#{event.source}" => true, "#{event.source}_verification_checksum" => nil)
registry.save!
job_id = ::Geo::ProjectSyncWorker.perform_async(event.project_id, Time.now)
logger.event_info( logger.event_info(
created_at, created_at,
'Repository update', 'Repository update',
project_id: event.project_id, project_id: event.project_id,
source: event.source, source: event.source,
resync_repository: registry.resync_repository, resync_repository: registry.resync_repository,
resync_wiki: registry.resync_wiki) resync_wiki: registry.resync_wiki,
job_id: job_id)
registry.save!
::Geo::ProjectSyncWorker.perform_async(event.project_id, Time.now)
end end
def handle_repository_deleted_event(event, created_at) def handle_repository_deleted_event(event, created_at)
job_id = ::Geo::RepositoryDestroyService registry = find_or_initialize_registry(event.project_id)
.new(event.project_id, event.deleted_project_name, event.deleted_path, event.repository_storage_name) skippable = registry.new_record?
.async_execute
logger.event_info( params = {
created_at,
'Deleted project',
project_id: event.project_id, project_id: event.project_id,
repository_storage_name: event.repository_storage_name, repository_storage_name: event.repository_storage_name,
disk_path: event.deleted_path, disk_path: event.deleted_path,
job_id: job_id) skippable: skippable
}
unless skippable
params[:job_id] = ::Geo::RepositoryDestroyService.new(
event.project_id,
event.deleted_project_name,
event.deleted_path,
event.repository_storage_name
).async_execute
::Geo::ProjectRegistry.where(project_id: event.project_id).delete_all
end
# No need to create a project entry if it doesn't exist logger.event_info(created_at, 'Deleted project', params)
::Geo::ProjectRegistry.where(project_id: event.project_id).delete_all
end end
def handle_repositories_changed_event(event, created_at) def handle_repositories_changed_event(event, created_at)
...@@ -151,41 +160,52 @@ module Gitlab ...@@ -151,41 +160,52 @@ module Gitlab
def handle_repository_renamed_event(event, created_at) def handle_repository_renamed_event(event, created_at)
return unless event.project_id return unless event.project_id
old_path = event.old_path_with_namespace registry = find_or_initialize_registry(event.project_id)
new_path = event.new_path_with_namespace skippable = registry.new_record?
job_id = ::Geo::RenameRepositoryService
.new(event.project_id, old_path, new_path)
.async_execute
logger.event_info( params = {
created_at,
'Renaming project',
project_id: event.project_id, project_id: event.project_id,
old_path: old_path, old_path: event.old_path_with_namespace,
new_path: new_path, new_path: event.new_path_with_namespace,
job_id: job_id) skippable: skippable
}
unless skippable
params[:job_id] = ::Geo::RenameRepositoryService.new(
event.project_id,
event.old_path_with_namespace,
event.new_path_with_namespace
).async_execute
end
logger.event_info(created_at, 'Renaming project', params)
end end
def handle_hashed_storage_migrated_event(event, created_at) def handle_hashed_storage_migrated_event(event, created_at)
return unless event.project_id return unless event.project_id
job_id = ::Geo::HashedStorageMigrationService.new( registry = find_or_initialize_registry(event.project_id)
event.project_id, skippable = registry.new_record?
old_disk_path: event.old_disk_path,
new_disk_path: event.new_disk_path,
old_storage_version: event.old_storage_version
).async_execute
logger.event_info( params = {
created_at,
'Migrating project to hashed storage',
project_id: event.project_id, project_id: event.project_id,
old_storage_version: event.old_storage_version, old_storage_version: event.old_storage_version,
new_storage_version: event.new_storage_version, new_storage_version: event.new_storage_version,
old_disk_path: event.old_disk_path, old_disk_path: event.old_disk_path,
new_disk_path: event.new_disk_path, new_disk_path: event.new_disk_path,
job_id: job_id) skippable: skippable
}
unless skippable
params[:job_id] = ::Geo::HashedStorageMigrationService.new(
event.project_id,
old_disk_path: event.old_disk_path,
new_disk_path: event.new_disk_path,
old_storage_version: event.old_storage_version
).async_execute
end
logger.event_info(created_at, 'Migrating project to hashed storage', params)
end end
def handle_hashed_storage_attachments_event(event, created_at) def handle_hashed_storage_attachments_event(event, created_at)
...@@ -254,7 +274,7 @@ module Gitlab ...@@ -254,7 +274,7 @@ module Gitlab
::Geo::FileRegistry.where(file_id: event.upload_id, file_type: event.upload_type).delete_all ::Geo::FileRegistry.where(file_id: event.upload_id, file_type: event.upload_type).delete_all
end end
def find_or_initialize_registry(project_id, attrs) def find_or_initialize_registry(project_id, attrs = nil)
registry = ::Geo::ProjectRegistry.find_or_initialize_by(project_id: project_id) registry = ::Geo::ProjectRegistry.find_or_initialize_by(project_id: project_id)
registry.assign_attributes(attrs) registry.assign_attributes(attrs)
registry registry
......
...@@ -20,6 +20,10 @@ FactoryBot.define do ...@@ -20,6 +20,10 @@ FactoryBot.define do
wikis_count 9 wikis_count 9
wikis_synced_count 4 wikis_synced_count 4
wikis_failed_count 1 wikis_failed_count 1
repositories_verified_count 501
repositories_verification_failed_count 100
wikis_verified_count 499
wikis_verification_failed_count 99
last_event_id 2 last_event_id 2
last_event_timestamp { Time.now.to_i } last_event_timestamp { Time.now.to_i }
cursor_last_event_id 1 cursor_last_event_id 1
......
...@@ -9,12 +9,12 @@ FactoryBot.define do ...@@ -9,12 +9,12 @@ FactoryBot.define do
trait :repository_outdated do trait :repository_outdated do
repository_verification_checksum nil repository_verification_checksum nil
last_repository_verification_failure false last_repository_verification_failure nil
end end
trait :repository_verified do trait :repository_verified do
repository_verification_checksum 'f079a831cab27bcda7d81cd9b48296d0c3dd92ee' repository_verification_checksum 'f079a831cab27bcda7d81cd9b48296d0c3dd92ee'
last_repository_verification_failure false last_repository_verification_failure nil
end end
trait :wiki_failed do trait :wiki_failed do
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
"wikis_count", "wikis_count",
"wikis_failed_count", "wikis_failed_count",
"wikis_synced_count", "wikis_synced_count",
"repository_verification_enabled",
"repositories_verified_count", "repositories_verified_count",
"repositories_verification_failed_count", "repositories_verification_failed_count",
"repositories_verified_in_percentage", "repositories_verified_in_percentage",
...@@ -70,6 +71,7 @@ ...@@ -70,6 +71,7 @@
"wikis_failed_count": { "type": ["integer", "null"] }, "wikis_failed_count": { "type": ["integer", "null"] },
"wikis_synced_count": { "type": ["integer", "null"] }, "wikis_synced_count": { "type": ["integer", "null"] },
"wikis_synced_in_percentage": { "type": "string" }, "wikis_synced_in_percentage": { "type": "string" },
"repository_verification_enabled": { "type": "boolean" },
"repositories_verified_count": { "type": ["integer", "null"] }, "repositories_verified_count": { "type": ["integer", "null"] },
"repositories_verification_failed_count": { "type": ["integer", "null"] }, "repositories_verification_failed_count": { "type": ["integer", "null"] },
"repositories_verified_in_percentage": { "type": "string" }, "repositories_verified_in_percentage": { "type": "string" },
......
...@@ -7,6 +7,7 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared ...@@ -7,6 +7,7 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared
set(:secondary) { create(:geo_node) } set(:secondary) { create(:geo_node) }
let(:options) { {} } let(:options) { {} }
subject(:daemon) { described_class.new(options) } subject(:daemon) { described_class.new(options) }
around do |example| around do |example|
...@@ -164,26 +165,35 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared ...@@ -164,26 +165,35 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
let(:repository_deleted_event) { event_log.repository_deleted_event } let(:repository_deleted_event) { event_log.repository_deleted_event }
let(:project) { repository_deleted_event.project } let(:project) { repository_deleted_event.project }
let(:deleted_project_name) { repository_deleted_event.deleted_project_name }
let(:deleted_path) { repository_deleted_event.deleted_path }
it 'does not create a tracking database entry' do context 'when a tracking entry does not exist' do
expect { daemon.run_once! }.not_to change(Geo::ProjectRegistry, :count) it 'does not schedule a GeoRepositoryDestroyWorker' do
end expect(::GeoRepositoryDestroyWorker).not_to receive(:perform_async)
.with(project.id, deleted_project_name, deleted_path, project.repository_storage)
it 'schedules a GeoRepositoryDestroyWorker' do
project_id = repository_deleted_event.project_id
project_name = repository_deleted_event.deleted_project_name
project_path = repository_deleted_event.deleted_path
expect(::GeoRepositoryDestroyWorker).to receive(:perform_async) daemon.run_once!
.with(project_id, project_name, project_path, project.repository_storage) end
daemon.run_once! it 'does not create a tracking entry' do
expect { daemon.run_once! }.not_to change(Geo::ProjectRegistry, :count)
end
end end
it 'removes the tracking database entry if exist' do context 'when a tracking entry exists' do
create(:geo_project_registry, :synced, project: project) let!(:tracking_entry) { create(:geo_project_registry, project: project) }
it 'schedules a GeoRepositoryDestroyWorker' do
expect(::GeoRepositoryDestroyWorker).to receive(:perform_async)
.with(project.id, deleted_project_name, deleted_path, project.repository_storage)
daemon.run_once!
end
expect { daemon.run_once! }.to change(Geo::ProjectRegistry, :count).by(-1) it 'removes the tracking entry' do
expect { daemon.run_once! }.to change(Geo::ProjectRegistry, :count).by(-1)
end
end end
end end
...@@ -214,27 +224,33 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared ...@@ -214,27 +224,33 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared
let(:repository_updated_event) { create(:geo_repository_updated_event, project: project) } let(:repository_updated_event) { create(:geo_repository_updated_event, project: project) }
let(:event_log) { create(:geo_event_log, repository_updated_event: repository_updated_event) } let(:event_log) { create(:geo_event_log, repository_updated_event: repository_updated_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
let!(:registry) { create(:geo_project_registry, :synced, project: project) }
before do
allow(Geo::ProjectSyncWorker).to receive(:perform_async)
end
it 'replays events for projects that belong to selected namespaces to replicate' do it 'replays events for projects that belong to selected namespaces to replicate' do
secondary.update!(namespaces: [group_1]) secondary.update!(namespaces: [group_1])
expect { daemon.run_once! }.to change(Geo::ProjectRegistry, :count).by(1) expect(Geo::ProjectSyncWorker).to receive(:perform_async)
.with(project.id, anything).once
daemon.run_once!
end end
it 'does not replay events for projects that do not belong to selected namespaces to replicate' do it 'does not replay events for projects that do not belong to selected namespaces to replicate' do
secondary.update!(selective_sync_type: 'namespaces', namespaces: [group_2]) secondary.update!(selective_sync_type: 'namespaces', namespaces: [group_2])
expect { daemon.run_once! }.not_to change(Geo::ProjectRegistry, :count) expect(Geo::ProjectSyncWorker).not_to receive(:perform_async)
.with(project.id, anything)
daemon.run_once!
end end
it 'does not replay events for projects that do not belong to selected shards to replicate' do it 'does not replay events for projects that do not belong to selected shards to replicate' do
secondary.update!(selective_sync_type: 'shards', selective_sync_shards: ['broken']) secondary.update!(selective_sync_type: 'shards', selective_sync_shards: ['broken'])
expect { daemon.run_once! }.not_to change(Geo::ProjectRegistry, :count) expect(Geo::ProjectSyncWorker).not_to receive(:perform_async)
.with(project.id, anything)
daemon.run_once!
end end
end end
...@@ -242,20 +258,32 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared ...@@ -242,20 +258,32 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared
let(:event_log) { create(:geo_event_log, :renamed_event) } let(:event_log) { create(:geo_event_log, :renamed_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
let(:repository_renamed_event) { event_log.repository_renamed_event } let(:repository_renamed_event) { event_log.repository_renamed_event }
let(:project) {repository_renamed_event.project }
let(:old_path_with_namespace) { repository_renamed_event.old_path_with_namespace }
let(:new_path_with_namespace) { repository_renamed_event.new_path_with_namespace }
it 'does not create a new project registry' do context 'when a tracking entry does not exist' do
expect { daemon.run_once! }.not_to change(Geo::ProjectRegistry, :count) it 'does not create a tracking entry' do
expect { daemon.run_once! }.not_to change(Geo::ProjectRegistry, :count)
end
it 'does not schedule a Geo::RenameRepositoryWorker' do
expect(::Geo::RenameRepositoryWorker).not_to receive(:perform_async)
.with(project.id, old_path_with_namespace, new_path_with_namespace)
daemon.run_once!
end
end end
it 'schedules a Geo::RenameRepositoryWorker' do context 'when a tracking entry does exists' do
project_id = repository_renamed_event.project_id it 'schedules a Geo::RenameRepositoryWorker' do
old_path_with_namespace = repository_renamed_event.old_path_with_namespace create(:geo_project_registry, project: project)
new_path_with_namespace = repository_renamed_event.new_path_with_namespace
expect(::Geo::RenameRepositoryWorker).to receive(:perform_async) expect(::Geo::RenameRepositoryWorker).to receive(:perform_async)
.with(project_id, old_path_with_namespace, new_path_with_namespace) .with(project.id, old_path_with_namespace, new_path_with_namespace)
daemon.run_once! daemon.run_once!
end
end end
end end
...@@ -263,21 +291,33 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared ...@@ -263,21 +291,33 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared
let(:event_log) { create(:geo_event_log, :hashed_storage_migration_event) } let(:event_log) { create(:geo_event_log, :hashed_storage_migration_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
let(:hashed_storage_migrated_event) { event_log.hashed_storage_migrated_event } let(:hashed_storage_migrated_event) { event_log.hashed_storage_migrated_event }
let(:project) { hashed_storage_migrated_event.project }
let(:old_disk_path) { hashed_storage_migrated_event.old_disk_path }
let(:new_disk_path) { hashed_storage_migrated_event.new_disk_path }
let(:old_storage_version) { hashed_storage_migrated_event.old_storage_version }
context 'when a tracking entry does not exist' do
it 'does not create a tracking entry' do
expect { daemon.run_once! }.not_to change(Geo::ProjectRegistry, :count)
end
it 'does not create a new project registry' do it 'does not schedule a Geo::HashedStorageMigrationWorker' do
expect { daemon.run_once! }.not_to change(Geo::ProjectRegistry, :count) expect(::Geo::HashedStorageMigrationWorker).not_to receive(:perform_async)
.with(project.id, old_disk_path, new_disk_path, old_storage_version)
daemon.run_once!
end
end end
it 'schedules a Geo::HashedStorageMigrationWorker' do context 'when a tracking entry exists' do
project = hashed_storage_migrated_event.project it 'schedules a Geo::HashedStorageMigrationWorker' do
old_disk_path = hashed_storage_migrated_event.old_disk_path create(:geo_project_registry, project: project)
new_disk_path = hashed_storage_migrated_event.new_disk_path
old_storage_version = hashed_storage_migrated_event.old_storage_version
expect(::Geo::HashedStorageMigrationWorker).to receive(:perform_async) expect(::Geo::HashedStorageMigrationWorker).to receive(:perform_async)
.with(project.id, old_disk_path, new_disk_path, old_storage_version) .with(project.id, old_disk_path, new_disk_path, old_storage_version)
daemon.run_once! daemon.run_once!
end
end end
end end
......
...@@ -388,6 +388,182 @@ describe GeoNodeStatus, :geo do ...@@ -388,6 +388,182 @@ describe GeoNodeStatus, :geo do
end end
end end
describe '#repositories_verified_count' do
context 'on the primary' do
before do
stub_current_geo_node(primary)
end
it 'returns the right number of verified repositories' do
stub_feature_flags(geo_repository_verification: true)
create(:repository_state, :repository_verified)
create(:repository_state, :repository_verified)
expect(subject.repositories_verified_count).to eq(2)
end
it 'returns existing value when feature flag if off' do
stub_feature_flags(geo_repository_verification: false)
create(:geo_node_status, :healthy, geo_node: primary)
expect(subject.repositories_verified_count).to eq(501)
end
end
context 'on the secondary' do
before do
stub_current_geo_node(secondary)
end
it 'returns the right number of verified repositories' do
stub_feature_flags(geo_repository_verification: true)
create(:geo_project_registry, :repository_verified)
create(:geo_project_registry, :repository_verified)
expect(subject.repositories_verified_count).to eq(2)
end
it 'returns existing value when feature flag if off' do
stub_feature_flags(geo_repository_verification: false)
create(:geo_node_status, :healthy, geo_node: secondary)
expect(subject.repositories_verified_count).to eq(501)
end
end
end
describe '#repositories_verification_failed_count' do
context 'on the primary' do
before do
stub_current_geo_node(primary)
end
it 'returns the right number of failed repositories' do
stub_feature_flags(geo_repository_verification: true)
create(:repository_state, :repository_failed)
create(:repository_state, :repository_failed)
expect(subject.repositories_verification_failed_count).to eq(2)
end
it 'returns existing value when feature flag if off' do
stub_feature_flags(geo_repository_verification: false)
create(:geo_node_status, :healthy, geo_node: primary)
expect(subject.repositories_verification_failed_count).to eq(100)
end
end
context 'on the secondary' do
before do
stub_current_geo_node(secondary)
end
it 'returns the right number of failed repositories' do
stub_feature_flags(geo_repository_verification: true)
create(:geo_project_registry, :repository_verification_failed)
create(:geo_project_registry, :repository_verification_failed)
expect(subject.repositories_verification_failed_count).to eq(2)
end
it 'returns existing value when feature flag if off' do
stub_feature_flags(geo_repository_verification: false)
create(:geo_node_status, :healthy, geo_node: secondary)
expect(subject.repositories_verification_failed_count).to eq(100)
end
end
end
describe '#wikis_verified_count' do
context 'on the primary' do
before do
stub_current_geo_node(primary)
end
it 'returns the right number of verified wikis' do
stub_feature_flags(geo_repository_verification: true)
create(:repository_state, :wiki_verified)
create(:repository_state, :wiki_verified)
expect(subject.wikis_verified_count).to eq(2)
end
it 'returns existing value when feature flag if off' do
stub_feature_flags(geo_repository_verification: false)
create(:geo_node_status, :healthy, geo_node: primary)
expect(subject.wikis_verified_count).to eq(499)
end
end
context 'on the secondary' do
before do
stub_current_geo_node(secondary)
end
it 'returns the right number of verified wikis' do
stub_feature_flags(geo_repository_verification: true)
create(:geo_project_registry, :wiki_verified)
create(:geo_project_registry, :wiki_verified)
expect(subject.wikis_verified_count).to eq(2)
end
it 'returns existing value when feature flag if off' do
stub_feature_flags(geo_repository_verification: false)
create(:geo_node_status, :healthy, geo_node: secondary)
expect(subject.wikis_verified_count).to eq(499)
end
end
end
describe '#wikis_verification_failed_count' do
context 'on the primary' do
before do
stub_current_geo_node(primary)
end
it 'returns the right number of failed wikis' do
stub_feature_flags(geo_repository_verification: true)
create(:repository_state, :wiki_failed)
create(:repository_state, :wiki_failed)
expect(subject.wikis_verification_failed_count).to eq(2)
end
it 'returns existing value when feature flag if off' do
stub_feature_flags(geo_repository_verification: false)
create(:geo_node_status, :healthy, geo_node: primary)
expect(subject.wikis_verification_failed_count).to eq(99)
end
end
context 'on the secondary' do
before do
stub_current_geo_node(secondary)
end
it 'returns the right number of failed wikis' do
stub_feature_flags(geo_repository_verification: true)
create(:geo_project_registry, :wiki_verification_failed)
create(:geo_project_registry, :wiki_verification_failed)
expect(subject.wikis_verification_failed_count).to eq(2)
end
it 'returns existing value when feature flag if off' do
stub_feature_flags(geo_repository_verification: false)
create(:geo_node_status, :healthy, geo_node: secondary)
expect(subject.wikis_verification_failed_count).to eq(99)
end
end
end
describe '#last_event_id and #last_event_date' do describe '#last_event_id and #last_event_date' do
it 'returns nil when no events are available' do it 'returns nil when no events are available' do
expect(subject.last_event_id).to be_nil expect(subject.last_event_id).to be_nil
......
...@@ -83,6 +83,10 @@ module Gitlab ...@@ -83,6 +83,10 @@ module Gitlab
end end
end end
def self.random_storage
Gitlab.config.repositories.storages.keys.sample
end
def self.address(storage) def self.address(storage)
params = Gitlab.config.repositories.storages[storage] params = Gitlab.config.repositories.storages[storage]
raise "storage not found: #{storage.inspect}" if params.nil? raise "storage not found: #{storage.inspect}" if params.nil?
......
...@@ -3,6 +3,17 @@ module Gitlab ...@@ -3,6 +3,17 @@ module Gitlab
class RemoteService class RemoteService
MAX_MSG_SIZE = 128.kilobytes.freeze MAX_MSG_SIZE = 128.kilobytes.freeze
def self.exists?(remote_url)
request = Gitaly::FindRemoteRepositoryRequest.new(remote: remote_url)
response = GitalyClient.call(GitalyClient.random_storage,
:remote_service,
:find_remote_repository, request,
timeout: GitalyClient.medium_timeout)
response.exists
end
def initialize(repository) def initialize(repository)
@repository = repository @repository = repository
@gitaly_repo = repository.gitaly_repository @gitaly_repo = repository.gitaly_repository
......
...@@ -16,7 +16,8 @@ module Gitlab ...@@ -16,7 +16,8 @@ module Gitlab
# Returns true if we should import the wiki for the project. # Returns true if we should import the wiki for the project.
def import_wiki? def import_wiki?
client.repository(project.import_source)&.has_wiki && client.repository(project.import_source)&.has_wiki &&
!project.wiki_repository_exists? !project.wiki_repository_exists? &&
Gitlab::GitalyClient::RemoteService.exists?(wiki_url)
end end
# Imports the repository data. # Imports the repository data.
...@@ -55,7 +56,6 @@ module Gitlab ...@@ -55,7 +56,6 @@ module Gitlab
def import_wiki_repository def import_wiki_repository
wiki_path = "#{project.disk_path}.wiki" wiki_path = "#{project.disk_path}.wiki"
wiki_url = project.import_url.sub(/\.git\z/, '.wiki.git')
storage_path = project.repository_storage_path storage_path = project.repository_storage_path
gitlab_shell.import_repository(storage_path, wiki_path, wiki_url) gitlab_shell.import_repository(storage_path, wiki_path, wiki_url)
...@@ -70,6 +70,10 @@ module Gitlab ...@@ -70,6 +70,10 @@ module Gitlab
end end
end end
def wiki_url
project.import_url.sub(/\.git\z/, '.wiki.git')
end
def update_clone_time def update_clone_time
project.update_column(:last_repository_updated_at, Time.zone.now) project.update_column(:last_repository_updated_at, Time.zone.now)
end end
......
...@@ -42,7 +42,7 @@ module Gitlab ...@@ -42,7 +42,7 @@ module Gitlab
end end
def send_git_blob(repository, blob) def send_git_blob(repository, blob)
params = if Gitlab::GitalyClient.feature_enabled?(:workhorse_raw_show) params = if Gitlab::GitalyClient.feature_enabled?(:workhorse_raw_show, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT)
{ {
'GitalyServer' => gitaly_server_hash(repository), 'GitalyServer' => gitaly_server_hash(repository),
'GetBlobRequest' => { 'GetBlobRequest' => {
...@@ -70,7 +70,7 @@ module Gitlab ...@@ -70,7 +70,7 @@ module Gitlab
params = repository.archive_metadata(ref, Gitlab.config.gitlab.repository_downloads_path, format) params = repository.archive_metadata(ref, Gitlab.config.gitlab.repository_downloads_path, format)
raise "Repository or ref not found" if params.empty? raise "Repository or ref not found" if params.empty?
if Gitlab::GitalyClient.feature_enabled?(:workhorse_archive) if Gitlab::GitalyClient.feature_enabled?(:workhorse_archive, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT)
params.merge!( params.merge!(
'GitalyServer' => gitaly_server_hash(repository), 'GitalyServer' => gitaly_server_hash(repository),
'GitalyRepository' => repository.gitaly_repository.to_h 'GitalyRepository' => repository.gitaly_repository.to_h
...@@ -87,7 +87,7 @@ module Gitlab ...@@ -87,7 +87,7 @@ module Gitlab
end end
def send_git_diff(repository, diff_refs) def send_git_diff(repository, diff_refs)
params = if Gitlab::GitalyClient.feature_enabled?(:workhorse_send_git_diff) params = if Gitlab::GitalyClient.feature_enabled?(:workhorse_send_git_diff, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT)
{ {
'GitalyServer' => gitaly_server_hash(repository), 'GitalyServer' => gitaly_server_hash(repository),
'RawDiffRequest' => Gitaly::RawDiffRequest.new( 'RawDiffRequest' => Gitaly::RawDiffRequest.new(
...@@ -105,7 +105,7 @@ module Gitlab ...@@ -105,7 +105,7 @@ module Gitlab
end end
def send_git_patch(repository, diff_refs) def send_git_patch(repository, diff_refs)
params = if Gitlab::GitalyClient.feature_enabled?(:workhorse_send_git_patch) params = if Gitlab::GitalyClient.feature_enabled?(:workhorse_send_git_patch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT)
{ {
'GitalyServer' => gitaly_server_hash(repository), 'GitalyServer' => gitaly_server_hash(repository),
'RawPatchRequest' => Gitaly::RawPatchRequest.new( 'RawPatchRequest' => Gitaly::RawPatchRequest.new(
......
...@@ -58,4 +58,14 @@ describe Gitlab::GitalyClient::RemoteService do ...@@ -58,4 +58,14 @@ describe Gitlab::GitalyClient::RemoteService do
client.update_remote_mirror(ref_name, only_branches_matching) client.update_remote_mirror(ref_name, only_branches_matching)
end end
end end
describe '.exists?' do
context "when the remote doesn't exist" do
let(:url) { 'https://gitlab.com/gitlab-org/ik-besta-niet-of-ik-word-geplaagd.git' }
it 'returns false' do
expect(described_class.exists?(url)).to be(false)
end
end
end
end end
...@@ -38,8 +38,12 @@ describe Gitlab::GithubImport::Importer::RepositoryImporter do ...@@ -38,8 +38,12 @@ describe Gitlab::GithubImport::Importer::RepositoryImporter do
expect(project) expect(project)
.to receive(:wiki_repository_exists?) .to receive(:wiki_repository_exists?)
.and_return(false) .and_return(false)
expect(Gitlab::GitalyClient::RemoteService)
.to receive(:exists?)
.with("foo.wiki.git")
.and_return(true)
expect(importer.import_wiki?).to eq(true) expect(importer.import_wiki?).to be(true)
end end
it 'returns false if the GitHub wiki is disabled' do it 'returns false if the GitHub wiki is disabled' do
......
RSpec.configure do |config| RSpec.configure do |config|
config.before(:each) do |example| config.before(:each) do |example|
if example.metadata[:disable_gitaly] if example.metadata[:disable_gitaly]
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) # Use 'and_wrap_original' to make sure the arguments are valid
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original { |m, *args| m.call(*args) && false }
else else
next if example.metadata[:skip_gitaly_mock] next if example.metadata[:skip_gitaly_mock]
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true) # Use 'and_wrap_original' to make sure the arguments are valid
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original { |m, *args| m.call(*args) || true }
end end
end end
end end
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