summaryrefslogtreecommitdiff
path: root/lib/gitlab/ci/runner_instructions.rb
blob: dd0bfa768a8156313550d5790d4e38057463c450 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# 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(Rails.root.join(path).to_s)
      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