Project

General

Profile

« Previous | Next » 

Revision d3509e63

Added by Lukas Zapletal over 10 years ago

fixes #3943 - add simple virsh providers for libvirt DNS/DHCP

View differences:

config/settings.yml.example
# valid providers:
# nsupdate
# nsupdate_gss (for GSS-TSIG support)
# virsh (simple implementation for libvirt)
:dns_provider: nsupdate
#:dns_key: /etc/rndc.key
# use this setting if you are managing a dns server which is not localhost though this proxy
......
# Enable DHCP management
:dhcp: false
# The vendor can be either isc or native_ms
# valid vendors:
# - isc
# - native_ms (Microsoft native implementation)
# - virsh (simple implementation for libvirt)
:dhcp_vendor: isc
# dhcp_subnets is a Native MS implementation setting. It restricts the subnets queried to a
# subset, so as to reduce the query time.
......
#:dhcp_key_name: secret_key_name
#:dhcp_key_secret: secret_key
# shared options for virsh DNS/DHCP provider
:virsh_network: default
# enable PuppetCA management
:puppetca: false
#:ssldir: /var/lib/puppet/ssl
lib/dhcp_api.rb
when "native_ms"
require 'proxy/dhcp/server/native_ms'
@server = Proxy::DHCP::NativeMS.new(:server => SETTINGS.dhcp_server ? SETTINGS.dhcp_server : "127.0.0.1")
when "virsh"
require 'proxy/dhcp/server/virsh'
@server = Proxy::DHCP::Virsh.new(:virsh_network => SETTINGS.virsh_network)
else
log_halt 400, "Unrecognized or missing DHCP vendor type: #{SETTINGS.dhcp_vendor.nil? ? "MISSING" : SETTINGS.dhcp_vendor}"
end
lib/dns_api.rb
:tsig_keytab => SETTINGS.dns_tsig_keytab,
:tsig_principal => SETTINGS.dns_tsig_principal
))
when "virsh"
require 'proxy/dns/virsh'
@server = Proxy::DNS::Virsh.new(opts.merge(
:virsh_network => SETTINGS.virsh_network
))
else
log_halt 400, "Unrecognized or missing DNS provider: #{SETTINGS.dns_provider || "MISSING"}"
end
lib/proxy/dhcp/server/virsh.rb
require 'proxy/virsh'
require 'ipaddr'
module Proxy::DHCP
class Virsh < Server
include Proxy::Virsh
def initialize options
@network = options[:virsh_network]
raise "DNS virsh provider needs 'virsh_network' option" unless network
super(options)
end
# we support only one subnet
def loadSubnets
super
begin
doc = REXML::Document.new xml = dump_xml
doc.elements.each("network/ip") do |e|
next if e.attributes["family"] == "ipv6"
netmask = e.attributes["netmask"]
gateway = e.attributes["address"]
network = IPAddr.new(gateway).mask(netmask).to_s
subnet = Proxy::DHCP::Subnet.new(self, network, netmask)
end
rescue Exception => e
msg = "DHCP virsh provider error: unable to retrive virsh info: #{e}"
logger.error msg
logger.debug xml if defined?(xml)
raise Proxy::DHCP::Error, msg
end
end
def loadSubnetData subnet
super(subnet)
begin
doc = REXML::Document.new xml = dump_xml
REXML::XPath.each(doc, "//network/ip[not(@family) or @family='ipv4']/dhcp/host") do |e|
Proxy::DHCP::Record.new(:subnet => subnet,
:ip => e.attributes["ip"],
:mac => e.attributes["mac"])
end
rescue Exception => e
msg = "DHCP virsh provider error: unable to retrive virsh info: #{e}"
logger.error msg
logger.debug xml if defined?(xml)
raise Proxy::DHCP::Error, msg
end
end
def addRecord options={}
record = super(options)
virsh_update_dhcp 'add-last', record.mac, record.ip
record
end
def delRecord subnet, record
super(subnet, record)
virsh_update_dhcp 'delete', record.mac, record.ip
end
end
end
lib/proxy/dns/virsh.rb
require "proxy/dns"
require "proxy/virsh"
module Proxy::DNS
class Virsh < Record
include Proxy::Log
include Proxy::Util
include Proxy::Virsh
def initialize options = {}
@network = options[:virsh_network]
raise "DNS virsh provider needs 'virsh_network' option" unless network
super(options)
end
def create
if @type == 'A'
result = virsh_update_dns 'add-last', @fqdn, @value
if result =~ /^Updated/
return true
else
raise Proxy::DNS::Error.new("DNS update error: #{result}")
end
else
logger.warn "not creating #{@type} record for #{@fqdn} (unsupported)"
end
end
def remove
if @type == 'A'
result = virsh_update_dns 'delete', @fqdn, find_ip_for_host(@fqdn)
if result =~ /^Updated/
return true
else
raise Proxy::DNS::Error.new("DNS update error: #{result}")
end
else
logger.warn "not deleting #{@type} record for #{@fqdn} (unsupported)"
end
end
end
end
lib/proxy/virsh.rb
require 'rexml/document'
module Proxy::Virsh
include Proxy::Log
include Proxy::Util
attr_reader :network
def dump_xml
@xml_dump ||= virsh('net-dumpxml', network)
end
def find_ip_for_host host
doc = REXML::Document.new xml = dump_xml
doc.elements.each("network/dns/host/hostname") do |e|
if e.text == host
return e.parent.attributes["ip"]
end
end
raise Proxy::DNS::Error.new("Cannot find DNS entry for #{host}")
rescue Exception => e
msg = "DNS virsh provider error: unable to retrive virsh info: #{e}"
logger.error msg
logger.debug xml if defined?(xml)
raise Proxy::DNS::Error, msg
end
def virsh *params
unless sudo_cmd = which("sudo", "/usr/bin", "/usr/sbin")
raise "DNS virsh provider error: sudo binary was not found"
end
unless virsh_cmd = which("virsh", "/usr/bin", "/usr/sbin")
raise "DNS virsh provider error: virsh binary was not found"
end
logger.debug command = ([sudo_cmd, virsh_cmd] + params + ['2>&1']).join(' ')
stdout = `#{command}`
if $? == 0
return stdout
else
raise "DNS virsh provider error: virsh call failed (#{$?}) - #{stdout}"
end
end
def virsh_update_dns command, hostname, ip
hostname = escape_for_shell(hostname)
ip = escape_for_shell(ip)
net = escape_for_shell(network)
virsh "net-update", net, command, "dns-host",
"--xml", "'<host ip=\"#{ip}\"><hostname>#{hostname}</hostname></host>'",
"--live", "--config"
rescue Exception => e
raise Proxy::DNS::Error, "Failed to update DNS: #{e}"
end
def virsh_update_dhcp command, mac, ip
mac = escape_for_shell(mac)
ip = escape_for_shell(ip)
net = escape_for_shell(network)
virsh "net-update", net, command, "ip-dhcp-host",
"--xml", "'<host mac=\"#{mac}\" ip=\"#{ip}\"/>'",
"--live", "--config"
rescue Exception => e
raise Proxy::DHCP::Error, "Failed to update DNS: #{e}"
end
end

Also available in: Unified diff