BigW Consortium Gitlab

runners.rb 5.46 KB
Newer Older
1 2 3 4 5 6
module API
  # Runners API
  class Runners < Grape::API
    before { authenticate! }

    resource :runners do
7
      # Get runners available for user
8 9 10 11
      #
      # Example Request:
      #   GET /runners
      get do
12
        runners = filter_runners(current_user.ci_authorized_runners, params[:scope], without: ['specific', 'shared'])
13 14
        present paginate(runners), with: Entities::Runner
      end
15

16 17 18 19 20 21 22
      # Get all runners - shared and specific
      #
      # Example Request:
      #   GET /runners/all
      get 'all' do
        authenticated_as_admin!
        runners = filter_runners(Ci::Runner.all, params[:scope])
23 24 25
        present paginate(runners), with: Entities::Runner
      end

26 27 28 29 30 31
      # Get runner's details
      #
      # Parameters:
      #   id (required) - The ID of ther runner
      # Example Request:
      #   GET /runners/:id
32 33
      get ':id' do
        runner = get_runner(params[:id])
34
        authenticate_show_runner!(runner)
35

36
        present runner, with: Entities::RunnerDetails, current_user: current_user
37 38
      end

39 40 41 42 43 44 45 46 47
      # Update runner's details
      #
      # Parameters:
      #   id (required) - The ID of ther runner
      #   description (optional) - Runner's description
      #   active (optional) - Runner's status
      #   tag_list (optional) - Array of tags for runner
      # Example Request:
      #   PUT /runners/:id
48 49
      put ':id' do
        runner = get_runner(params[:id])
50
        authenticate_update_runner!(runner)
51

52
        attrs = attributes_for_keys [:description, :active, :tag_list, :run_untagged, :locked]
53
        if runner.update(attrs)
54
          present runner, with: Entities::RunnerDetails, current_user: current_user
55 56 57 58 59
        else
          render_validation_error!(runner)
        end
      end

60 61 62 63 64 65
      # Remove runner
      #
      # Parameters:
      #   id (required) - The ID of ther runner
      # Example Request:
      #   DELETE /runners/:id
66 67
      delete ':id' do
        runner = get_runner(params[:id])
68
        authenticate_delete_runner!(runner)
69 70
        runner.destroy!

71
        present runner, with: Entities::Runner
72 73 74 75 76 77 78 79 80 81 82 83 84 85
      end
    end

    resource :projects do
      before { authorize_admin_project }

      # Get runners available for project
      #
      # Example Request:
      #   GET /projects/:id/runners
      get ':id/runners' do
        runners = filter_runners(Ci::Runner.owned_or_shared(user_project.id), params[:scope])
        present paginate(runners), with: Entities::Runner
      end
86

87 88 89 90 91 92
      # Enable runner for project
      #
      # Parameters:
      #   id (required) - The ID of the project
      #   runner_id (required) - The ID of the runner
      # Example Request:
93
      #   POST /projects/:id/runners/:runner_id
94 95 96
      post ':id/runners' do
        required_attributes! [:runner_id]

97
        runner = get_runner(params[:runner_id])
98
        authenticate_enable_runner!(runner)
99

100 101 102
        runner_project = runner.assign_to(user_project)

        if runner_project.persisted?
103 104 105 106
          present runner, with: Entities::Runner
        else
          conflict!("Runner was already enabled for this project")
        end
107 108
      end

109 110 111 112 113 114 115
      # Disable project's runner
      #
      # Parameters:
      #   id (required) - The ID of the project
      #   runner_id (required) - The ID of the runner
      # Example Request:
      #   DELETE /projects/:id/runners/:runner_id
116 117 118 119 120
      delete ':id/runners/:runner_id' do
        runner_project = user_project.runner_projects.find_by(runner_id: params[:runner_id])
        not_found!('Runner') unless runner_project

        runner = runner_project.runner
121
        forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1
122 123 124 125 126

        runner_project.destroy

        present runner, with: Entities::Runner
      end
127 128 129
    end

    helpers do
130
      def filter_runners(runners, scope, options = {})
131 132 133
        return runners unless scope.present?

        available_scopes = ::Ci::Runner::AVAILABLE_SCOPES
134 135 136 137
        if options[:without]
          available_scopes = available_scopes - options[:without]
        end

138
        if (available_scopes & [scope]).empty?
139 140
          render_api_error!('Scope contains invalid value', 400)
        end
141 142

        runners.send(scope)
143 144 145 146 147 148 149 150
      end

      def get_runner(id)
        runner = Ci::Runner.find(id)
        not_found!('Runner') unless runner
        runner
      end

151 152 153
      def authenticate_show_runner!(runner)
        return if runner.is_shared || current_user.is_admin?
        forbidden!("No access granted") unless user_can_access_runner?(runner)
154 155
      end

156 157 158 159
      def authenticate_update_runner!(runner)
        return if current_user.is_admin?
        forbidden!("Runner is shared") if runner.is_shared?
        forbidden!("No access granted") unless user_can_access_runner?(runner)
160 161
      end

162 163 164 165 166
      def authenticate_delete_runner!(runner)
        return if current_user.is_admin?
        forbidden!("Runner is shared") if runner.is_shared?
        forbidden!("Runner associated with more than one project") if runner.projects.count > 1
        forbidden!("No access granted") unless user_can_access_runner?(runner)
167 168
      end

169 170
      def authenticate_enable_runner!(runner)
        forbidden!("Runner is shared") if runner.is_shared?
171
        forbidden!("Runner is locked") if runner.locked?
172 173
        return if current_user.is_admin?
        forbidden!("No access granted") unless user_can_access_runner?(runner)
174 175
      end

176
      def user_can_access_runner?(runner)
177
        current_user.ci_authorized_runners.exists?(runner.id)
178 179 180 181
      end
    end
  end
end