module RCM class ConfigManager PACKAGES = 'packages'.freeze FILES = 'files'.freeze SERVICES = 'services'.freeze LOGGING = 'logging'.freeze @wanted = nil @logger = nil @env = '' VALID_LOG_LEVELS = %w[fatal error info debug].freeze def initialize() @env = ENV.fetch('ENVIRONMENT', '') @wanted = { PACKAGES => {}, FILES => {}, SERVICES => {} } config_file = @env.empty? ? 'config.yaml' : "config_#{@env}.yaml" raise "#{config_file} not found." unless ::File.readable?(config_file) config = YAML.load_file(config_file) config.each do |yaml_objects| yaml_objects.each do |collection, resource_definition| case collection when LOGGING configure_logging(resource_definition) when PACKAGES parse_packages(resource_definition) when FILES parse_files(resource_definition) when SERVICES parse_services(resource_definition) end # of case end # of iterating over yaml_objects end # of iterating over config end def logger @logger end def packages @wanted[PACKAGES] end def files @wanted[FILES] end def services @wanted[SERVICES] end def configure_logging(markup) file = markup[0]['file'] device = '' level = markup[0]['level'] if (VALID_LOG_LEVELS & [level]).empty? raise "Invalid log level '#{level}'. Valid log levels are: #{VALID_LOG_LEVELS.join(', ')}" end case file when 'STDOUT' device = STDOUT when 'STDERR' device = STDERR else # treat whatever is written as file device = ::File.open(file, 'a+') end @logger = ::Logger.new(device) @logger.level = level @logger.progname = 'rcm' @logger end def parse_packages(markup) @logger.info("Environment = #{@env}") markup.each do |d| # ensure package version exists, if mentioned. version = d.fetch('version', '') desired_state = d.fetch('desired_state', ::RCM::Package::INSTALLED) valid_package_states = [::RCM::Package::INSTALLED, ::RCM::Package::REMOVED] if (valid_package_states & [desired_state]).empty? raise "Unknown desired_state: #{desired_state}. Valid states: #{valid_package_states.join(', ')}" end unless version.empty? # Convenience... check if the version mentioned in config is correct. pkg_mgr = ::RCM::Apt.new(@logger) available_versions = pkg_mgr.get_versions(d['name']) if (available_versions & [version]).empty? raise "\n\n#{d['name']} = #{version} is not available.\nAvailable versions: #{available_versions.join(', ')}" end end p = RCM::Package.new(d['name'], version, desired_state) @wanted[PACKAGES][d['name']] = p end end def parse_files(markup) valid_file_states = [::RCM::File::PRESENT, ::RCM::File::ABSENT] markup.each do |d| raise "\n\nFile state can only be one of #{valid_file_states.join(', ')}" if (valid_file_states | [d['desired_state']]).empty? raise "\n\n'#{d['local_file']}' is not readable.\n\n" if d['desired_state'] == ::RCM::File::PRESENT && !::File.readable?(d['local_file']) f = RCM::File.new(d['path'], d['owner'], d['group'], d['mode'], d['local_file'], d['desired_state']) @wanted[FILES][d['path']] = f end end def parse_services(markup) pkgs = @wanted[PACKAGES] files = @wanted[FILES] file_dependencies = {} package_dependencies = {} markup.each do |d| dependencies = d.fetch('dependencies', {}) dependencies.each do |values| values.each do |dep_type, dep| case dep_type when PACKAGES dep.each do |pkg_definition| pkg_name = pkg_definition['name'] raise "\n\nPlease ensure #{pkg_name} is managed by this program before adding it as a dependency.\n\n" unless pkgs.key?(pkg_name) p = pkgs[pkg_name] package_dependencies[pkg_name] = p end when FILES dep.each do |file_defnition| path = file_defnition['path'] raise "\n\nPlease ensure #{path} is managed by this program before adding it as a dependency.\n\n" unless files.key?(path) f = files[path] file_dependencies[path] = f end end end end s = RCM::Service.new(d['name'], file_dependencies, package_dependencies) @wanted[SERVICES][d['name']] = s end end end # of class ConfigManager end # module