summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/deploy_keys.rb1
-rw-r--r--lib/gitlab/database/migration_helpers.rb1
-rw-r--r--lib/gitlab/database/migration_helpers/wraparound_vacuum_helpers.rb90
-rw-r--r--lib/product_analytics/settings.rb27
4 files changed, 119 insertions, 0 deletions
diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb
index ffe0b6589bc..634d6052b99 100644
--- a/lib/api/deploy_keys.rb
+++ b/lib/api/deploy_keys.rb
@@ -104,6 +104,7 @@ module API
requires :key, type: String, desc: 'New deploy key'
requires :title, type: String, desc: "New deploy key's title"
optional :can_push, type: Boolean, desc: "Can deploy key push to the project's repository"
+ optional :expires_at, type: DateTime, desc: 'The expiration date of the SSH key in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)'
end
# rubocop: disable CodeReuse/ActiveRecord
post ":id/deploy_keys" do
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 91199c55b1d..291f483e6e4 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -15,6 +15,7 @@ module Gitlab
include RenameTableHelpers
include AsyncIndexes::MigrationHelpers
include AsyncConstraints::MigrationHelpers
+ include WraparoundVacuumHelpers
def define_batchable_model(table_name, connection: self.connection)
super(table_name, connection: connection)
diff --git a/lib/gitlab/database/migration_helpers/wraparound_vacuum_helpers.rb b/lib/gitlab/database/migration_helpers/wraparound_vacuum_helpers.rb
new file mode 100644
index 00000000000..01ff3dcbfb8
--- /dev/null
+++ b/lib/gitlab/database/migration_helpers/wraparound_vacuum_helpers.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module MigrationHelpers
+ module WraparoundVacuumHelpers
+ class WraparoundCheck
+ WraparoundError = Class.new(StandardError)
+
+ def initialize(table_name, migration:)
+ @migration = migration
+ @table_name = table_name
+
+ validate_table_existence!
+ end
+
+ def execute
+ return if disabled?
+ return unless wraparound_vacuum.present?
+
+ log "Autovacuum with wraparound prevention mode is running on `#{table_name}`", title: true
+ log "This process prevents the migration from acquiring the necessary locks"
+ log "Query: `#{wraparound_vacuum[:query]}`"
+ log "Current duration: #{wraparound_vacuum[:duration].inspect}"
+ log "Process id: #{wraparound_vacuum[:pid]}"
+ log "You can wait until it completes or if absolutely necessary interrupt it using: " \
+ "`select pg_cancel_backend(#{wraparound_vacuum[:pid]});`"
+ log "Be aware that a new process will kick in immediately, so multiple interruptions " \
+ "might be required to time it right with the locks retry mechanism"
+ end
+
+ private
+
+ attr_reader :table_name
+
+ delegate :say, :connection, to: :@migration
+
+ def wraparound_vacuum
+ @wraparound_vacuum ||= transform_wraparound_vacuum
+ end
+
+ def transform_wraparound_vacuum
+ result = raw_wraparound_vacuum
+ values = Array.wrap(result.cast_values.first)
+
+ result.columns.zip(values).to_h.with_indifferent_access.compact
+ end
+
+ def raw_wraparound_vacuum
+ connection.select_all(<<~SQL.squish)
+ SELECT pid, state, age(clock_timestamp(), query_start) as duration, query
+ FROM pg_stat_activity
+ WHERE query ILIKE '%VACUUM%' || #{quoted_table_name} || '%(to prevent wraparound)'
+ AND backend_type = 'autovacuum worker'
+ LIMIT 1
+ SQL
+ end
+
+ def validate_table_existence!
+ return if connection.table_exists?(table_name)
+
+ raise WraparoundError, "Table #{table_name} does not exist"
+ end
+
+ def quoted_table_name
+ connection.quote(table_name)
+ end
+
+ def disabled?
+ return true unless wraparound_check_allowed?
+
+ Gitlab::Utils.to_boolean(ENV['GITLAB_MIGRATIONS_DISABLE_WRAPAROUND_CHECK'])
+ end
+
+ def wraparound_check_allowed?
+ Gitlab.com? || Gitlab.dev_or_test_env?
+ end
+
+ def log(text, title: false)
+ say text, !title
+ end
+ end
+
+ def check_if_wraparound_in_progress(table_name)
+ WraparoundCheck.new(table_name, migration: self).execute
+ end
+ end
+ end
+ end
+end
diff --git a/lib/product_analytics/settings.rb b/lib/product_analytics/settings.rb
new file mode 100644
index 00000000000..9e38adf8a13
--- /dev/null
+++ b/lib/product_analytics/settings.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module ProductAnalytics
+ class Settings
+ CONFIG_KEYS = (%w[jitsu_host jitsu_project_xid jitsu_administrator_email jitsu_administrator_password] +
+ %w[product_analytics_data_collector_host product_analytics_clickhouse_connection_string] +
+ %w[cube_api_base_url cube_api_key]).freeze
+
+ class << self
+ def enabled?
+ ::Gitlab::CurrentSettings.product_analytics_enabled? && configured?
+ end
+
+ def configured?
+ CONFIG_KEYS.all? do |key|
+ ::Gitlab::CurrentSettings.public_send(key)&.present? # rubocop:disable GitlabSecurity/PublicSend
+ end
+ end
+
+ CONFIG_KEYS.each do |key|
+ define_method key.to_sym do
+ ::Gitlab::CurrentSettings.public_send(key) # rubocop:disable GitlabSecurity/PublicSend
+ end
+ end
+ end
+ end
+end