GitList
Repositories
Help
Report an Issue
rcm
Code
Commits
Branches
Tags
Search
Tree:
97a2c49
Branches
Tags
master
rcm
task.rb
Converging the state as defined by config.
Dev
commited
97a2c49
at 2018-06-16 23:34:21
task.rb
Blame
History
Raw
#!/usr/bin/ruby require_relative 'objects/rcm_file' require_relative 'objects/rcm_package' require_relative 'objects/rcm_service' require_relative 'managers/rcm_package_manager' require_relative 'managers/rcm_file_manager' require_relative 'managers/rcm_service_manager' require_relative 'rcm_utils' require 'yaml' require 'logger' module RCM PACKAGES = 'packages'.freeze FILES = 'files'.freeze SERVICES = 'services'.freeze VALID_LOG_LEVELS = %w(fatal error info debug).freeze RCM_ENV = ENV.fetch('ENVIRONMENT', '') @@wanted = { PACKAGES => {}, FILES => {}, SERVICES => {} } @@got = { PACKAGES => {}, FILES => {}, SERVICES => {} } @@crackalackin = { PACKAGES => [], FILES => [], SERVICES => [] } @@logger = ::Logger.new(STDOUT) @@pkg_mgr = ::RCM::Apt.new(@@logger) @@file_mgr = ::RCM::FileManager.new(@@logger) @@svc_mgr = ::RCM::ServiceManager.new(@@logger) def self.configure_logger # Can be exposed as settings but was expanding the scope as this # object will need to be passed to all other objects @@logger.level = ::Logger::DEBUG @@logger.progname = 'rcm' end def self.parse_packages(markup) @@logger.info("Environment = #{RCM_ENV}") @@pkg_mgr.update unless RCM_ENV == 'dev' 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? 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 self.parse_files(markup) markup.each do |d| raise "\n\n'#{d['local_file']}' is not readable.\n\n" unless ::File.readable?(d['local_file']) f = RCM::File.new(d['path'], d['owner'], d['group'], d['mode'], d['local_file']) @@wanted[FILES][d['path']] = f end end def self.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 def self.whachuwant # or parse_config # Consume config from YAML, and convert it to usable objects in @@wanted. config_file = RCM_ENV.empty? ? 'config.yaml' : "config_#{RCM_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 PACKAGES parse_packages(resource_definition) when FILES parse_files(resource_definition) when SERVICES parse_services(resource_definition) end end end end def self.whachugot # or get_current_state @@got[PACKAGES] = @@pkg_mgr.get_current_state(@@wanted[PACKAGES]) @@got[FILES] = @@file_mgr.get_current_state(@@wanted[FILES]) # @@got[SERVICES] = @@svc_mgr.get_current_state(@@wanted[SERVICES]) end def self.converge_packages @@wanted[PACKAGES].each do |pkg_name, pkg_obj| current_pkg = @@got[PACKAGES][pkg_name] if current_pkg == pkg_obj @@logger.info("#{pkg_name} is in expected state.") next end @@logger.debug('Missing package:' + pkg_name) if current_pkg.version != pkg_obj.version && current_pkg.state == ::RCM::Package::INSTALLED # Wrong version is installed. Remove current version and install the correct one. # Not the best way to go about it... but we are not implementing a legit solution. @logger.debug("#{current_pkg.name}=#{current_pkg.version} is installed. Uninstalling first.") @@pkg_mgr.remove(pkg_obj) @@pkg_mgr.install(pkg_obj) elsif current_pkg.state == ::RCM::Package::REMOVED @@pkg_mgr.install(pkg_obj) end end end def self.converge_files @@wanted[FILES].each do |path, file_obj| file_on_fs = @@got[FILES][path] if file_on_fs == file_obj @@logger.info("#{path} is in expected state.") next end # try to do minimal changes by finding what is different if file_on_fs.path.empty? # for files, we're not doing explicit state maintenance like we are doing for packages # If file is on disk, file obj will contain the path. @@logger.info("#{path} is not present on disk.") @@file_mgr.copy(file_obj) @@file_mgr.apply_attributes(file_obj) elsif file_on_fs.mode != file_obj.mode || file_on_fs.owner != file_obj.owner || file_on_fs.group != file_obj.group @@logger.debug("Attributes on #{path} are not in expected state.") @@file_mgr.apply_attributes(file_obj) elsif !::File.cmp(file_obj.src_path, path) @@logger.debug("File contents don't match, even though #{path} is on disk.") @@file_mgr.remove(file_obj) @@file_mgr.copy(file_obj) @@file_mgr.apply_attributes(file_obj) end # Set the version correctly @@crackalackin[FILES].push(file_obj) end end def self.restart_services_if_needed @@wanted[SERVICES].values.each do |svc_obj| @@svc_manager.restart(svc_obj) if @@svc_mgr.dependencies_changed?(svc_obj) end end def main configure_logger whachuwant whachugot converge_packages converge_files restart_services_if_needed end module_function :main end RCM.main