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 ""
msgid "April"
msgstr ""
msgid "Architecture not found for OS"
msgstr ""
msgid "Archive"
msgstr ""
......@@ -13204,6 +13207,9 @@ msgstr ""
msgid "Invalid Login or password"
msgstr ""
msgid "Invalid OS"
msgstr ""
msgid "Invalid URL"
msgstr ""
......@@ -15735,6 +15741,12 @@ msgstr ""
msgid "Missing OAuth configuration for GitHub."
msgstr ""
msgid "Missing OS"
msgstr ""
msgid "Missing arch"
msgstr ""
msgid "Missing commit signatures endpoint!"
msgstr ""
......@@ -16457,6 +16469,9 @@ msgstr ""
msgid "No required pipeline"
msgstr ""
msgid "No runner executable"
msgstr ""
msgid "No runners found"
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