rosa-build/app/models/node_instruction.rb

87 lines
2.0 KiB
Ruby

class NodeInstruction < ActiveRecord::Base
STATUSES = [
DISABLED = 'disabled',
READY = 'ready',
RESTARTING = 'restarting',
FAILED = 'failed'
]
LOCK_KEY = 'NodeInstruction::lock-key'
belongs_to :user
scope :duplicate, -> id, user_id {
where.not(id: id.to_i).where(user_id: user_id, status: STATUSES - [DISABLED])
}
attr_encrypted :instruction, key: APP_CONFIG['keys']['node_instruction_secret_key']
validates :user, presence: true
validates :instruction, presence: true, length: { maximum: 10000 }
validates :status, presence: true
validate -> {
errors.add(:status, 'Can be only single active instruction for each node') if !disabled? && NodeInstruction.duplicate(id.to_i, user_id).exists?
}
state_machine :status, initial: :ready do
after_transition(on: :restart) do |instruction, transition|
instruction.perform_restart
end
event :ready do
transition %i(ready restarting disabled failed) => :ready
end
event :disable do
transition ready: :disabled
end
event :restart do
transition ready: :restarting
end
event :restart_failed do
transition restarting: :failed
end
end
def perform_restart
restart_failed if NodeInstruction.all_locked?
success = false
stdout = ''
instruction.lines.each do |command|
next if command.blank?
command.chomp!; command.strip!
stdout << %x[ #{command} 2>&1 ]
success = $?.success?
end
build_lists = BuildList.where(builder_id: user_id, external_nodes: [nil, '']).
for_status(BuildList::BUILD_STARTED)
build_lists.find_each do |bl|
bl.update_column(:status, BuildList::BUILD_PENDING)
bl.restart_job
end
update_column(:output, stdout)
success ? ready : restart_failed
end
later :perform_restart, queue: :low
def self.all_locked?
Redis.current.get(LOCK_KEY).present?
end
def self.lock_all
Redis.current.set(LOCK_KEY, 1)
end
def self.unlock_all
Redis.current.del(LOCK_KEY)
end
end