1# frozen_string_literal: true
2
3module Gitlab
4  module Ci
5    class RunnerInstructions
6      class ArgumentError < ::ArgumentError; end
7
8      include Gitlab::Allowable
9
10      OS = {
11        linux: {
12          human_readable_name: "Linux",
13          download_locations: {
14            amd64: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64",
15            '386': "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-386",
16            arm: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm",
17            arm64: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm64"
18          },
19          install_script_template_path: "lib/gitlab/ci/runner_instructions/templates/linux/install.sh",
20          runner_executable: "sudo gitlab-runner"
21        },
22        osx: {
23          human_readable_name: "macOS",
24          download_locations: {
25            amd64: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64"
26          },
27          install_script_template_path: "lib/gitlab/ci/runner_instructions/templates/osx/install.sh",
28          runner_executable: "sudo gitlab-runner"
29        },
30        windows: {
31          human_readable_name: "Windows",
32          download_locations: {
33            amd64: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe",
34            '386': "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-386.exe"
35          },
36          install_script_template_path: "lib/gitlab/ci/runner_instructions/templates/windows/install.ps1",
37          runner_executable: "./gitlab-runner.exe"
38        }
39      }.freeze
40
41      OTHER_ENVIRONMENTS = {
42        docker: {
43          human_readable_name: "Docker",
44          installation_instructions_url: "https://docs.gitlab.com/runner/install/docker.html"
45        },
46        kubernetes: {
47          human_readable_name: "Kubernetes",
48          installation_instructions_url: "https://docs.gitlab.com/runner/install/kubernetes.html"
49        }
50      }.freeze
51
52      attr_reader :errors
53
54      def initialize(os:, arch:)
55        @os = os
56        @arch = arch
57        @errors = []
58
59        validate_params
60      end
61
62      def install_script
63        with_error_handling [Gitlab::Ci::RunnerInstructions::ArgumentError] do
64          raise Gitlab::Ci::RunnerInstructions::ArgumentError, s_('Architecture not found for OS') unless environment[:download_locations].key?(@arch.to_sym)
65
66          replace_variables(get_file(environment[:install_script_template_path]))
67        end
68      end
69
70      def register_command
71        with_error_handling [Gitlab::Ci::RunnerInstructions::ArgumentError, Gitlab::Access::AccessDeniedError] do
72          raise Gitlab::Ci::RunnerInstructions::ArgumentError, s_('No runner executable') unless environment[:runner_executable]
73
74          server_url = Gitlab::Routing.url_helpers.root_url(only_path: false)
75          runner_executable = environment[:runner_executable]
76
77          "#{runner_executable} register --url #{server_url} --registration-token $REGISTRATION_TOKEN"
78        end
79      end
80
81      private
82
83      def with_error_handling(exceptions)
84        return if errors.present?
85
86        yield
87      rescue *exceptions => e
88        @errors << e.message
89        nil
90      end
91
92      def environment
93        @environment ||= OS[@os.to_sym] || ( raise Gitlab::Ci::RunnerInstructions::ArgumentError, s_('Invalid OS') )
94      end
95
96      def validate_params
97        @errors << s_('Missing OS') unless @os.present?
98        @errors << s_('Missing arch') unless @arch.present?
99      end
100
101      def replace_variables(expression)
102        expression.sub('${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}', "#{environment[:download_locations][@arch.to_sym]}")
103      end
104
105      def get_file(path)
106        File.read(Rails.root.join(path).to_s)
107      end
108    end
109  end
110end
111