Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dependency_proxy_for_containers_controller.rb « groups « controllers « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e19b8ae35f87608c19eb8f8e534875ca42524ec6 (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
138
139
140
# frozen_string_literal: true

class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy::ApplicationController
  include Gitlab::Utils::StrongMemoize
  include DependencyProxy::GroupAccess
  include SendFileUpload
  include ::PackagesHelper # for event tracking
  include WorkhorseRequest

  before_action :ensure_group
  before_action :ensure_token_granted!, only: [:blob, :manifest]
  before_action :ensure_feature_enabled!

  before_action :verify_workhorse_api!, only: [:authorize_upload_blob, :upload_blob]
  skip_before_action :verify_authenticity_token, only: [:authorize_upload_blob, :upload_blob]

  attr_reader :token

  feature_category :dependency_proxy

  def manifest
    result = DependencyProxy::FindOrCreateManifestService.new(group, image, tag, token).execute

    if result[:status] == :success
      response.headers['Docker-Content-Digest'] = result[:manifest].digest
      response.headers['Content-Length'] = result[:manifest].size
      response.headers['Docker-Distribution-Api-Version'] = DependencyProxy::DISTRIBUTION_API_VERSION
      response.headers['Etag'] = "\"#{result[:manifest].digest}\""
      content_type = result[:manifest].content_type

      event_name = tracking_event_name(object_type: :manifest, from_cache: result[:from_cache])
      track_package_event(event_name, :dependency_proxy, namespace: group, user: auth_user)
      send_upload(
        result[:manifest].file,
        proxy: true,
        redirect_params: { query: { 'response-content-type' => content_type } },
        send_params: { type: content_type }
      )
    else
      render status: result[:http_status], json: result[:message]
    end
  end

  def blob
    return blob_via_workhorse if Feature.enabled?(:dependency_proxy_workhorse, group, default_enabled: :yaml)

    result = DependencyProxy::FindOrCreateBlobService
      .new(group, image, token, params[:sha]).execute

    if result[:status] == :success
      event_name = tracking_event_name(object_type: :blob, from_cache: result[:from_cache])
      track_package_event(event_name, :dependency_proxy, namespace: group, user: auth_user)
      send_upload(result[:blob].file)
    else
      head result[:http_status]
    end
  end

  def authorize_upload_blob
    set_workhorse_internal_api_content_type

    render json: DependencyProxy::FileUploader.workhorse_authorize(has_length: false)
  end

  def upload_blob
    @group.dependency_proxy_blobs.create!(
      file_name: blob_file_name,
      file: params[:file],
      size: params[:file].size
    )

    event_name = tracking_event_name(object_type: :blob, from_cache: false)
    track_package_event(event_name, :dependency_proxy, namespace: group, user: auth_user)

    head :ok
  end

  private

  def blob_via_workhorse
    blob = @group.dependency_proxy_blobs.find_by_file_name(blob_file_name)

    if blob.present?
      event_name = tracking_event_name(object_type: :blob, from_cache: true)
      track_package_event(event_name, :dependency_proxy, namespace: group, user: auth_user)

      send_upload(blob.file)
    else
      send_dependency(token, DependencyProxy::Registry.blob_url(image, params[:sha]), blob_file_name)
    end
  end

  def blob_file_name
    @blob_file_name ||= params[:sha].sub('sha256:', '') + '.gz'
  end

  def group
    strong_memoize(:group) do
      Group.find_by_full_path(params[:group_id], follow_redirects: true)
    end
  end

  def image
    params[:image]
  end

  def tag
    params[:tag]
  end

  def tracking_event_name(object_type:, from_cache:)
    event_name = "pull_#{object_type}"
    event_name = "#{event_name}_from_cache" if from_cache

    event_name
  end

  def dependency_proxy
    @dependency_proxy ||=
      group.dependency_proxy_setting || group.create_dependency_proxy_setting
  end

  def ensure_group
    render_404 unless group
  end

  def ensure_feature_enabled!
    render_404 unless dependency_proxy.enabled
  end

  def ensure_token_granted!
    result = DependencyProxy::RequestTokenService.new(image).execute

    if result[:status] == :success
      @token = result[:token]
    else
      render status: result[:http_status], json: result[:message]
    end
  end
end