2014-04-14 22:32:25 +01:00
|
|
|
class NodeInstruction < ActiveRecord::Base
|
|
|
|
STATUSES = [
|
|
|
|
DISABLED = 'disabled',
|
|
|
|
READY = 'ready',
|
|
|
|
RESTARTING = 'restarting',
|
|
|
|
FAILED = 'failed'
|
|
|
|
]
|
|
|
|
|
2014-04-17 20:08:22 +01:00
|
|
|
LOCK_KEY = 'NodeInstruction::lock-key'
|
|
|
|
|
2014-04-14 22:32:25 +01:00
|
|
|
belongs_to :user
|
|
|
|
|
2014-04-17 20:15:35 +01:00
|
|
|
scope :duplicate, -> id, user_id {
|
|
|
|
where.not(id: id.to_i).where(user_id: user_id, status: STATUSES - [DISABLED])
|
|
|
|
}
|
|
|
|
|
2014-04-14 22:32:25 +01:00
|
|
|
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 -> {
|
2014-04-17 20:15:35 +01:00
|
|
|
errors.add(:status, 'Can be only single active instruction for each node') if !disabled? && NodeInstruction.duplicate(id.to_i, user_id).exists?
|
2014-04-14 22:32:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
attr_accessible :instruction, :user_id, :output, :status
|
|
|
|
|
|
|
|
state_machine :status, initial: :ready do
|
2014-04-15 20:15:52 +01:00
|
|
|
|
2014-04-17 20:08:22 +01:00
|
|
|
after_transition(on: :restart) do |instruction, transition|
|
|
|
|
instruction.perform_restart
|
|
|
|
end
|
2014-04-15 20:15:52 +01:00
|
|
|
|
2014-04-14 22:32:25 +01:00
|
|
|
event :ready do
|
2014-04-15 19:08:43 +01:00
|
|
|
transition %i(ready restarting disabled failed) => :ready
|
2014-04-14 22:32:25 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
event :disable do
|
|
|
|
transition ready: :disabled
|
|
|
|
end
|
|
|
|
|
|
|
|
event :restart do
|
2014-04-15 19:08:43 +01:00
|
|
|
transition ready: :restarting
|
2014-04-14 22:32:25 +01:00
|
|
|
end
|
|
|
|
|
2014-04-15 22:26:12 +01:00
|
|
|
event :restart_failed do
|
2014-04-15 19:08:43 +01:00
|
|
|
transition restarting: :failed
|
2014-04-14 22:32:25 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-15 20:15:52 +01:00
|
|
|
def perform_restart
|
2014-04-17 20:08:22 +01:00
|
|
|
restart_failed if NodeInstruction.all_locked?
|
|
|
|
|
2014-04-15 20:15:52 +01:00
|
|
|
success = false
|
2014-04-17 22:55:37 +01:00
|
|
|
stdout = ''
|
2014-04-15 20:15:52 +01:00
|
|
|
instruction.lines.each do |command|
|
|
|
|
next if command.blank?
|
|
|
|
command.chomp!; command.strip!
|
2014-04-17 22:55:37 +01:00
|
|
|
stdout << %x[ #{command} 2>&1 ]
|
2014-04-15 20:15:52 +01:00
|
|
|
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
|
|
|
|
|
2014-04-17 22:55:37 +01:00
|
|
|
update_column(:output, stdout)
|
2014-04-15 22:26:12 +01:00
|
|
|
success ? ready : restart_failed
|
2014-04-15 20:15:52 +01:00
|
|
|
end
|
|
|
|
later :perform_restart, queue: :low
|
|
|
|
|
2014-04-17 20:08:22 +01:00
|
|
|
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
|
|
|
|
|
2014-04-14 22:32:25 +01:00
|
|
|
end
|