Commit 60309ca5 authored by Nick Thomas's avatar Nick Thomas

Merge branch '3912-transparently-proxy-http-git-push-from-secondary-to-primary' into 'master'

Resolve "Transparently proxy HTTP Git push from secondary to primary"

Closes #3912

See merge request gitlab-org/gitlab-ee!5785
parents 8e72417d 258796c4
......@@ -3,6 +3,7 @@
class Projects::GitHttpClientController < Projects::ApplicationController
include ActionController::HttpAuthentication::Basic
include KerberosSpnegoHelper
prepend ::EE::Projects::GitHttpClientController
attr_reader :authentication_result, :redirected_path
......
......@@ -201,7 +201,10 @@ Read how to [replicate the Container Registry][docker-registry].
> **IMPORTANT**: This list of limitations tracks only the latest version. If you are in an older version,
extra limitations may be in place.
- You cannot push code to secondary nodes, see [gitlab-org/gitlab-ee#3912] for details.
- Pushing code to a secondary redirects the request to the primary instead of handling it directly [gitlab-ee#1381](https://gitlab.com/gitlab-org/gitlab-ee/issues/1381):
* Only push via HTTP is currently supported
* Pushing via SSH is currently not supported: [gitlab-ee#5387](https://gitlab.com/gitlab-org/gitlab-ee/issues/5387)
* Git LFS is currently not supported: [gitlab-ee#6195](https://gitlab.com/gitlab-org/gitlab-ee/issues/6195)
- The primary node has to be online for OAuth login to happen (existing sessions and Git are not affected)
- The installation takes multiple manual steps that together can take about an hour depending on circumstances; we are
working on improving this experience, see [gitlab-org/omnibus-gitlab#2978] for details.
......
module EE
module Projects
module GitHttpClientController
extend ActiveSupport::Concern
prepended do
before_action :redirect_push_to_primary, only: [:info_refs]
end
private
def redirect_push_to_primary
redirect_to(primary_full_url) if redirect_push_to_primary?
end
def primary_full_url
File.join(::Gitlab::Geo.primary_node.url, request_fullpath_for_primary)
end
def request_fullpath_for_primary
relative_url_root = ::Gitlab.config.gitlab.relative_url_root.chomp('/')
request.fullpath.sub(relative_url_root, '')
end
def redirect_push_to_primary?
git_push_request? && ::Gitlab::Geo.secondary_with_primary?
end
def git_push_request?
git_command == 'git-receive-pack'
end
end
end
end
---
title: 'Geo: HTTP git push to secondary now redirects to the primary'
merge_request: 5785
author:
type: added
......@@ -13,6 +13,8 @@ describe "Git HTTP requests (Geo)" do
# Ensure the token always comes from the real time of the request
let!(:auth_token) { Gitlab::Geo::BaseRequest.new.authorization }
let(:env) { valid_geo_env }
before do
stub_licensed_features(geo: true)
stub_current_geo_node(secondary)
......@@ -21,30 +23,14 @@ describe "Git HTTP requests (Geo)" do
shared_examples_for 'Geo sync request' do
subject do
make_request
response
end
context 'valid Geo JWT token' do
let(:env) { valid_geo_env }
it 'returns an OK response' do
is_expected.to have_gitlab_http_status(:ok)
expect(response.content_type).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
expect(json_response).to include('ShowAllRefs' => true)
end
end
context 'post-dated Geo JWT token' do
let(:env) { valid_geo_env }
it { travel_to(11.minutes.ago) { is_expected.to have_gitlab_http_status(:unauthorized) } }
end
context 'expired Geo JWT token' do
let(:env) { valid_geo_env }
it { travel_to(Time.now + 11.minutes) { is_expected.to have_gitlab_http_status(:unauthorized) } }
end
......@@ -54,14 +40,21 @@ describe "Git HTTP requests (Geo)" do
it { is_expected.to have_gitlab_http_status(:unauthorized) }
end
context 'valid Geo JWT token' do
it 'returns an OK response' do
is_expected.to have_gitlab_http_status(:ok)
expect(response.content_type).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
expect(json_response).to include('ShowAllRefs' => true)
end
end
context 'no Geo JWT token' do
let(:env) { workhorse_internal_api_request_header }
it { is_expected.to have_gitlab_http_status(:unauthorized) }
end
context 'Geo is unlicensed' do
let(:env) { valid_geo_env }
before do
stub_licensed_features(geo: false)
end
......@@ -71,18 +64,39 @@ describe "Git HTTP requests (Geo)" do
end
describe 'GET info_refs' do
def make_request
get "/#{project.full_path}.git/info/refs", { service: 'git-upload-pack' }, env
context 'git pull' do
def make_request
get "/#{project.full_path}.git/info/refs", { service: 'git-upload-pack' }, env
end
it_behaves_like 'Geo sync request'
context 'when terms are enforced' do
before do
enforce_terms
end
it_behaves_like 'Geo sync request'
end
end
it_behaves_like 'Geo sync request'
context 'git push' do
def make_request
get url, { service: 'git-receive-pack' }, env
end
context 'when terms are enforced' do
before do
enforce_terms
let(:url) { "/#{project.full_path}.git/info/refs" }
subject do
make_request
response
end
it_behaves_like 'Geo sync request'
it 'redirects to the primary' do
is_expected.to have_gitlab_http_status(:redirect)
redirect_location = "#{primary.url.chomp('/')}#{url}?service=git-receive-pack"
expect(subject.header['Location']).to eq(redirect_location)
end
end
end
......@@ -107,9 +121,8 @@ describe "Git HTTP requests (Geo)" do
end
def geo_env(authorization)
env = workhorse_internal_api_request_header
env['HTTP_AUTHORIZATION'] = authorization
env
workhorse_internal_api_request_header.tap do |env|
env['HTTP_AUTHORIZATION'] = authorization
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