summaryrefslogtreecommitdiff
path: root/app/finders/ci/runners_finder.rb
blob: bc1dcb3ad5f3ccad52de481000ecdbdbe9c6ef5f (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
# frozen_string_literal: true

module Ci
  class RunnersFinder < UnionFinder
    include Gitlab::Allowable

    ALLOWED_SORTS = %w[contacted_asc contacted_desc created_at_asc created_at_desc created_date token_expires_at_asc token_expires_at_desc].freeze
    DEFAULT_SORT = 'created_at_desc'

    def initialize(current_user:, params:)
      @params = params
      @group = params.delete(:group)
      @project = params.delete(:project)
      @current_user = current_user
    end

    def execute
      search!
      filter_by_active!
      filter_by_status!
      filter_by_upgrade_status!
      filter_by_runner_type!
      filter_by_tag_list!
      sort!
      request_tag_list!

      @runners

    rescue Gitlab::Access::AccessDeniedError
      Ci::Runner.none
    end

    def sort_key
      ALLOWED_SORTS.include?(@params[:sort]) ? @params[:sort] : DEFAULT_SORT
    end

    private

    def search!
      if @project
        project_runners
      elsif @group
        group_runners
      else
        all_runners
      end

      @runners = @runners.search(@params[:search]) if @params[:search].present?
    end

    def all_runners
      raise Gitlab::Access::AccessDeniedError unless @current_user&.can_admin_all_resources?

      @runners = Ci::Runner.all
    end

    def group_runners
      raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :read_group_runners, @group)

      @runners = case @params[:membership]
                 when :direct
                   Ci::Runner.belonging_to_group(@group.id)
                 when :descendants, nil
                   Ci::Runner.belonging_to_group_or_project_descendants(@group.id)
                 when :all_available
                   unless can?(@current_user, :read_group_all_available_runners, @group)
                     raise Gitlab::Access::AccessDeniedError
                   end

                   Ci::Runner.usable_from_scope(@group)
                 else
                   raise ArgumentError, 'Invalid membership filter'
                 end
    end

    def project_runners
      raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :admin_project, @project)

      @runners = ::Ci::Runner.owned_or_instance_wide(@project.id)
    end

    def filter_by_active!
      @runners = @runners.active(@params[:active]) if @params.include?(:active)
    end

    def filter_by_status!
      filter_by!(:status_status, Ci::Runner::AVAILABLE_STATUSES)
    end

    def filter_by_upgrade_status!
      upgrade_status = @params[:upgrade_status]

      return unless upgrade_status

      unless Ci::RunnerVersion.statuses.key?(upgrade_status)
        raise ArgumentError, "Invalid upgrade status value '#{upgrade_status}'"
      end

      @runners = @runners.with_upgrade_status(upgrade_status)
    end

    def filter_by_runner_type!
      filter_by!(:type_type, Ci::Runner::AVAILABLE_TYPES)
    end

    def filter_by_tag_list!
      tag_list = @params[:tag_name].presence

      if tag_list
        @runners = @runners.tagged_with(tag_list)
      end
    end

    def sort!
      @runners = @runners.order_by(sort_key)
    end

    def request_tag_list!
      @runners = @runners.with_tags if !@params[:preload].present? || @params.dig(:preload, :tag_name)
    end

    def filter_by!(scope_name, available_scopes)
      scope = @params[scope_name]

      if scope.present? && available_scopes.include?(scope)
        @runners = @runners.public_send(scope) # rubocop:disable GitlabSecurity/PublicSend
      end
    end
  end
end