Commit cd9e3a23 authored by Alex Buijs's avatar Alex Buijs

Add root_namespace and project metadata for APi

This adds meta.project and meta.root_namespace
data when available for the /api/:version/runners and
/api/:version/jobs/request API endpoints
parent ff21bade
---
title: Add runners api context metadata
merge_request: 55089
author:
type: changed
...@@ -34,12 +34,12 @@ module API ...@@ -34,12 +34,12 @@ module API
if runner_registration_token_valid? if runner_registration_token_valid?
# Create shared runner. Requires admin access # Create shared runner. Requires admin access
attributes.merge(runner_type: :instance_type) attributes.merge(runner_type: :instance_type)
elsif project = Project.find_by_runners_token(params[:token]) elsif @project = Project.find_by_runners_token(params[:token])
# Create a specific runner for the project # Create a specific runner for the project
attributes.merge(runner_type: :project_type, projects: [project]) attributes.merge(runner_type: :project_type, projects: [@project])
elsif group = Group.find_by_runners_token(params[:token]) elsif @group = Group.find_by_runners_token(params[:token])
# Create a specific runner for the group # Create a specific runner for the group
attributes.merge(runner_type: :group_type, groups: [group]) attributes.merge(runner_type: :group_type, groups: [@group])
else else
forbidden! forbidden!
end end
...@@ -81,12 +81,7 @@ module API ...@@ -81,12 +81,7 @@ module API
end end
resource :jobs do resource :jobs do
before do before { set_application_context }
Gitlab::ApplicationContext.push(
user: -> { current_job&.user },
project: -> { current_job&.project }
)
end
desc 'Request a job' do desc 'Request a job' do
success Entities::JobRequest::Response success Entities::JobRequest::Response
......
...@@ -71,6 +71,26 @@ module API ...@@ -71,6 +71,26 @@ module API
header 'Job-Status', job.status header 'Job-Status', job.status
forbidden!(reason) forbidden!(reason)
end end
def set_application_context
if current_job
Gitlab::ApplicationContext.push(
user: -> { current_job.user },
project: -> { current_job.project }
)
elsif current_runner&.project_type?
Gitlab::ApplicationContext.push(
project: -> do
projects = current_runner.projects.limit(2) # rubocop: disable CodeReuse/ActiveRecord
projects.first if projects.length == 1
end
)
elsif current_runner&.group_type?
Gitlab::ApplicationContext.push(
namespace: -> { current_runner.groups.first }
)
end
end
end end
end end
end end
...@@ -798,6 +798,50 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -798,6 +798,50 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end end
end end
describe 'setting the application context' do
subject { request_job }
context 'when triggered by a user' do
let(:job) { create(:ci_build, user: user, project: project) }
subject { request_job(id: job.id) }
it_behaves_like 'storing arguments in the application context' do
let(:expected_params) { { user: user.username, project: project.full_path } }
end
it_behaves_like 'not executing any extra queries for the application context', 3 do
# Extra queries: User, Project, Route
let(:subject_proc) { proc { request_job(id: job.id) } }
end
end
context 'when the runner is of project type' do
it_behaves_like 'storing arguments in the application context' do
let(:expected_params) { { project: project.full_path } }
end
it_behaves_like 'not executing any extra queries for the application context', 2 do
# Extra queries: Project, Route
let(:subject_proc) { proc { request_job } }
end
end
context 'when the runner is of group type' do
let(:group) { create(:group) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
it_behaves_like 'storing arguments in the application context' do
let(:expected_params) { { root_namespace: group.full_path_components.first } }
end
it_behaves_like 'not executing any extra queries for the application context', 2 do
# Extra queries: Group, Route
let(:subject_proc) { proc { request_job } }
end
end
end
def request_job(token = runner.token, **params) def request_job(token = runner.token, **params)
new_params = params.merge(token: token, last_update: last_update) new_params = params.merge(token: token, last_update: last_update)
post api('/jobs/request'), params: new_params.to_json, headers: { 'User-Agent' => user_agent, 'Content-Type': 'application/json' } post api('/jobs/request'), params: new_params.to_json, headers: { 'User-Agent' => user_agent, 'Content-Type': 'application/json' }
......
...@@ -35,6 +35,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -35,6 +35,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end end
context 'when valid token is provided' do context 'when valid token is provided' do
def request
post api('/runners'), params: { token: token }
end
it 'creates runner with default values' do it 'creates runner with default values' do
post api('/runners'), params: { token: registration_token } post api('/runners'), params: { token: registration_token }
...@@ -51,9 +55,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -51,9 +55,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
context 'when project token is used' do context 'when project token is used' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:token) { project.runners_token }
it 'creates project runner' do it 'creates project runner' do
post api('/runners'), params: { token: project.runners_token } request
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(project.runners.size).to eq(1) expect(project.runners.size).to eq(1)
...@@ -62,13 +67,24 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -62,13 +67,24 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(runner.token).not_to eq(project.runners_token) expect(runner.token).not_to eq(project.runners_token)
expect(runner).to be_project_type expect(runner).to be_project_type
end end
it_behaves_like 'storing arguments in the application context' do
subject { request }
let(:expected_params) { { project: project.full_path } }
end
it_behaves_like 'not executing any extra queries for the application context' do
let(:subject_proc) { proc { request } }
end
end end
context 'when group token is used' do context 'when group token is used' do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:token) { group.runners_token }
it 'creates a group runner' do it 'creates a group runner' do
post api('/runners'), params: { token: group.runners_token } request
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(group.runners.reload.size).to eq(1) expect(group.runners.reload.size).to eq(1)
...@@ -77,6 +93,16 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -77,6 +93,16 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(runner.token).not_to eq(group.runners_token) expect(runner.token).not_to eq(group.runners_token)
expect(runner).to be_group_type expect(runner).to be_group_type
end end
it_behaves_like 'storing arguments in the application context' do
subject { request }
let(:expected_params) { { root_namespace: group.full_path_components.first } }
end
it_behaves_like 'not executing any extra queries for the application context' do
let(:subject_proc) { proc { request } }
end
end end
end end
......
...@@ -22,3 +22,19 @@ RSpec.shared_examples 'storing arguments in the application context' do ...@@ -22,3 +22,19 @@ RSpec.shared_examples 'storing arguments in the application context' do
hash.transform_keys! { |key| "meta.#{key}" } hash.transform_keys! { |key| "meta.#{key}" }
end end
end end
RSpec.shared_examples 'not executing any extra queries for the application context' do |expected_extra_queries = 0|
it 'does not execute more queries than without adding anything to the application context' do
# Call the subject once to memoize all factories being used for the spec, so they won't
# add any queries to the expectation.
subject_proc.call
expect do
allow(Gitlab::ApplicationContext).to receive(:push).and_call_original
subject_proc.call
end.to issue_same_number_of_queries_as {
allow(Gitlab::ApplicationContext).to receive(:push)
subject_proc.call
}.with_threshold(expected_extra_queries).ignoring_cached_queries
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