Commit dca1424b authored by Stan Hu's avatar Stan Hu

Store CI runner config data

With https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/2848,
we will now be sending some information about the runner config.
Currently, this is only limited to the `gpus` string, but it can be
extended to cover more.

Changelog: added
parent e49d7bf4
...@@ -163,6 +163,8 @@ module Ci ...@@ -163,6 +163,8 @@ module Ci
numericality: { greater_than_or_equal_to: 0.0, numericality: { greater_than_or_equal_to: 0.0,
message: 'needs to be non-negative' } message: 'needs to be non-negative' }
validates :config, json_schema: { filename: 'ci_runner_config' }
# Searches for runners matching the given query. # Searches for runners matching the given query.
# #
# This method uses ILIKE on PostgreSQL. # This method uses ILIKE on PostgreSQL.
...@@ -353,7 +355,7 @@ module Ci ...@@ -353,7 +355,7 @@ module Ci
end end
def heartbeat(values) def heartbeat(values)
values = values&.slice(:version, :revision, :platform, :architecture, :ip_address) || {} values = values&.slice(:version, :revision, :platform, :architecture, :ip_address, :config) || {}
values[:contacted_at] = Time.current values[:contacted_at] = Time.current
cache_attributes(values) cache_attributes(values)
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "CI Runner config values",
"type": "object",
"properties": {
"gpus": { "type": "string" }
},
"additionalProperties": false
}
# frozen_string_literal: true
class AddConfigToCiRunners < ActiveRecord::Migration[6.0]
def change
add_column :ci_runners, :config, :jsonb, default: {}, null: false
end
end
0bd47f9055aab927a4e8efb4f995f44532880926af9892af60f7d2b8dcdef4a6
\ No newline at end of file
...@@ -11148,7 +11148,8 @@ CREATE TABLE ci_runners ( ...@@ -11148,7 +11148,8 @@ CREATE TABLE ci_runners (
runner_type smallint NOT NULL, runner_type smallint NOT NULL,
token_encrypted character varying, token_encrypted character varying,
public_projects_minutes_cost_factor double precision DEFAULT 0.0 NOT NULL, public_projects_minutes_cost_factor double precision DEFAULT 0.0 NOT NULL,
private_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL private_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
config jsonb DEFAULT '{}'::jsonb NOT NULL
); );
CREATE SEQUENCE ci_runners_id_seq CREATE SEQUENCE ci_runners_id_seq
...@@ -98,6 +98,9 @@ module API ...@@ -98,6 +98,9 @@ module API
optional :architecture, type: String, desc: %q(Runner's architecture) optional :architecture, type: String, desc: %q(Runner's architecture)
optional :executor, type: String, desc: %q(Runner's executor) optional :executor, type: String, desc: %q(Runner's executor)
optional :features, type: Hash, desc: %q(Runner's features) optional :features, type: Hash, desc: %q(Runner's features)
optional :config, type: Hash, desc: %q(Runner's config) do
optional :gpus, type: String, desc: %q(GPUs enabled)
end
end end
optional :session, type: Hash, desc: %q(Runner's session data) do optional :session, type: Hash, desc: %q(Runner's session data) do
optional :url, type: String, desc: %q(Session's url) optional :url, type: String, desc: %q(Session's url)
......
...@@ -25,6 +25,7 @@ module API ...@@ -25,6 +25,7 @@ module API
return get_runner_ip unless params['info'].present? return get_runner_ip unless params['info'].present?
attributes_for_keys(%w(name version revision platform architecture), params['info']) attributes_for_keys(%w(name version revision platform architecture), params['info'])
.merge(get_runner_config_from_request)
.merge(get_runner_ip) .merge(get_runner_ip)
end end
...@@ -91,6 +92,12 @@ module API ...@@ -91,6 +92,12 @@ module API
def track_ci_minutes_usage!(_build, _runner) def track_ci_minutes_usage!(_build, _runner)
# noop: overridden in EE # noop: overridden in EE
end end
private
def get_runner_config_from_request
{ config: attributes_for_keys(%w(gpus), params.dig('info', 'config')) }
end
end end
end end
end end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::Helpers::Runner do
let(:ip_address) { '1.2.3.4' }
let(:runner_class) do
Class.new do
include API::Helpers
include API::Helpers::Runner
attr_accessor :params
def initialize(params)
@params = params
end
def ip_address
'1.2.3.4'
end
end
end
let(:runner_helper) { runner_class.new(runner_params) }
describe '#get_runner_details_from_request' do
context 'when no runner info is present' do
let(:runner_params) { {} }
it 'returns the runner IP' do
expect(runner_helper.get_runner_details_from_request).to eq({ ip_address: ip_address })
end
end
context 'when runner info is present' do
let(:name) { 'runner' }
let(:version) { '1.2.3' }
let(:revision) { '10.0' }
let(:platform) { 'test' }
let(:architecture) { 'arm' }
let(:config) { { 'gpus' => 'all' } }
let(:runner_params) do
{
'info' =>
{
'name' => name,
'version' => version,
'revision' => revision,
'platform' => platform,
'architecture' => architecture,
'config' => config,
'ignored' => 1
}
}
end
subject(:details) { runner_helper.get_runner_details_from_request }
it 'extracts the runner details', :aggregate_failures do
expect(details.keys).to match_array(%w(name version revision platform architecture config ip_address))
expect(details['name']).to eq(name)
expect(details['version']).to eq(version)
expect(details['revision']).to eq(revision)
expect(details['platform']).to eq(platform)
expect(details['architecture']).to eq(architecture)
expect(details['config']).to eq(config)
expect(details['ip_address']).to eq(ip_address)
end
end
end
end
...@@ -75,6 +75,22 @@ RSpec.describe Ci::Runner do ...@@ -75,6 +75,22 @@ RSpec.describe Ci::Runner do
expect { create(:group, runners: [project_runner]) } expect { create(:group, runners: [project_runner]) }
.to raise_error(ActiveRecord::RecordInvalid) .to raise_error(ActiveRecord::RecordInvalid)
end end
context 'when runner has config' do
it 'is valid' do
runner = build(:ci_runner, config: { gpus: "all" })
expect(runner).to be_valid
end
end
context 'when runner has an invalid config' do
it 'is invalid' do
runner = build(:ci_runner, config: { test: 1 })
expect(runner).not_to be_valid
end
end
end end
context 'cost factors validations' do context 'cost factors validations' do
...@@ -653,7 +669,7 @@ RSpec.describe Ci::Runner do ...@@ -653,7 +669,7 @@ RSpec.describe Ci::Runner do
describe '#heartbeat' do describe '#heartbeat' do
let(:runner) { create(:ci_runner, :project) } let(:runner) { create(:ci_runner, :project) }
subject { runner.heartbeat(architecture: '18-bit') } subject { runner.heartbeat(architecture: '18-bit', config: { gpus: "all" }) }
context 'when database was updated recently' do context 'when database was updated recently' do
before do before do
...@@ -701,6 +717,7 @@ RSpec.describe Ci::Runner do ...@@ -701,6 +717,7 @@ RSpec.describe Ci::Runner do
def does_db_update def does_db_update
expect { subject }.to change { runner.reload.read_attribute(:contacted_at) } expect { subject }.to change { runner.reload.read_attribute(:contacted_at) }
.and change { runner.reload.read_attribute(:architecture) } .and change { runner.reload.read_attribute(:architecture) }
.and change { runner.reload.read_attribute(:config) }
end end
end end
......
...@@ -439,6 +439,13 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do ...@@ -439,6 +439,13 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end end
end end
it "sets the runner's config" do
request_job info: { 'config' => { 'gpus' => 'all', 'ignored' => 'hello' } }
expect(response).to have_gitlab_http_status(:created)
expect(runner.reload.config).to eq( { 'gpus' => 'all' } )
end
it "sets the runner's ip_address" do it "sets the runner's ip_address" do
post api('/jobs/request'), post api('/jobs/request'),
params: { token: runner.token }, params: { token: runner.token },
......
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