2020-05-06 02:09:36 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# ProjectRepositoryStorageMove are details of repository storage moves for a
|
|
|
|
# project. For example, moving a project to another gitaly node to help
|
|
|
|
# balance storage capacity.
|
|
|
|
class ProjectRepositoryStorageMove < ApplicationRecord
|
|
|
|
include AfterCommitQueue
|
|
|
|
|
|
|
|
belongs_to :project, inverse_of: :repository_storage_moves
|
|
|
|
|
|
|
|
validates :project, presence: true
|
|
|
|
validates :state, presence: true
|
|
|
|
validates :source_storage_name,
|
|
|
|
on: :create,
|
|
|
|
presence: true,
|
|
|
|
inclusion: { in: ->(_) { Gitlab.config.repositories.storages.keys } }
|
|
|
|
validates :destination_storage_name,
|
|
|
|
on: :create,
|
|
|
|
presence: true,
|
|
|
|
inclusion: { in: ->(_) { Gitlab.config.repositories.storages.keys } }
|
2020-05-26 17:07:45 -04:00
|
|
|
validate :project_repository_writable, on: :create
|
2020-05-06 02:09:36 -04:00
|
|
|
|
2020-10-19 08:09:20 -04:00
|
|
|
default_value_for(:destination_storage_name, allows_nil: false) do
|
|
|
|
pick_repository_storage
|
|
|
|
end
|
|
|
|
|
2020-05-06 02:09:36 -04:00
|
|
|
state_machine initial: :initial do
|
|
|
|
event :schedule do
|
|
|
|
transition initial: :scheduled
|
|
|
|
end
|
|
|
|
|
|
|
|
event :start do
|
|
|
|
transition scheduled: :started
|
|
|
|
end
|
|
|
|
|
2020-08-13 08:09:50 -04:00
|
|
|
event :finish_replication do
|
|
|
|
transition started: :replicated
|
|
|
|
end
|
|
|
|
|
|
|
|
event :finish_cleanup do
|
|
|
|
transition replicated: :finished
|
2020-05-06 02:09:36 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
event :do_fail do
|
|
|
|
transition [:initial, :scheduled, :started] => :failed
|
2020-08-13 08:09:50 -04:00
|
|
|
transition replicated: :cleanup_failed
|
2020-05-06 02:09:36 -04:00
|
|
|
end
|
|
|
|
|
2020-10-21 02:09:17 -04:00
|
|
|
around_transition initial: :scheduled do |storage_move, block|
|
|
|
|
block.call
|
|
|
|
|
|
|
|
begin
|
|
|
|
storage_move.project.set_repository_read_only!
|
|
|
|
rescue => err
|
|
|
|
errors.add(:project, err.message)
|
|
|
|
next false
|
|
|
|
end
|
2020-05-26 17:07:45 -04:00
|
|
|
|
2020-05-06 02:09:36 -04:00
|
|
|
storage_move.run_after_commit do
|
|
|
|
ProjectUpdateRepositoryStorageWorker.perform_async(
|
2020-05-10 20:09:29 -04:00
|
|
|
storage_move.project_id,
|
|
|
|
storage_move.destination_storage_name,
|
|
|
|
storage_move.id
|
2020-05-06 02:09:36 -04:00
|
|
|
)
|
|
|
|
end
|
2020-10-21 02:09:17 -04:00
|
|
|
|
|
|
|
true
|
2020-05-06 02:09:36 -04:00
|
|
|
end
|
|
|
|
|
2020-10-21 02:09:17 -04:00
|
|
|
before_transition started: :replicated do |storage_move|
|
|
|
|
storage_move.project.set_repository_writable!
|
|
|
|
|
|
|
|
storage_move.project.update_column(:repository_storage, storage_move.destination_storage_name)
|
2020-05-26 17:07:45 -04:00
|
|
|
end
|
|
|
|
|
2020-10-21 02:09:17 -04:00
|
|
|
before_transition started: :failed do |storage_move|
|
|
|
|
storage_move.project.set_repository_writable!
|
2020-05-26 17:07:45 -04:00
|
|
|
end
|
|
|
|
|
2020-05-06 02:09:36 -04:00
|
|
|
state :initial, value: 1
|
|
|
|
state :scheduled, value: 2
|
|
|
|
state :started, value: 3
|
|
|
|
state :finished, value: 4
|
|
|
|
state :failed, value: 5
|
2020-08-13 08:09:50 -04:00
|
|
|
state :replicated, value: 6
|
|
|
|
state :cleanup_failed, value: 7
|
2020-05-06 02:09:36 -04:00
|
|
|
end
|
2020-05-15 05:07:59 -04:00
|
|
|
|
|
|
|
scope :order_created_at_desc, -> { order(created_at: :desc) }
|
|
|
|
scope :with_projects, -> { includes(project: :route) }
|
2020-05-26 17:07:45 -04:00
|
|
|
|
2020-10-19 08:09:20 -04:00
|
|
|
class << self
|
|
|
|
def pick_repository_storage
|
|
|
|
Project.pick_repository_storage
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-05-26 17:07:45 -04:00
|
|
|
private
|
|
|
|
|
|
|
|
def project_repository_writable
|
|
|
|
errors.add(:project, _('is read only')) if project&.repository_read_only?
|
|
|
|
end
|
2020-05-06 02:09:36 -04:00
|
|
|
end
|