#!/usr/bin/env ruby
require 'rubygems'
require 'net/https'
require 'builder'
require 'rexml/document'
require 'idn'
require 'erb'
require 'resolv'
SECONDARY_DNS_HOSTNAME = 'ns2.example.net'
ADMINISTRATOR_EMAIL = 'support@example.com'
BIND_ZONE_PATH = '/usr/local/var/named'
BIND_SLAVE_CONFIG_PATH = '/usr/local/etc/named/named.slave.conf'
class PleskAgent
CONFIG = {:hostname => 'plesk.example.com', :port => 8443, :username => 'admin', :password => 'secret'}
ROOTCA = '/etc/ssl/certs/ca-certificates.crt'
PROTOCOL_VERSION = '1.6.0.1'
attr_reader :username, :password, :http
def self.dns_records
begin
data = self.request do |xml|
xml.dns do
xml.get_rec do
xml.filter do
end
end
end
end
rescue Exception => e
PleskAgent.log_message e, :err
end
end
def initialize
@username = CONFIG[:username]
@password = CONFIG[:password]
@http = Net::HTTP.new(CONFIG[:hostname], CONFIG[:port])
@http.use_ssl = true
if File.exists?(ROOTCA)
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
@http.ca_file = ROOTCA
else
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
end
def send(request_xml)
request = request_xml.target!
request_headers= {'Content-Type' => 'text/xml; charset=utf-8', 'HTTP_AUTH_LOGIN' => @username, 'HTTP_AUTH_PASSWD' => @password}
PleskAgent.log_message "Establishing connection with #{CONFIG[:hostname]}"
response = http.request_post('/enterprise/control/agent.php', request, request_headers)
PleskAgent.log_message 'Processing response'
response_xml = REXML::Document.new(response.body)
status = response_xml.root.get_text('//status[1]')
if status == 'ok'
PleskAgent.log_message 'OK'
response_xml.root
else
error_message = response_xml.root.get_text('//errtext[1]')
error_code = response_xml.root.get_text('//errcode[1]')
PleskAgent.log_message "#{error_message} (#{error_code})"
false
end
end
def self.request
rpc = self.new
xml = Builder::XmlMarkup.new
xml.instruct! :xml, :version => '1.0'
xml.packet :version => PROTOCOL_VERSION do
yield xml if block_given?
end
rpc.send xml
end
private
def self.log_message(message)
`logger -i -t PleskAgent "#{message}"`
end
end
template = ERB.new <<-"EOF"
zone "<%= @zone %>" IN {
type slave;
file "#{BIND_ZONE_PATH}/<%= @zone %>.db";
masters {#{Resolv.getaddress(PleskAgent::CONFIG[:hostname])};};
};
EOF
zones = "# Created at #{Time.now.utc}\r\n"
begin
PleskAgent.dns_records.elements.collect('//result/data') do |record|
if record.get_text('type') == 'NS' and record.get_text('value') == "#{SECONDARY_DNS_HOSTNAME}."
@zone = IDN::Idna.toASCII(record.get_text('host').to_s.chop)
zones << template.result(binding)
end
end
PleskAgent.log_message 'Writing zones to file'
`mv "#{BIND_SLAVE_CONFIG_PATH}" #{BIND_SLAVE_CONFIG_PATH}~`
File.open(BIND_SLAVE_CONFIG_PATH, 'w') {|f| f.write(zones)}
PleskAgent.log_message 'Done. Reloading Nameserver.'
`rndc reload`
rescue Exception => e
PleskAgent.log_message "#{e}. Restoring previous configuration and notifying administrator"
`mv "#{BIND_SLAVE_CONFIG_PATH}~" #{BIND_SLAVE_CONFIG_PATH}`
`echo "#{e}" | mail -s "Retrieval of zones for #{SECONDARY_DNS_HOSTNAME} failed" #{ADMINISTRATOR_EMAIL}`
end