Commit f376347f authored by Jacob Vosmaer's avatar Jacob Vosmaer

Find and mark more Git disk access locations, part 2

parent b2ef7f6c
......@@ -23,10 +23,11 @@ def perform(*args)
source_repository_storage_path, source_disk_path = *args
source_repository_storage_name = Gitlab.config.repositories.storages.find do |_, info|
info.legacy_disk_path == source_repository_storage_path
end&.first || raise("no shard found for path '#{source_repository_storage_path}'")
source_repository_storage_name = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab.config.repositories.storages.find do |_, info|
info.legacy_disk_path == source_repository_storage_path
end&.first || raise("no shard found for path '#{source_repository_storage_path}'")
end
fork_repository(target_project, source_repository_storage_name, source_disk_path)
end
end
......
......@@ -53,24 +53,11 @@ def shard_path
# Import project via git clone --bare
# URL must be publicly cloneable
def import_project(source, timeout)
Gitlab::GitalyClient.migrate(:import_repository, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_import_repository(source)
else
git_import_repository(source, timeout)
end
end
git_import_repository(source, timeout)
end
def fork_repository(new_shard_name, new_repository_relative_path)
Gitlab::GitalyClient.migrate(:fork_repository,
status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_fork_repository(new_shard_name, new_repository_relative_path)
else
git_fork_repository(new_shard_name, new_repository_relative_path)
end
end
git_fork_repository(new_shard_name, new_repository_relative_path)
end
def fetch_remote(name, timeout, force:, tags:, ssh_key: nil, known_hosts: nil, prune: true)
......@@ -241,16 +228,6 @@ def git_import_repository(source, timeout)
true
end
def gitaly_import_repository(source)
raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
Gitlab::GitalyClient::RepositoryService.new(raw_repository).import_repository(source)
true
rescue GRPC::BadStatus => e
@output << e.message
false
end
def git_fork_repository(new_shard_name, new_repository_relative_path)
from_path = repository_absolute_path
new_shard_path = Gitlab.config.repositories.storages.fetch(new_shard_name).legacy_disk_path
......@@ -270,16 +247,6 @@ def git_fork_repository(new_shard_name, new_repository_relative_path)
run(cmd, nil) && Gitlab::Git::Repository.create_hooks(to_path, global_hooks_path)
end
def gitaly_fork_repository(new_shard_name, new_repository_relative_path)
target_repository = Gitlab::Git::Repository.new(new_shard_name, new_repository_relative_path, nil)
raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
Gitlab::GitalyClient::RepositoryService.new(target_repository).fork_repository(raw_repository)
rescue GRPC::BadStatus => e
logger.error "fork-repository failed: #{e.message}"
false
end
end
end
end
......@@ -24,7 +24,9 @@ def gitaly_configuration_toml(gitaly_dir, gitaly_ruby: true)
address = val['gitaly_address']
end
storages << { name: key, path: val.legacy_disk_path }
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
storages << { name: key, path: val.legacy_disk_path }
end
end
if Rails.env.test?
......
......@@ -106,10 +106,17 @@ def import_repository(storage, name, url)
raise Error.new("don't use disk paths with import_repository: #{url.inspect}")
end
# The timeout ensures the subprocess won't hang forever
cmd = gitlab_projects(storage, "#{name}.git")
success = cmd.import_project(url, git_timeout)
relative_path = "#{name}.git"
cmd = gitaly_migrate(:import_repository, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
GitalyGitlabProjects.new(storage, relative_path)
else
# The timeout ensures the subprocess won't hang forever
gitlab_projects(storage, relative_path)
end
end
success = cmd.import_project(url, git_timeout)
raise Error, cmd.output unless success
success
......@@ -165,8 +172,16 @@ def mv_repository(storage, path, new_path)
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/817
def fork_repository(forked_from_storage, forked_from_disk_path, forked_to_storage, forked_to_disk_path)
gitlab_projects(forked_from_storage, "#{forked_from_disk_path}.git")
.fork_repository(forked_to_storage, "#{forked_to_disk_path}.git")
forked_from_relative_path = "#{forked_from_disk_path}.git"
fork_args = [forked_to_storage, "#{forked_to_disk_path}.git"]
gitaly_migrate(:fork_repository, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
GitalyGitlabProjects.new(forked_from_storage, forked_from_relative_path).fork_repository(*fork_args)
else
gitlab_projects(forked_from_storage, forked_from_relative_path).fork_repository(*fork_args)
end
end
end
# Removes a repository from file system, using rm_diretory which is an alias
......@@ -452,5 +467,39 @@ def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN
# need to do the same here...
raise Error, e
end
class GitalyGitlabProjects
attr_reader :shard_name, :repository_relative_path, :output
def initialize(shard_name, repository_relative_path)
@shard_name = shard_name
@repository_relative_path = repository_relative_path
@output = ''
end
def import_project(source, _timeout)
raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
Gitlab::GitalyClient::RepositoryService.new(raw_repository).import_repository(source)
true
rescue GRPC::BadStatus => e
@output = e.message
false
end
def fork_repository(new_shard_name, new_repository_relative_path)
target_repository = Gitlab::Git::Repository.new(new_shard_name, new_repository_relative_path, nil)
raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
Gitlab::GitalyClient::RepositoryService.new(target_repository).fork_repository(raw_repository)
rescue GRPC::BadStatus => e
logger.error "fork-repository failed: #{e.message}"
false
end
def logger
Rails.logger
end
end
end
end
......@@ -140,7 +140,9 @@ def all_repos
end
def repository_storage_paths_args
Gitlab.config.repositories.storages.values.map { |rs| rs.legacy_disk_path }
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab.config.repositories.storages.values.map { |rs| rs.legacy_disk_path }
end
end
def user_home
......
......@@ -4,13 +4,15 @@ class NamespaceCheck < SystemCheck::BaseCheck
set_name 'Orphaned namespaces:'
def multi_check
Gitlab.config.repositories.storages.each do |storage_name, repository_storage|
$stdout.puts
$stdout.puts "* Storage: #{storage_name} (#{repository_storage.legacy_disk_path})".color(:yellow)
toplevel_namespace_dirs = disk_namespaces(repository_storage.legacy_disk_path)
orphans = (toplevel_namespace_dirs - existing_namespaces)
print_orphans(orphans, storage_name)
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab.config.repositories.storages.each do |storage_name, repository_storage|
$stdout.puts
$stdout.puts "* Storage: #{storage_name} (#{repository_storage.legacy_disk_path})".color(:yellow)
toplevel_namespace_dirs = disk_namespaces(repository_storage.legacy_disk_path)
orphans = (toplevel_namespace_dirs - existing_namespaces)
print_orphans(orphans, storage_name)
end
end
clear_namespaces! # releases memory when check finishes
......
......@@ -44,11 +44,13 @@ namespace :gitlab do
start_checking "GitLab Shell"
check_gitlab_shell
check_repo_base_exists
check_repo_base_is_not_symlink
check_repo_base_user_and_group
check_repo_base_permissions
check_repos_hooks_directory_is_link
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
check_repo_base_exists
check_repo_base_is_not_symlink
check_repo_base_user_and_group
check_repo_base_permissions
check_repos_hooks_directory_is_link
end
check_gitlab_shell_self_test
finished_checking "GitLab Shell"
......
......@@ -67,8 +67,10 @@ namespace :gitlab do
puts "GitLab Shell".color(:yellow)
puts "Version:\t#{gitlab_shell_version || "unknown".color(:red)}"
puts "Repository storage paths:"
Gitlab.config.repositories.storages.each do |name, repository_storage|
puts "- #{name}: \t#{repository_storage.legacy_disk_path}"
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab.config.repositories.storages.each do |name, repository_storage|
puts "- #{name}: \t#{repository_storage.legacy_disk_path}"
end
end
puts "Hooks:\t\t#{Gitlab.config.gitlab_shell.hooks_path}"
puts "Git:\t\t#{Gitlab.config.git.bin_path}"
......
......@@ -151,11 +151,6 @@
trait :empty_repo do
after(:create) do |project|
raise "Failed to create repository!" unless project.create_repository
# We delete hooks so that gitlab-shell will not try to authenticate with
# an API that isn't running
project.gitlab_shell.rm_directory(project.repository_storage,
File.join("#{project.disk_path}.git", 'hooks'))
end
end
......@@ -180,13 +175,6 @@
trait :wiki_repo do
after(:create) do |project|
raise 'Failed to create wiki repository!' unless project.create_wiki
# We delete hooks so that gitlab-shell will not try to authenticate with
# an API that isn't running
project.gitlab_shell.rm_directory(
project.repository_storage,
File.join("#{project.wiki.repository.disk_path}.git", "hooks")
)
end
end
......
......@@ -79,7 +79,9 @@
let(:diffs) { commit.diffs }
before do
info_dir_path = File.join(project.repository.path_to_repo, 'info')
info_dir_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
File.join(project.repository.path_to_repo, 'info')
end
FileUtils.mkdir(info_dir_path) unless File.exist?(info_dir_path)
File.write(File.join(info_dir_path, 'attributes'), "*.md -diff\n")
......
......@@ -149,7 +149,9 @@
it 'limits the size of a large file' do
blob_size = Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE + 1
buffer = Array.new(blob_size, 0)
rugged_blob = Rugged::Blob.from_buffer(repository.rugged, buffer.join(''))
rugged_blob = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Rugged::Blob.from_buffer(repository.rugged, buffer.join(''))
end
blob = Gitlab::Git::Blob.raw(repository, rugged_blob)
expect(blob.size).to eq(blob_size)
......@@ -164,7 +166,9 @@
context 'when sha references a tree' do
it 'returns nil' do
tree = repository.rugged.rev_parse('master^{tree}')
tree = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
repository.rugged.rev_parse('master^{tree}')
end
blob = Gitlab::Git::Blob.raw(repository, tree.oid)
......@@ -278,7 +282,11 @@
end
describe '.batch_lfs_pointers' do
let(:tree_object) { repository.rugged.rev_parse('master^{tree}') }
let(:tree_object) do
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
repository.rugged.rev_parse('master^{tree}')
end
end
let(:non_lfs_blob) do
Gitlab::Git::Blob.find(
......
......@@ -69,7 +69,9 @@
Gitlab::Git.committer_hash(email: user.email, name: user.name)
end
let(:params) do
parents = [repository.rugged.head.target]
parents = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
[repository.rugged.head.target]
end
tree = parents.first.tree
{
......
......@@ -4,12 +4,15 @@
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
let(:commit) { described_class.find(repository, SeedRepo::Commit::ID) }
let(:rugged_commit) do
repository.rugged.lookup(SeedRepo::Commit::ID)
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
repository.rugged.lookup(SeedRepo::Commit::ID)
end
end
describe "Commit info" do
before do
repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
end
@committer = {
email: 'mike@smith.com',
......@@ -58,7 +61,9 @@
after do
# Erase the new commit so other tests get the original repo
repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
end
repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID)
end
end
......@@ -115,7 +120,9 @@
describe '.find' do
it "should return first head commit if without params" do
expect(described_class.last(repository).id).to eq(
repository.rugged.head.target.oid
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
repository.rugged.head.target.oid
end
)
end
......
......@@ -27,8 +27,10 @@
too_large: false
}
@rugged_diff = repository.rugged.diff("5937ac0a7beb003549fc5fd26fc247adbce4a52e^", "5937ac0a7beb003549fc5fd26fc247adbce4a52e", paths:
[".gitmodules"]).patches.first
@rugged_diff = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
repository.rugged.diff("5937ac0a7beb003549fc5fd26fc247adbce4a52e^", "5937ac0a7beb003549fc5fd26fc247adbce4a52e", paths:
[".gitmodules"]).patches.first
end
end
describe '.new' do
......
......@@ -5,6 +5,13 @@
TestEnv.clean_test_path
end
around do |example|
# TODO move this spec to gitaly-ruby. GitlabProjects is not used in gitlab-ce
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
example.run
end
end
let(:project) { create(:project, :repository) }
if $VERBOSE
......@@ -190,36 +197,30 @@ def stub_tempfile(name, filename, opts = {})
end
end
context 'when Gitaly import_repository feature is enabled' do
it_behaves_like 'importing repository'
end
describe 'logging' do
it 'imports a repo' do
message = "Importing project from <#{import_url}> to <#{tmp_repo_path}>."
expect(logger).to receive(:info).with(message)
context 'when Gitaly import_repository feature is disabled', :disable_gitaly do
describe 'logging' do
it 'imports a repo' do
message = "Importing project from <#{import_url}> to <#{tmp_repo_path}>."
expect(logger).to receive(:info).with(message)
subject
end
subject
end
end
context 'timeout' do
it 'does not import a repo' do
stub_spawn_timeout(cmd, timeout, nil)
context 'timeout' do
it 'does not import a repo' do
stub_spawn_timeout(cmd, timeout, nil)
message = "Importing project from <#{import_url}> to <#{tmp_repo_path}> failed."
expect(logger).to receive(:error).with(message)
message = "Importing project from <#{import_url}> to <#{tmp_repo_path}> failed."
expect(logger).to receive(:error).with(message)
is_expected.to be_falsy
is_expected.to be_falsy
expect(gl_projects.output).to eq("Timed out\n")
expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_falsy
end
expect(gl_projects.output).to eq("Timed out\n")
expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_falsy
end
it_behaves_like 'importing repository'
end
it_behaves_like 'importing repository'
end
describe '#fork_repository' do
......@@ -232,9 +233,6 @@ def stub_tempfile(name, filename, opts = {})
before do
FileUtils.mkdir_p(dest_repos_path)
# Undo spec_helper stub that deletes hooks
allow_any_instance_of(described_class).to receive(:fork_repository).and_call_original
end
after do
......@@ -258,51 +256,45 @@ def stub_tempfile(name, filename, opts = {})
end
end
context 'when Gitaly fork_repository feature is enabled' do
it_behaves_like 'forking a repository'
end
context 'when Gitaly fork_repository feature is disabled', :disable_gitaly do
it_behaves_like 'forking a repository'
it_behaves_like 'forking a repository'
# We seem to be stuck to having only one working Gitaly storage in tests, changing
# that is not very straight-forward so I'm leaving this test here for now till
# https://gitlab.com/gitlab-org/gitlab-ce/issues/41393 is fixed.
context 'different storages' do
let(:dest_repos) { 'alternative' }
let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), dest_repos) }
# We seem to be stuck to having only one working Gitaly storage in tests, changing
# that is not very straight-forward so I'm leaving this test here for now till
# https://gitlab.com/gitlab-org/gitlab-ce/issues/41393 is fixed.
context 'different storages' do
let(:dest_repos) { 'alternative' }
let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), dest_repos) }
before do
stub_storage_settings(dest_repos => { 'path' => dest_repos_path })
end
before do
stub_storage_settings(dest_repos => { 'path' => dest_repos_path })
end
it 'forks the repo' do
is_expected.to be_truthy
it 'forks the repo' do
is_expected.to be_truthy
expect(File.exist?(dest_repo)).to be_truthy
expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy
expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy
end
expect(File.exist?(dest_repo)).to be_truthy
expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy
expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy
end
end
describe 'log messages' do
describe 'successful fork' do
it do
message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>."
expect(logger).to receive(:info).with(message)
describe 'log messages' do
describe 'successful fork' do
it do
message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>."
expect(logger).to receive(:info).with(message)
subject
end
subject
end
end
describe 'failed fork due existing destination' do
it do
FileUtils.mkdir_p(dest_repo)
message = "fork-repository failed: destination repository <#{dest_repo}> already exists."
expect(logger).to receive(:error).with(message)
describe 'failed fork due existing destination' do
it do
FileUtils.mkdir_p(dest_repo)
message = "fork-repository failed: destination repository <#{dest_repo}> already exists."
expect(logger).to receive(:error).with(message)
subject
end
subject
end
end
end
......
......@@ -8,6 +8,13 @@
allow_any_instance_of(described_class).to receive(:trigger).and_call_original
end
around do |example|
# TODO move hook tests to gitaly-ruby. Hook will disappear from gitlab-ce
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
example.run
end
end
describe "#trigger" do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository.raw_repository }
......
......@@ -8,6 +8,13 @@
index.read_tree(repository.lookup('master').tree)
end
around do |example|
# TODO move these specs to gitaly-ruby. The Index class will disappear from gitlab-ce
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
example.run
end
end
describe '#create' do
let(:options) do
{
......
......@@ -19,7 +19,9 @@
end
after do
FileUtils.rm_rf(project.repository.path_to_repo)
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
FileUtils.rm_rf(project.repository.path_to_repo)
end
end
it 'has a source branch' do
......
......@@ -498,16 +498,34 @@
)
end
it 'returns true when the command succeeds' do
expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { true }
context 'with gitaly' do
it 'returns true when the command succeeds' do
expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository)
.with(repository.raw_repository) { :gitaly_response_object }
is_expected.to be_truthy
end
it 'return false when the command fails' do
expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository)
.with(repository.raw_repository) { raise GRPC::BadStatus, 'bla' }
is_expected.to be_truthy
is_expected.to be_falsy
end
end
it 'return false when the command fails' do
expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { false }
context 'without gitaly', :disable_gitaly do
it 'returns true when the command succeeds' do
expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { true }
is_expected.to be_falsy
is_expected.to be_truthy
end
it 'return false when the command fails' do
expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { false }
is_expected.to be_falsy
end
end
end
......@@ -662,21 +680,43 @@ def build_ssh_auth(opts = {})
describe '#import_repository' do
let(:import_url) { 'https://gitlab.com/gitlab-org/gitlab-ce.git' }