Commit 61c1182b authored by Fabio Pitino's avatar Fabio Pitino

Merge branch 'add-install-register-runner-instructions' into 'master'

Add InstallScriptFactory, RegisterCommandBuilder and template files

See merge request gitlab-org/gitlab!35364
parents 69c664e4 95de4d4b
# frozen_string_literal: true
module Gitlab
module Ci
class RunnerInstructions
class ArgumentError < ::ArgumentError; end
include Gitlab::Allowable
OS = {
linux: {
human_readable_name: "Linux",
download_locations: {
amd64: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64",
'386': "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-386",
arm: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm",
arm64: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm64"
},
install_script_template_path: "lib/gitlab/ci/runner_instructions/templates/linux/install.sh",
runner_executable: "sudo gitlab-runner"
},
osx: {
human_readable_name: "macOS",
download_locations: {
amd64: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64"
},
install_script_template_path: "lib/gitlab/ci/runner_instructions/templates/osx/install.sh",
runner_executable: "sudo gitlab-runner"
},
windows: {
human_readable_name: "Windows",
download_locations: {
amd64: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe",
'386': "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-386.exe"
},
install_script_template_path: "lib/gitlab/ci/runner_instructions/templates/windows/install.ps1",
runner_executable: "./gitlab-runner.exe"
}
}.freeze
OTHER_ENVIRONMENTS = {
docker: {
human_readable_name: "Docker",
installation_instructions_url: "https://docs.gitlab.com/runner/install/docker.html"
},
kubernetes: {
human_readable_name: "Kubernetes",
installation_instructions_url: "https://docs.gitlab.com/runner/install/kubernetes.html"
}
}.freeze
attr_reader :errors
def initialize(current_user:, group: nil, project: nil, os:, arch:)
@current_user = current_user
@group = group
@project = project
@os = os
@arch = arch
@errors = []
validate_params
end
def install_script
with_error_handling [Gitlab::Ci::RunnerInstructions::ArgumentError] do
raise Gitlab::Ci::RunnerInstructions::ArgumentError, s_('Architecture not found for OS') unless environment[:download_locations].key?(@arch.to_sym)
replace_variables(get_file(environment[:install_script_template_path]))
end
end
def register_command
with_error_handling [Gitlab::Ci::RunnerInstructions::ArgumentError, Gitlab::Access::AccessDeniedError] do
raise Gitlab::Ci::RunnerInstructions::ArgumentError, s_('No runner executable') unless environment[:runner_executable]
server_url = Gitlab::Routing.url_helpers.root_url(only_path: false)
runner_executable = environment[:runner_executable]
"#{runner_executable} register --url #{server_url} --registration-token #{registration_token}"
end
end
private
def with_error_handling(exceptions)
return if errors.present?
yield
rescue *exceptions => e
@errors << e.message
nil
end
def environment
@environment ||= OS[@os.to_sym] || ( raise Gitlab::Ci::RunnerInstructions::ArgumentError, s_('Invalid OS') )
end
def validate_params
@errors << s_('Missing OS') unless @os.present?
@errors << s_('Missing arch') unless @arch.present?
end
def replace_variables(expression)
expression.sub('${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}', "#{environment[:download_locations][@arch.to_sym]}")
end
def get_file(path)
File.read(path)
end
def registration_token
project_token || group_token || instance_token
end
def project_token
return unless @project
raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :admin_pipeline, @project)
@project.runners_token
end
def group_token
return unless @group
raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :admin_group, @group)
@group.runners_token
end
def instance_token
raise Gitlab::Access::AccessDeniedError unless @current_user&.admin?
Gitlab::CurrentSettings.runners_registration_token
end
end
end
end
# Download the binary for your system
sudo curl -L --output /usr/local/bin/gitlab-runner ${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}
# Give it permissions to execute
sudo chmod +x /usr/local/bin/gitlab-runner
# Create a GitLab CI user
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
# Install and run as service
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start
# Download the binary for your system
sudo curl --output /usr/local/bin/gitlab-runner ${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}
# Give it permissions to execute
sudo chmod +x /usr/local/bin/gitlab-runner
# The rest of commands execute as the user who will run the Runner
# Register the Runner (steps below), then run
cd ~
gitlab-runner install
gitlab-runner start
# Run PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/starting-windows-powershell?view=powershell-7#with-administrative-privileges-run-as-administrator
# Create a folder somewhere in your system ex.: C:\GitLab-Runner
New-Item -Path 'C:\GitLab-Runner' -ItemType Directory
# Enter the folder
cd 'C:\GitLab-Runner'
# Dowload binary
Invoke-WebRequest -Uri "${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}" -OutFile "gitlab-runner.exe"
# Register the Runner (steps below), then run
.\gitlab-runner.exe install
.\gitlab-runner.exe start
...@@ -3130,6 +3130,9 @@ msgstr "" ...@@ -3130,6 +3130,9 @@ msgstr ""
msgid "April" msgid "April"
msgstr "" msgstr ""
msgid "Architecture not found for OS"
msgstr ""
msgid "Archive" msgid "Archive"
msgstr "" msgstr ""
...@@ -13204,6 +13207,9 @@ msgstr "" ...@@ -13204,6 +13207,9 @@ msgstr ""
msgid "Invalid Login or password" msgid "Invalid Login or password"
msgstr "" msgstr ""
msgid "Invalid OS"
msgstr ""
msgid "Invalid URL" msgid "Invalid URL"
msgstr "" msgstr ""
...@@ -15735,6 +15741,12 @@ msgstr "" ...@@ -15735,6 +15741,12 @@ msgstr ""
msgid "Missing OAuth configuration for GitHub." msgid "Missing OAuth configuration for GitHub."
msgstr "" msgstr ""
msgid "Missing OS"
msgstr ""
msgid "Missing arch"
msgstr ""
msgid "Missing commit signatures endpoint!" msgid "Missing commit signatures endpoint!"
msgstr "" msgstr ""
...@@ -16457,6 +16469,9 @@ msgstr "" ...@@ -16457,6 +16469,9 @@ msgstr ""
msgid "No required pipeline" msgid "No required pipeline"
msgstr "" msgstr ""
msgid "No runner executable"
msgstr ""
msgid "No runners found" msgid "No runners found"
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Ci::RunnerInstructions do
using RSpec::Parameterized::TableSyntax
let(:params) { {} }
let(:user) { create(:user) }
describe 'OS' do
Gitlab::Ci::RunnerInstructions::OS.each do |name, subject|
context name do
it 'has the required fields' do
expect(subject).to have_key(:human_readable_name)
expect(subject).to have_key(:download_locations)
expect(subject).to have_key(:install_script_template_path)
expect(subject).to have_key(:runner_executable)
end
it 'has a valid script' do
expect(File.read(subject[:install_script_template_path]).length).not_to eq(0)
end
end
end
end
describe 'OTHER_ENVIRONMENTS' do
Gitlab::Ci::RunnerInstructions::OTHER_ENVIRONMENTS.each do |name, subject|
context name do
it 'has the required fields' do
expect(subject).to have_key(:human_readable_name)
expect(subject).to have_key(:installation_instructions_url)
end
end
end
end
describe '#install_script' do
subject { described_class.new(current_user: user, **params) }
context 'invalid params' do
where(:current_params, :expected_error_message) do
{ os: nil, arch: nil } | 'Missing OS'
{ os: 'linux', arch: nil } | 'Missing arch'
{ os: nil, arch: 'amd64' } | 'Missing OS'
{ os: 'non_existing_os', arch: 'amd64' } | 'Invalid OS'
{ os: 'linux', arch: 'non_existing_arch' } | 'Architecture not found for OS'
{ os: 'windows', arch: 'non_existing_arch' } | 'Architecture not found for OS'
end
with_them do
let(:params) { current_params }
it 'raises argument error' do
result = subject.install_script
expect(result).to be_nil
expect(subject.errors).to include(expected_error_message)
end
end
end
context 'with valid params' do
where(:os, :arch) do
'linux' | 'amd64'
'linux' | '386'
'linux' | 'arm'
'linux' | 'arm64'
'windows' | 'amd64'
'windows' | '386'
'osx' | 'amd64'
end
with_them do
let(:params) { { os: os, arch: arch } }
it 'returns string containing correct params' do
result = subject.install_script
expect(result).to be_a(String)
if os == 'osx'
expect(result).to include("darwin-#{arch}")
else
expect(result).to include("#{os}-#{arch}")
end
end
end
end
end
describe '#register_command' do
let(:params) { { os: 'linux', arch: 'foo' } }
where(:commands) do
Gitlab::Ci::RunnerInstructions::OS.map do |name, values|
{ name => values[:runner_executable] }
end
end
context 'group' do
let(:group) { create(:group) }
subject { described_class.new(current_user: user, group: group, **params) }
context 'user is owner' do
before do
group.add_owner(user)
end
with_them do
let(:params) { { os: commands.each_key.first, arch: 'foo' } }
it 'have correct configurations' do
result = subject.register_command
expect(result).to include("#{commands[commands.each_key.first]} register")
expect(result).to include("--registration-token #{group.runners_token}")
expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
end
end
end
context 'user is not owner' do
where(:user_permission) do
[:maintainer, :developer, :reporter, :guest]
end
with_them do
before do
create(:group_member, user_permission, group: group, user: user)
end
it 'raises error' do
result = subject.register_command
expect(result).to be_nil
expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
end
end
end
end
context 'project' do
let(:project) { create(:project) }
subject { described_class.new(current_user: user, project: project, **params) }
context 'user is maintainer' do
before do
project.add_maintainer(user)
end
with_them do
let(:params) { { os: commands.each_key.first, arch: 'foo' } }
it 'have correct configurations' do
result = subject.register_command
expect(result).to include("#{commands[commands.each_key.first]} register")
expect(result).to include("--registration-token #{project.runners_token}")
expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
end
end
end
context 'user is not maintainer' do
where(:user_permission) do
[:developer, :reporter, :guest]
end
with_them do
before do
create(:project_member, user_permission, project: project, user: user)
end
it 'raises error' do
result = subject.register_command
expect(result).to be_nil
expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
end
end
end
end
context 'instance' do
subject { described_class.new(current_user: user, **params) }
context 'user is admin' do
let(:user) { create(:user, :admin) }
with_them do
let(:params) { { os: commands.each_key.first, arch: 'foo' } }
it 'have correct configurations' do
result = subject.register_command
expect(result).to include("#{commands[commands.each_key.first]} register")
expect(result).to include("--registration-token #{Gitlab::CurrentSettings.runners_registration_token}")
expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
end
end
end
context 'user is not admin' do
it 'raises error' do
result = subject.register_command
expect(result).to be_nil
expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
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