cschritt/dockerdns

View on GitHub
lib/dockerdns.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'docker'
require 'dnsruby'

class DockerDNS

  #==========================================================================
  def self.run!(config)
    DockerDNS.new(config).run!
  end
  #==========================================================================

  def initialize(config)
    @config = config
  end

  def domain
      @config["domain"]
  end

  def reversezone
      @config["reversezone"]
  end

  def resolver
    @resolver ||= Dnsruby::Resolver.new(@config['dnsserver'])
  end

  def ttl
    @config["ttl"]
  end

  def docker_url
    @config["dockerurl"] || '/var/run/docker.sock'
  end

  def run!
      Docker.url = docker_url
      Docker.options[:read_timeout] = 5
    begin
          Docker::Event.stream do |event|
            case event.status
        when "create"
                next
            when "start"
                puts "caught event #{event.status} for container id #{event.id}"
                create_or_update_dns_records!(event.id)
            when "die", "kill", "stop", "destroy"
                puts "caught event #{event.status} for container id #{event.id}"
                delete_dns_records!(event.id)
            else
                puts "Ignoring Docker Event #{event.status}"
            end
          end
      rescue Docker::Error::TimeoutError, Excon::Errors::SocketError
          retry
      rescue StandardError => e
          puts "Error while streaming events: #{e}"
      end
  end

  def container_ip(id)
    Docker::Container.get(id).json["NetworkSettings"]["IPAddress"]
  end

  def container_name(id)
    Docker::Container.get(id).json["Config"]["Hostname"]
  end

  def a_record(fqdn)
    resolver.query(fqdn, 'A').answer.first.address.to_s
  end

  def ptr_record(ipAddress)
    resolver.query(ipAddress, 'PTR').answer.first.domainname.to_s
  end

  def set_a_record(ipAddress, hostname)
    record = "#{hostname}.#{domain}"
    puts "setting a-record #{record}"
    update = Dnsruby::Update.new(domain)
    # add record
      puts "update.add(#{record}, 'A', #{ttl}, #{ipAddress})"
    update.absent(record)
    update.add(record, 'A', ttl, ipAddress)
    # send update
    begin
      resolver.send_message(update)
      puts "Successfully added #{record}"
    rescue Dnsruby::YXRRSet, Dnsruby::YXDomain
      puts "#{record} already present, deleting!"
      delete_a_record(ipAddress, hostname)
      retry
    rescue Exception => e
      puts "Update failed: #{e}"
    end
  end

  def delete_a_record(ipAddress, hostname)
    record = "#{hostname}.#{domain}"
    puts "deleting a-record #{record}"
      update = Dnsruby::Update.new(domain)
      # delete record
      puts "update.delete(#{record})"
    update.delete(record)
    # send update
    begin
      resolver.send_message(update)
      puts "Successfully deleted #{record}"
    rescue Exception => e
      puts "Update failed: #{e}"
    end
  end

  def set_ptr_record(ipAddress, hostname)
    record = "#{IPAddr.new(ipAddress).reverse}"
    fqdn = "#{hostname}.#{domain}"
    puts "setting ptr-record #{record}"
    update = Dnsruby::Update.new(reversezone)
    # add record
      puts "update.add(#{record}, 'PTR', #{ttl}, #{fqdn})"
    update.absent(record)
    update.add(record, 'PTR', ttl, fqdn)
    # send update
    begin
      resolver.send_message(update)
      puts "Successfully added #{record}"
    rescue Dnsruby::YXRRSet, Dnsruby::YXDomain
      puts "#{record} already present, deleting!"
      delete_ptr_record(ipAddress, hostname)
      retry
    rescue Exception => e
      puts "Update failed: #{e}"
    end
  end

  def delete_ptr_record(ipAddress, hostname)
      record = "#{IPAddr.new(ipAddress).reverse}"
    puts "deleting ptr-record #{record}"
    update = Dnsruby::Update.new(reversezone)
    # delete record
      puts "update.delete(#{record})"
    update.delete(record)
    # send update
    begin
      resolver.send_message(update)
      puts "Successfully deleted #{record}"
    rescue Exception => e
      puts "Update failed: #{e}"
    end
  end

  def create_or_update_dns_records!(id)
    hostname = container_name(id)
    ipAddress = container_ip(id)
    set_a_record(ipAddress, hostname)
    set_ptr_record(ipAddress, hostname)
  end


  def delete_dns_records!(id)
    hostname = container_name(id)
    ipAddress = a_record("#{hostname}.#{domain}")
    delete_a_record(ipAddress, hostname)
      delete_ptr_record(ipAddress, hostname)
  end
end