root/lib/cyborghood/base/config.rb @ d9ef7de9
d32ee48a | Marc Dequenes | #--
|
|
# CyborgHood, a distributed system management software.
|
|||
e7315259 | Marc Dequènes (Duck) | # Copyright (c) 2009-2010 Marc Dequènes (Duck) <Duck@DuckCorp.org>
|
|
d32ee48a | Marc Dequenes | #
|
|
# This program is free software: you can redistribute it and/or modify
|
|||
# it under the terms of the GNU General Public License as published by
|
|||
# the Free Software Foundation, either version 3 of the License, or
|
|||
# (at your option) any later version.
|
|||
#
|
|||
# This program is distributed in the hope that it will be useful,
|
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
# GNU General Public License for more details.
|
|||
#
|
|||
# You should have received a copy of the GNU General Public License
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#++
|
|||
d31869c4 | Marc Dequenes | require 'singleton'
|
|
fd5bab1c | Marc Dequènes (Duck) | require 'cyborghood/base/config_setup'
|
|
2f1c6b5b | Marc Dequènes (Duck) | require 'yaml'
|
|
require 'kwalify'
|
|||
d31869c4 | Marc Dequenes | ||
module CyborgHood
|
|||
class Config
|
|||
include Singleton
|
|||
CONFFILE_GLOBAL = "cyborghood.conf"
|
|||
CONFFILE_BOT = "cyborghood_%s.conf"
|
|||
def self.load(name = nil)
|
|||
# load all config parts
|
|||
2f1c6b5b | Marc Dequènes (Duck) | g_config_raw = load_config_raw()
|
|
g_def = parse('config', 'global', g_config_raw)
|
|||
g_default_config = load_default_config()
|
|||
config = merge_into_default_config(g_default_config, g_def)
|
|||
b28fbd1e | Marc Dequenes | unless name.nil?
|
|
2f1c6b5b | Marc Dequènes (Duck) | config_spc_raw = load_config_raw(name)
|
|
083d3024 | Marc Dequènes (Duck) | spc_def = parse('config', name, config_spc_raw) || {}
|
|
2f1c6b5b | Marc Dequènes (Duck) | default_config_spc = load_default_config(name)
|
|
spc_config = merge_into_default_config(default_config_spc, spc_def)
|
|||
config = merge_into_default_config(config, spc_config)
|
|||
b28fbd1e | Marc Dequenes | end
|
|
d31869c4 | Marc Dequenes | ||
ecdabe95 | Marc Dequènes (Duck) | config['bot_name'] = name
|
|
d31869c4 | Marc Dequenes | # create config object for easier access
|
|
@@config = config.to_ostruct.freeze
|
|||
end
|
|||
def method_missing(sym, *args, &block)
|
|||
begin
|
|||
@@config.send sym, *args, &block
|
|||
rescue
|
|||
nil
|
|||
end
|
|||
end
|
|||
748bfcf3 | Marc Dequènes (Duck) | protected
|
|
def self.merge_into_default_config(conf_default, conf)
|
|||
2f1c6b5b | Marc Dequènes (Duck) | new_conf = conf_default.dup
|
|
conf.each_pair do |k, v|
|
|||
if conf_default.has_key?(k) and conf_default[k].is_a?(Hash) and v.is_a?(Hash)
|
|||
new_conf[k] = merge_into_default_config(conf_default[k], v)
|
|||
elsif conf_default.has_key?(k) and conf_default[k].is_a?(Hash) and v.nil?
|
|||
new_conf[k] = conf_default[k]
|
|||
else
|
|||
new_conf[k] = v
|
|||
end
|
|||
end
|
|||
return new_conf
|
|||
end
|
|||
d31869c4 | Marc Dequenes | ||
2f1c6b5b | Marc Dequènes (Duck) | def self.load_config_raw(name = nil)
|
|
d31869c4 | Marc Dequenes | begin
|
|
if name.nil?
|
|||
filename = CONFFILE_GLOBAL
|
|||
else
|
|||
ecdabe95 | Marc Dequènes (Duck) | filename = CONFFILE_BOT % name.downcase
|
|
d31869c4 | Marc Dequenes | end
|
|
filepath = File.join(File.expand_path(CFG_DIR), filename)
|
|||
2f1c6b5b | Marc Dequènes (Duck) | File.read(filepath)
|
|
d31869c4 | Marc Dequenes | rescue
|
|
logger.fatal "Problems fetching configuration file '" + filepath + "': " + $!
|
|||
exit 1
|
|||
end
|
|||
end
|
|||
2f1c6b5b | Marc Dequènes (Duck) | def self.parse(def_name, type, def_data_raw, validate = true, extra_data = nil)
|
|
schema = load_schema(type)
|
|||
if validate
|
|||
validator_klass = case type
|
|||
when 'global'
|
|||
GlobalValidator
|
|||
d31869c4 | Marc Dequenes | else
|
|
ecdabe95 | Marc Dequènes (Duck) | klass_name = type + "Validator"
|
|
2f1c6b5b | Marc Dequènes (Duck) | if self.const_defined? klass_name
|
|
self.const_get klass_name
|
|||
else
|
|||
CyborgHoodValidator
|
|||
end
|
|||
d31869c4 | Marc Dequenes | end
|
|
2f1c6b5b | Marc Dequènes (Duck) | validator = validator_klass.new(schema)
|
|
validator.extra_data = extra_data
|
|||
else
|
|||
validator = nil
|
|||
end
|
|||
# validate config with schema
|
|||
parser = Kwalify::Yaml::Parser.new(validator)
|
|||
def_data = parser.parse(def_data_raw, :filename => def_name, :untabify => true)
|
|||
ecdabe95 | Marc Dequènes (Duck) | raise_if_validation_errors("#{type} '#{def_name}'", parser.errors)
|
|
2f1c6b5b | Marc Dequènes (Duck) | ||
def_data
|
|||
rescue
|
|||
logger.fatal "Problems parsing %s file for '%s': %s" % [def_name, type, $!]
|
|||
exit 1
|
|||
end
|
|||
def self.load_default_config(type = "global")
|
|||
ecdabe95 | Marc Dequènes (Duck) | filename = File.join(DATA_DIR, "default_config", type.downcase + ".yaml")
|
|
2f1c6b5b | Marc Dequènes (Duck) | default_config_raw = File.read(filename)
|
|
default_config = parse(':defaults:', type, default_config_raw, false)
|
|||
083d3024 | Marc Dequènes (Duck) | default_config || {}
|
|
2f1c6b5b | Marc Dequènes (Duck) | rescue
|
|
logger.fatal "Could not load default config for '%s': %s" % [type, $!]
|
|||
exit 1
|
|||
end
|
|||
def self.load_schema(type = "global")
|
|||
ecdabe95 | Marc Dequènes (Duck) | schema_file = File.join(DATA_DIR, "schema", type.downcase + ".yaml")
|
|
2f1c6b5b | Marc Dequènes (Duck) | schema = YAML.load_file(schema_file)
|
|
# validate schema
|
|||
metavalidator = Kwalify::MetaValidator.instance
|
|||
errors = metavalidator.validate(schema)
|
|||
raise_if_validation_errors("'#{type}' schema", errors)
|
|||
schema
|
|||
rescue
|
|||
logger.fatal "Could not load schema for '%s': %s" % [type, $!]
|
|||
exit 1
|
|||
end
|
|||
protected
|
|||
class CyborgHoodValidator < Kwalify::Validator
|
|||
attr_accessor :extra_data
|
|||
## hook method called by Validator#validate()
|
|||
def validate_hook(value, rule, path, errors)
|
|||
msg_list = []
|
|||
validate_hook_in(value, rule, path, msg_list)
|
|||
msg_list.each do |msg|
|
|||
errors << Kwalify::ValidationError.new(msg, path)
|
|||
end
|
|||
end
|
|||
def validate_hook_in(value, rule, path, msg_list)
|
|||
end
|
|||
end
|
|||
class GlobalValidator < CyborgHoodValidator
|
|||
def validate_hook_in(value, rule, path, msg_list)
|
|||
case rule.name
|
|||
when 'LogPath'
|
|||
unless File.directory? value
|
|||
msg_list << "Log path must be an existing directory"
|
|||
end
|
|||
end
|
|||
end
|
|||
end
|
|||
def self.raise_if_validation_errors(name, errors)
|
|||
if errors and not errors.empty?
|
|||
err_msg = []
|
|||
for e in errors
|
|||
err_msg << "[#{e.path}] #{e.message}"
|
|||
end
|
|||
logger.fatal "%s is not valid:\n%s" % [name, err_msg.join("\n")]
|
|||
exit 1
|
|||
d31869c4 | Marc Dequenes | end
|
|
end
|
|||
end
|
|||
end
|