hawk/app/models/resource.rb
# Copyright (c) 2009-2015 Tim Serong <tserong@suse.com>
# See COPYING for license.
class Resource < Record
class CommandError < StandardError
end
attribute :object_type, Symbol
attribute :sort_type, String
attribute :state, Symbol
attribute :ops, Hash
attribute :params, Hash
attribute :meta, Hash
attribute :utilization, Hash
attribute :running_on, Array
attribute :failed_ops, Array
validate do |record|
# to validate a new record:
# try making the shell form and running verify;commit in a temporary shadow cib in crm
# if it fails, report errors
if record.errors.blank? && record.new_record && current_cib.live?
cli = record.shell_syntax
_out, err, rc = Invoker.instance.no_log do |i|
i.crm_configure ['cib new', cli, 'verify', 'commit'].join("\n")
end
err.lines.each do |l|
if l.start_with? "ERROR:"
record.errors.add :base, l[7..-1]
break
end
end if rc != 0
end
end
def object_type
self.class.to_s.downcase
end
def sort_type
if @xml.name == 'primitive'
agent_name
else
@xml.name
end
end
def editable?
return false if @xml.name == 'bundle'
true
end
def state
cib_by_id(id)[:state] || :unknown
end
def ops
@ops ||= {}
end
def params
@params ||= {}
end
def meta
@meta ||= {}
end
def utilization
@utilization ||= {}
end
def running_on
rsc_is_running_on cib_by_id(id)
end
def failed_ops
rsc_failed_ops cib_by_id(id)
end
def start!
Invoker.instance.no_log { |i| i.crm("-F", "resource", "start", id) }
end
def stop!
Invoker.instance.no_log { |i| i.crm("-F", "resource", "stop", id) }
end
def promote!
Invoker.instance.no_log { |i| i.crm("-F", "resource", "promote", id) }
end
def demote!
Invoker.instance.no_log { |i| i.crm("-F", "resource", "demote", id) }
end
def maintenance!(on)
Invoker.instance.no_log { |i| i.crm("-F", "resource", "maintenance", id, on) }
end
def unmigrate!
Invoker.instance.no_log { |i| i.crm("-F", "resource", "clear", id) }
end
def migrate!(node = nil)
Invoker.instance.no_log { |i| i.crm("-F", "resource", "migrate", id, node.to_s) }
end
def cleanup!(node = nil)
Invoker.instance.no_log { |i| i.crm("-F", "resource", "cleanup", id, node.to_s) }
end
class << self
def all
super(true)
end
def find(id, attr = 'id')
rsc = super(id, attr)
return rsc if rsc.is_a? Resource
raise Cib::RecordNotFound, _("Not a resource")
end
def cib_type_fetch
"configuration//*[self::resources]/*"
end
def help_text
super.merge(
id: {
type: "string",
shortdesc: _("Resource ID"),
longdesc: _("Unique identifier for the resource. May not contain spaces."),
default: ""
}
)
end
end
def unique_id!(other)
m = /(.*)-(\d+)/.match(other)
other = m[1] if m
i = 1
i = m[2].to_i + 1 if m
i += 1 while current_cib.resources_by_id.key?("#{other}-#{i}")
@id = "#{other}-#{i}"
end
def rsc_constraints
outp = Util.safe_x('/usr/sbin/crm_resource', '--resource', "#{id}", '-A', '2>/dev/null')
info = {}
outp.each_line do |l|
l.strip!
next if l.blank? || l.start_with?('* ')
m = l.match(/\s*: Node (\S+)\s+\(score=([^,]+), id=([^)]+)\)/)
if m && !info.key?(m[3])
info[m[3]] = { id: m[3], type: :location, score: m[2], other: m[1] }
else
m = l.match(/\s*(\S+)\s+\(score=([^,]+), id=([^)]+)\)/)
if m && !info.key?(m[3])
info[m[3]] = { id: m[3], type: :colocation, score: m[2], other: m[1] }
end
end
end
info.values
end
protected
def cib_by_id(id)
current_cib.resources_by_id[id] || {}
end
def rsc_is_running_on(rsc)
{}.tap do |lst|
if rsc.key? :children
rsc[:children].each do |c|
lst.merge! rsc_is_running_on(c)
end
end
if rsc.key? :instances
rsc[:instances].each do |name, info|
[:master, :slave, :started, :pending].each do |rstate|
if info[rstate]
info[rstate].each do |n|
lst[n[:node]] = rstate
end
end
end
end
end
end
end
def rsc_failed_ops(rsc)
[].tap do |lst|
if rsc.key? :children
rsc[:children].each do |c|
lst.concat rsc_failed_ops(c)
end
end
if rsc.key? :instances
rsc[:instances].each do |_name, info|
lst.concat(info[:failed_ops]) if info.key? :failed_ops
end
end
end
end
end