runners.rb 5.08 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 13 14
        runners = filter_runners(current_user.ci_authorized_runners, params[:scope])
        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, user_is_admin: current_user.is_admin?
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 53 54 55 56 57 58 59

        attrs = attributes_for_keys [:description, :active, :tag_list]
        if runner.update(attrs)
          present runner, with: Entities::RunnerDetails
        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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
        runner.destroy!

        present runner, with: Entities::RunnerDetails
      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 94
      #   POST /projects/:id/runners/:runner_id
      post ':id/runners/:runner_id' do
95
        runner = get_runner(params[:runner_id])
96
        authenticate_enable_runner!(runner)
97 98 99 100 101
        Ci::RunnerProject.create(runner: runner, project: user_project)

        present runner, with: Entities::Runner
      end

102 103 104 105 106 107 108
      # 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
109 110 111 112 113
      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
114
        forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1
115 116 117 118 119

        runner_project.destroy

        present runner, with: Entities::Runner
      end
120 121 122 123 124 125 126
    end

    helpers do
      def filter_runners(runners, scope)
        return runners unless scope.present?

        available_scopes = ::Ci::Runner::AVAILABLE_SCOPES
127
        if (available_scopes & [scope]).empty?
128 129
          render_api_error!('Scope contains invalid value', 400)
        end
130 131

        runners.send(scope)
132 133 134 135 136 137 138 139
      end

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

140 141 142
      def authenticate_show_runner!(runner)
        return if runner.is_shared || current_user.is_admin?
        forbidden!("No access granted") unless user_can_access_runner?(runner)
143 144
      end

145 146 147 148
      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)
149 150
      end

151 152 153 154 155
      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)
156 157
      end

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

164
      def user_can_access_runner?(runner)
165
        current_user.ci_authorized_runners.exists?(runner.id)
166 167 168 169
      end
    end
  end
end