diff --git a/Gemfile b/Gemfile index 2a36760..5282f80 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,10 @@ source 'https://rubygems.org' gemspec +if RUBY_VERSION.start_with? '1.8' + gem 'pg', '< 0.18.0' +end + group :development do gem 'smart_proxy', :github => 'theforeman/smart-proxy', :branch => 'develop' end diff --git a/README.md b/README.md index 2748555..6e56d84 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,13 @@ To use MySQL, set the following parameters: :powerdns_mysql_password: '' :powerdns_mysql_database: 'powerdns' +### PostgreSQL + +To use PostgreSQL, set the following parameters: + + :powerdns_backend: 'postgresql' + :powerdns_postgresql_connection: 'host=localhost user=powerdns password=mypassword dbname=powerdns' + ### DNSSEC In case you've enabled DNSSEC (as you should), a rectify-zone is required after every zone change. The pdnssec command is configurable: diff --git a/lib/smart_proxy_dns_powerdns/backend/postgresql.rb b/lib/smart_proxy_dns_powerdns/backend/postgresql.rb new file mode 100644 index 0000000..cbf510d --- /dev/null +++ b/lib/smart_proxy_dns_powerdns/backend/postgresql.rb @@ -0,0 +1,42 @@ +require 'pg' + +module Proxy::Dns::Powerdns::Backend + class Postgresql < ::Proxy::Dns::Powerdns::Record + + attr_reader :connection_str + + def initialize(a_server = nil, a_ttl = nil) + @connection_str = Proxy::Dns::Powerdns::Plugin.settings.powerdns_postgresql_connection + + super(a_server, a_ttl) + end + + def connection + @connection ||= PG.connect(connection_str) + end + + def get_zone name + domain = nil + + connection.exec_params("SELECT LENGTH(name) domain_length, id, name FROM domains WHERE $1 LIKE CONCAT('%%.', name) ORDER BY domain_length DESC LIMIT 1", [name]) do |result| + result.each do |row| + domain = row + end + end + + raise Proxy::Dns::Error, "Unable to determine zone. Zone must exist in PowerDNS." unless domain + + domain + end + + def create_record domain_id, name, type, content + result = connection.exec_params("INSERT INTO records (domain_id, name, ttl, content, type) VALUES ($1::int, $2, $3::int, $4, $5)", [domain_id, name, ttl, content, type]) + result.cmdtuples == 1 + end + + def delete_record domain_id, name, type + result = connection.exec_params("DELETE FROM records WHERE domain_id=$1::int AND name=$2 AND type=$3", [domain_id, name, type]) + result.cmdtuples == 1 + end + end +end diff --git a/lib/smart_proxy_dns_powerdns/dependencies.rb b/lib/smart_proxy_dns_powerdns/dependencies.rb index fb15d14..406de5f 100644 --- a/lib/smart_proxy_dns_powerdns/dependencies.rb +++ b/lib/smart_proxy_dns_powerdns/dependencies.rb @@ -5,6 +5,9 @@ class Proxy::Dns::DependencyInjection::Dependencies when 'mysql' require 'smart_proxy_dns_powerdns/backend/mysql' dependency :dns_provider, Proxy::Dns::Powerdns::Backend::Mysql + when 'postgresql' + require 'smart_proxy_dns_powerdns/backend/postgresql' + dependency :dns_provider, Proxy::Dns::Powerdns::Backend::Postgresql when 'dummy' require 'smart_proxy_dns_powerdns/backend/dummy' dependency :dns_provider, Proxy::Dns::Powerdns::Backend::Dummy diff --git a/lib/smart_proxy_dns_powerdns/dns_powerdns_configuration_validator.rb b/lib/smart_proxy_dns_powerdns/dns_powerdns_configuration_validator.rb index 309af18..36a51a4 100644 --- a/lib/smart_proxy_dns_powerdns/dns_powerdns_configuration_validator.rb +++ b/lib/smart_proxy_dns_powerdns/dns_powerdns_configuration_validator.rb @@ -3,11 +3,13 @@ module Proxy::Dns::Powerdns class ConfigurationValidator def validate_settings!(settings) - validate_choice(settings, :powerdns_backend, ['mysql', 'dummy']) + validate_choice(settings, :powerdns_backend, ['mysql', 'postgresql', 'dummy']) case settings[:powerdns_backend] when 'mysql' validate_presence(settings, [:powerdns_mysql_username, :powerdns_mysql_password, :powerdns_mysql_database]) + when 'postgresql' + validate_presence(settings, [:powerdns_postgresql_connection]) end end diff --git a/smart_proxy_dns_powerdns.gemspec b/smart_proxy_dns_powerdns.gemspec index ff33004..56add58 100644 --- a/smart_proxy_dns_powerdns.gemspec +++ b/smart_proxy_dns_powerdns.gemspec @@ -20,4 +20,5 @@ Gem::Specification.new do |s| s.add_development_dependency('mocha') s.add_dependency('mysql2') + s.add_dependency('pg') end diff --git a/test/unit/dns_powerdns_configuration_validator_test.rb b/test/unit/dns_powerdns_configuration_validator_test.rb index d9390e8..529ad50 100644 --- a/test/unit/dns_powerdns_configuration_validator_test.rb +++ b/test/unit/dns_powerdns_configuration_validator_test.rb @@ -54,4 +54,24 @@ def test_initialize_mysql_with_settings @config_validator.validate_settings!(settings) end end + + def test_initialize_postgresql_without_settings + settings = {:dns_provider => 'powerdns', :powerdns_backend => 'postgresql'} + + assert_raise Proxy::Error::ConfigurationError do + @config_validator.validate_settings!(settings) + end + end + + def test_initialize_postgresql_with_settings + settings = { + :dns_provider => 'powerdns', + :powerdns_backend => 'postgresql', + :powerdns_postgresql_connection => 'dbname=powerdns' + } + + assert_nothing_raised do + @config_validator.validate_settings!(settings) + end + end end diff --git a/test/unit/dns_powerdns_record_postgresql_test.rb b/test/unit/dns_powerdns_record_postgresql_test.rb new file mode 100644 index 0000000..dbb632a --- /dev/null +++ b/test/unit/dns_powerdns_record_postgresql_test.rb @@ -0,0 +1,20 @@ +require 'test_helper' + +require 'smart_proxy_dns_powerdns/dns_powerdns_plugin' +require 'smart_proxy_dns_powerdns/dns_powerdns_main' +require 'smart_proxy_dns_powerdns/backend/postgresql' + +class DnsPowerdnsBackendPostgresqlTest < Test::Unit::TestCase + # Test that correct initialization works + def test_initialize_dummy_with_settings + Proxy::Dns::Powerdns::Plugin.load_test_settings(:powerdns_postgresql_connection => 'dbname=powerdns') + provider = klass.new + assert_equal 'dbname=powerdns', provider.connection_str + end + + private + + def klass + Proxy::Dns::Powerdns::Backend::Postgresql + end +end