# Duration to wait before taken modification into account (in minutes). duration = 5 if ARGV.size != 2 puts "usage: #{PROGRAM_NAME} dnsmanagerd-bind9-dir powerdns-bind9-dir" exit 0 end class BrainlessLog class_property last_text_size : Int32 = 0 # In case the lastly `unimportant` written string is to be kept on-screen. def self.important(str : String) unimportant "" # Clear the line and last_text_size = 0 STDOUT.puts str end # Log something that isn't important, meaning text that will be # rewritten in-place since we don't really want to read it. # WARNING: user may want to keep the lastly written string, `keep` it. def self.unimportant(str : String) STDOUT.write ("\r" + (" " * self.last_text_size)).to_slice # Clear the line. self.last_text_size = str.size STDOUT.write ("\r" + str).to_slice end # In case the last `unimportant` string is to be kept on-screen. def self.keep STDOUT.puts "" unless self.last_text_size == 0 end # In case the last `unimportant` string should be removed. def self.flush unimportant "" if self.last_text_size > 0 end end class Context class_property dnsmanagerd_dir : String = "" class_property powerdns_dir : String = "" end def copy_domain_files(domain : String) : Nil src = "#{Context.dnsmanagerd_dir}/#{domain}" dest = "#{Context.powerdns_dir}/#{domain}" BrainlessLog.important "copying #{src} -> #{dest}" i = File.info src File.copy src, dest rescue e : File::AccessDeniedError BrainlessLog.important "You don't have enough rights: #{e}" rescue e : File::Error BrainlessLog.important "File error: #{e}" end def run_process(cmd : String, params : Array(String), env : Hash(String, String)) : Nil unless Process.run(cmd, params, env, true # clear environment # input: Process::Redirect::Inherit, # output: Process::Redirect::Inherit, # error: Process::Redirect::Inherit ).success? puts "cannot run #{cmd} #{params.join(' ')}" end end def pdns_reload(domain : String) : Nil BrainlessLog.important "reloading a domain: pdns_control bind-reload-now #{domain}" run_process("pdns_control", [ "bind-reload-now", domain ], { "HOME" => "/" }) end def update_domain(domain : String) : Nil BrainlessLog.important "domain to reload: #{domain}" copy_domain_files domain pdns_reload domain end def pdns_add(domain : String) : Nil BrainlessLog.important "adding a new domain: pdns_control bind-add-zone #{Context.powerdns_dir}/#{domain}" run_process("pdns_control", [ "bind-add-zone", domain, "#{Context.powerdns_dir}/#{domain}" ], { "HOME" => "/" }) end def add_domain(domain : String) : Nil BrainlessLog.important "domain to add: #{domain}" copy_domain_files domain pdns_add domain end def delete_file(path : String) File.delete path rescue e : File::AccessDeniedError BrainlessLog.important "You don't have enough rights: #{e}" end def del_domain(domain : String) : Nil BrainlessLog.important "domain to delete: #{domain}" delete_file "#{Context.powerdns_dir}/#{domain}" # TODO: pdns_control ??? end Context.dnsmanagerd_dir = ARGV[0] Context.powerdns_dir = ARGV[1] dnsmanagerd_dir_content = Dir.children(Context.dnsmanagerd_dir).select { |d| ! d.ends_with? ".wip" } powerdns_dir_content = Dir.children(Context.powerdns_dir) both = dnsmanagerd_dir_content & powerdns_dir_content both.each do |d| i1 = File.info "#{Context.dnsmanagerd_dir}/#{d}" i2 = File.info "#{Context.powerdns_dir}/#{d}" if i1.modification_time > i2.modification_time # Wait for a few minutes before changing anything, to avoid useless reloads. if Time.local > i1.modification_time.shift minutes: duration BrainlessLog.important "#{d}: updating" update_domain d else BrainlessLog.unimportant "#{d}: has been modified less than #{duration} minute ago, do not update yet" end else BrainlessLog.unimportant "#{d}: hasn't been modified" end end BrainlessLog.flush to_add = dnsmanagerd_dir_content - powerdns_dir_content to_add.each { |d| add_domain d } to_delete = powerdns_dir_content - dnsmanagerd_dir_content to_delete.each { |d| del_domain d }