summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/entities.rb2
-rw-r--r--lib/api/issues.rb3
-rw-r--r--lib/api/merge_requests.rb4
-rw-r--r--lib/api/notes.rb2
-rw-r--r--lib/gitlab/gcp/model.rb13
-rw-r--r--lib/gitlab/gitaly_client.rb21
-rw-r--r--lib/gitlab/import_export/import_export.yml1
-rw-r--r--lib/gitlab/import_export/relation_factory.rb2
-rw-r--r--lib/gitlab/path_regex.rb1
-rw-r--r--lib/gitlab/usage_data.rb1
-rw-r--r--lib/google_api/auth.rb54
-rw-r--r--lib/google_api/cloud_platform/client.rb88
12 files changed, 188 insertions, 4 deletions
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 86dec3ca9f1..5f0bad14839 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -368,6 +368,7 @@ module API
end
expose :due_date
expose :confidential
+ expose :discussion_locked
expose :web_url do |issue, options|
Gitlab::UrlBuilder.build(issue)
@@ -464,6 +465,7 @@ module API
expose :diff_head_sha, as: :sha
expose :merge_commit_sha
expose :user_notes_count
+ expose :discussion_locked
expose :should_remove_source_branch?, as: :should_remove_source_branch
expose :force_remove_source_branch?, as: :force_remove_source_branch
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 1729df2aad0..0df41dcc903 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -48,6 +48,7 @@ module API
optional :labels, type: String, desc: 'Comma-separated list of label names'
optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY'
optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential'
+ optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked"
end
params :issue_params do
@@ -193,7 +194,7 @@ module API
desc: 'Date time when the issue was updated. Available only for admins and project owners.'
optional :state_event, type: String, values: %w[reopen close], desc: 'State of the issue'
use :issue_params
- at_least_one_of :title, :description, :assignee_ids, :assignee_id, :milestone_id,
+ at_least_one_of :title, :description, :assignee_ids, :assignee_id, :milestone_id, :discussion_locked,
:labels, :created_at, :due_date, :confidential, :state_event
end
put ':id/issues/:issue_iid' do
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 828bc48383e..be843ec8251 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -214,12 +214,14 @@ module API
:remove_source_branch,
:state_event,
:target_branch,
- :title
+ :title,
+ :discussion_locked
]
optional :title, type: String, allow_blank: false, desc: 'The title of the merge request'
optional :target_branch, type: String, allow_blank: false, desc: 'The target branch'
optional :state_event, type: String, values: %w[close reopen],
desc: 'Status of the merge request'
+ optional :discussion_locked, type: Boolean, desc: 'Whether the MR discussion is locked'
use :optional_params
at_least_one_of(*at_least_one_of_ce)
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index d6e7203adaf..0b9ab4eeb05 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -78,6 +78,8 @@ module API
}
if can?(current_user, noteable_read_ability_name(noteable), noteable)
+ authorize! :create_note, noteable
+
if params[:created_at] && (current_user.admin? || user_project.owner == current_user)
opts[:created_at] = params[:created_at]
end
diff --git a/lib/gitlab/gcp/model.rb b/lib/gitlab/gcp/model.rb
new file mode 100644
index 00000000000..195391f0e3c
--- /dev/null
+++ b/lib/gitlab/gcp/model.rb
@@ -0,0 +1,13 @@
+module Gitlab
+ module Gcp
+ module Model
+ def table_name_prefix
+ "gcp_"
+ end
+
+ def model_name
+ @model_name ||= ActiveModel::Name.new(self, nil, self.name.split("::").last)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 87b300dcf7e..cf36106e23d 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -28,6 +28,7 @@ module Gitlab
SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'.freeze
MAXIMUM_GITALY_CALLS = 30
+ CLIENT_NAME = (Sidekiq.server? ? 'gitlab-sidekiq' : 'gitlab-web').freeze
MUTEX = Mutex.new
private_constant :MUTEX
@@ -79,7 +80,16 @@ module Gitlab
def self.request_metadata(storage)
encoded_token = Base64.strict_encode64(token(storage).to_s)
- { metadata: { 'authorization' => "Bearer #{encoded_token}" } }
+ metadata = {
+ 'authorization' => "Bearer #{encoded_token}",
+ 'client_name' => CLIENT_NAME
+ }
+
+ feature_stack = Thread.current[:gitaly_feature_stack]
+ feature = feature_stack && feature_stack[0]
+ metadata['call_site'] = feature.to_s if feature
+
+ { metadata: metadata }
end
def self.token(storage)
@@ -137,7 +147,14 @@ module Gitlab
Gitlab::Metrics.measure(metric_name) do
# Some migrate calls wrap other migrate calls
allow_n_plus_1_calls do
- yield is_enabled
+ feature_stack = Thread.current[:gitaly_feature_stack] ||= []
+ feature_stack.unshift(feature)
+ begin
+ yield is_enabled
+ ensure
+ feature_stack.shift
+ Thread.current[:gitaly_feature_stack] = nil if feature_stack.empty?
+ end
end
end
end
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 2171c6c7bbb..dec8b4c5acd 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -53,6 +53,7 @@ project_tree:
- :auto_devops
- :triggers
- :pipeline_schedules
+ - :cluster
- :services
- :hooks
- protected_branches:
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index 380b336395d..a76cf1addc0 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -8,6 +8,8 @@ module Gitlab
triggers: 'Ci::Trigger',
pipeline_schedules: 'Ci::PipelineSchedule',
builds: 'Ci::Build',
+ cluster: 'Gcp::Cluster',
+ clusters: 'Gcp::Cluster',
hooks: 'ProjectHook',
merge_access_levels: 'ProtectedBranch::MergeAccessLevel',
push_access_levels: 'ProtectedBranch::PushAccessLevel',
diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb
index 7c02c9c5c48..e68160c8faf 100644
--- a/lib/gitlab/path_regex.rb
+++ b/lib/gitlab/path_regex.rb
@@ -33,6 +33,7 @@ module Gitlab
explore
favicon.ico
files
+ google_api
groups
health_check
help
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 6857038dba8..3f3ba77d47f 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -48,6 +48,7 @@ module Gitlab
deploy_keys: DeployKey.count,
deployments: Deployment.count,
environments: ::Environment.count,
+ gcp_clusters: ::Gcp::Cluster.count,
in_review_folder: ::Environment.in_review_folder.count,
groups: Group.count,
issues: Issue.count,
diff --git a/lib/google_api/auth.rb b/lib/google_api/auth.rb
new file mode 100644
index 00000000000..99a82c849e0
--- /dev/null
+++ b/lib/google_api/auth.rb
@@ -0,0 +1,54 @@
+module GoogleApi
+ class Auth
+ attr_reader :access_token, :redirect_uri, :state
+
+ ConfigMissingError = Class.new(StandardError)
+
+ def initialize(access_token, redirect_uri, state: nil)
+ @access_token = access_token
+ @redirect_uri = redirect_uri
+ @state = state
+ end
+
+ def authorize_url
+ client.auth_code.authorize_url(
+ redirect_uri: redirect_uri,
+ scope: scope,
+ state: state # This is used for arbitary redirection
+ )
+ end
+
+ def get_token(code)
+ ret = client.auth_code.get_token(code, redirect_uri: redirect_uri)
+ return ret.token, ret.expires_at
+ end
+
+ protected
+
+ def scope
+ raise NotImplementedError
+ end
+
+ private
+
+ def config
+ Gitlab.config.omniauth.providers.find { |provider| provider.name == "google_oauth2" }
+ end
+
+ def client
+ return @client if defined?(@client)
+
+ unless config
+ raise ConfigMissingError
+ end
+
+ @client = ::OAuth2::Client.new(
+ config.app_id,
+ config.app_secret,
+ site: 'https://accounts.google.com',
+ token_url: '/o/oauth2/token',
+ authorize_url: '/o/oauth2/auth'
+ )
+ end
+ end
+end
diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb
new file mode 100644
index 00000000000..a440a3e3562
--- /dev/null
+++ b/lib/google_api/cloud_platform/client.rb
@@ -0,0 +1,88 @@
+require 'google/apis/container_v1'
+
+module GoogleApi
+ module CloudPlatform
+ class Client < GoogleApi::Auth
+ DEFAULT_MACHINE_TYPE = 'n1-standard-1'.freeze
+ SCOPE = 'https://www.googleapis.com/auth/cloud-platform'.freeze
+ LEAST_TOKEN_LIFE_TIME = 10.minutes
+
+ class << self
+ def session_key_for_token
+ :cloud_platform_access_token
+ end
+
+ def session_key_for_expires_at
+ :cloud_platform_expires_at
+ end
+
+ def new_session_key_for_redirect_uri
+ SecureRandom.hex.tap do |state|
+ yield session_key_for_redirect_uri(state)
+ end
+ end
+
+ def session_key_for_redirect_uri(state)
+ "cloud_platform_second_redirect_uri_#{state}"
+ end
+ end
+
+ def scope
+ SCOPE
+ end
+
+ def validate_token(expires_at)
+ return false unless access_token
+ return false unless expires_at
+
+ # Making sure that the token will have been still alive during the cluster creation.
+ return false if token_life_time(expires_at) < LEAST_TOKEN_LIFE_TIME
+
+ true
+ end
+
+ def projects_zones_clusters_get(project_id, zone, cluster_id)
+ service = Google::Apis::ContainerV1::ContainerService.new
+ service.authorization = access_token
+
+ service.get_zone_cluster(project_id, zone, cluster_id)
+ end
+
+ def projects_zones_clusters_create(project_id, zone, cluster_name, cluster_size, machine_type:)
+ service = Google::Apis::ContainerV1::ContainerService.new
+ service.authorization = access_token
+
+ request_body = Google::Apis::ContainerV1::CreateClusterRequest.new(
+ {
+ "cluster": {
+ "name": cluster_name,
+ "initial_node_count": cluster_size,
+ "node_config": {
+ "machine_type": machine_type
+ }
+ }
+ } )
+
+ service.create_cluster(project_id, zone, request_body)
+ end
+
+ def projects_zones_operations(project_id, zone, operation_id)
+ service = Google::Apis::ContainerV1::ContainerService.new
+ service.authorization = access_token
+
+ service.get_zone_operation(project_id, zone, operation_id)
+ end
+
+ def parse_operation_id(self_link)
+ m = self_link.match(%r{projects/.*/zones/.*/operations/(.*)})
+ m[1] if m
+ end
+
+ private
+
+ def token_life_time(expires_at)
+ DateTime.strptime(expires_at, '%s').to_time.utc - Time.now.utc
+ end
+ end
+ end
+end