smart_proxy_dns_powerdns 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +26 -8
- data/lib/smart_proxy_dns_powerdns/backend/dummy.rb +24 -0
- data/lib/smart_proxy_dns_powerdns/backend/mysql.rb +49 -0
- data/lib/smart_proxy_dns_powerdns/backend/postgresql.rb +42 -0
- data/lib/smart_proxy_dns_powerdns/dependencies.rb +15 -0
- data/lib/smart_proxy_dns_powerdns/dns_powerdns_configuration_validator.rb +32 -0
- data/lib/smart_proxy_dns_powerdns/dns_powerdns_main.rb +38 -85
- data/lib/smart_proxy_dns_powerdns/dns_powerdns_plugin.rb +8 -3
- data/lib/smart_proxy_dns_powerdns/dns_powerdns_version.rb +1 -1
- data/test/integration/integration_test.rb +83 -0
- data/test/unit/dns_powerdns_configuration_validator_test.rb +78 -0
- data/test/unit/dns_powerdns_record_mysql_test.rb +77 -0
- data/test/unit/dns_powerdns_record_postgresql_test.rb +20 -0
- data/test/unit/dns_powerdns_record_test.rb +115 -0
- metadata +39 -14
- data/test/dns_powerdns_record_test.rb +0 -121
- data/test/integration_tests.py +0 -79
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c0bc4acefdd0c176ea6f1d9fcbb4037f36da5606
         | 
| 4 | 
            +
              data.tar.gz: 4386be7b8b5d77463f91fd005a35735893fa64f4
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 2a4143021040bf61c3de7509fe63db0c3951cc3bc3a3f42ab8ce3f9e95777228282063801cae652de32b7e8d51e5fe9f18a61b66e5061021fc0934cf05d692b3
         | 
| 7 | 
            +
              data.tar.gz: 6ef93f4db7399b45c31937ba71a5a5fbb208880a5ec503c4a3c82ff7255167850f78ce9a6f7951dc4beb6dc7e612105ac5531116da6be32c6a33140f26e2d237
         | 
    
        data/README.md
    CHANGED
    
    | @@ -7,7 +7,15 @@ This plugin adds a new DNS provider for managing records in PowerDNS. | |
| 7 7 | 
             
            See [How_to_Install_a_Smart-Proxy_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Smart-Proxy_Plugin)
         | 
| 8 8 | 
             
            for how to install Smart Proxy plugins
         | 
| 9 9 |  | 
| 10 | 
            -
            This plugin is compatible with Smart Proxy 1. | 
| 10 | 
            +
            This plugin is compatible with Smart Proxy 1.11 or higher.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            When installing using "gem", make sure to install the bundle file:
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            	echo "gem 'smart_proxy_dns_powerdns'" > /usr/share/foreman-proxy/bundler.d/dns_powerdns.rb
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            ## Upgrading
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Per version 0.2.0 the backend is a required parameter.
         | 
| 11 19 |  | 
| 12 20 | 
             
            ## Configuration
         | 
| 13 21 |  | 
| @@ -15,13 +23,25 @@ To enable this DNS provider, edit `/etc/foreman-proxy/settings.d/dns.yml` and se | |
| 15 23 |  | 
| 16 24 | 
             
                :use_provider: dns_powerdns
         | 
| 17 25 |  | 
| 18 | 
            -
            Configuration options for this plugin are in `/etc/foreman-proxy/settings.d/dns_powerdns.yml | 
| 26 | 
            +
            Configuration options for this plugin are in `/etc/foreman-proxy/settings.d/dns_powerdns.yml`.
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            ### MySQL
         | 
| 19 29 |  | 
| 30 | 
            +
            To use MySQL, set the following parameters:
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                :powerdns_backend: 'mysql'
         | 
| 20 33 | 
             
                :powerdns_mysql_hostname: 'localhost'
         | 
| 21 34 | 
             
                :powerdns_mysql_username: 'powerdns'
         | 
| 22 35 | 
             
                :powerdns_mysql_password: ''
         | 
| 23 36 | 
             
                :powerdns_mysql_database: 'powerdns'
         | 
| 24 37 |  | 
| 38 | 
            +
            ### PostgreSQL
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            To use PostgreSQL, set the following parameters:
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                :powerdns_backend: 'postgresql'
         | 
| 43 | 
            +
                :powerdns_postgresql_connection: 'host=localhost user=powerdns password=mypassword dbname=powerdns'
         | 
| 44 | 
            +
             | 
| 25 45 | 
             
            ### DNSSEC
         | 
| 26 46 |  | 
| 27 47 | 
             
            In case you've enabled DNSSEC (as you should), a rectify-zone is required after every zone change. The pdnssec command is configurable:
         | 
| @@ -38,22 +58,20 @@ Fork and send a Pull Request. Thanks! | |
| 38 58 |  | 
| 39 59 | 
             
            ### Running the integration tests
         | 
| 40 60 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
            First you need to run the smart proxy on `http://localhost:8000` and a powerdns instance on `127.0.0.1:5300` or change it in the fixtures.
         | 
| 61 | 
            +
            First you need to run the smart proxy on `http://localhost:8000` and a powerdns instance on `127.0.0.1:5300`.
         | 
| 44 62 |  | 
| 45 63 | 
             
            It is assumed the powerdns instance has both the `example.com` and `in-addr.arpa` domains configured. If not, create them:
         | 
| 46 64 |  | 
| 47 65 | 
             
                INSERT INTO domains (name, type) VALUES ('example.com', 'master'), ('in-addr.arpa', 'master');
         | 
| 48 66 | 
             
                INSERT INTO records (domain_id, name, type, content) SELECT id domain_id, name, 'SOA', 'ns1.example.com hostmaster.example.com. 0 3600 1800 1209600 3600' FROM domains WHERE NOT EXISTS (SELECT 1 FROM records WHERE records.domain_id=domains.id AND records.name=domains.name AND type='SOA');
         | 
| 49 67 |  | 
| 50 | 
            -
            Then  | 
| 68 | 
            +
            Then run the tests:
         | 
| 51 69 |  | 
| 52 | 
            -
                 | 
| 70 | 
            +
                bundle exec rake test:integration
         | 
| 53 71 |  | 
| 54 72 | 
             
            ## Copyright
         | 
| 55 73 |  | 
| 56 | 
            -
            Copyright (c) 2015 Ewoud Kohl van Wijngaarden
         | 
| 74 | 
            +
            Copyright (c) 2015 - 2016 Ewoud Kohl van Wijngaarden
         | 
| 57 75 |  | 
| 58 76 | 
             
            This program is free software: you can redistribute it and/or modify
         | 
| 59 77 | 
             
            it under the terms of the GNU General Public License as published by
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module Proxy::Dns::Powerdns::Backend
         | 
| 2 | 
            +
              class Dummy < ::Proxy::Dns::Powerdns::Record
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                def initialize(a_server = nil, a_ttl = nil)
         | 
| 5 | 
            +
                  super(a_server, a_ttl)
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def get_zone name
         | 
| 9 | 
            +
                  {
         | 
| 10 | 
            +
                    'id'   => 1,
         | 
| 11 | 
            +
                    'name' => name.partition('.')[2]
         | 
| 12 | 
            +
                  }
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def create_record domain_id, name, ttl, content, type
         | 
| 16 | 
            +
                  false
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def delete_record domain_id, name, type
         | 
| 20 | 
            +
                  false
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| 24 | 
            +
             | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            require 'mysql2'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Proxy::Dns::Powerdns::Backend
         | 
| 4 | 
            +
              class Mysql < ::Proxy::Dns::Powerdns::Record
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                attr_reader :hostname, :username, :password, :database
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(a_server = nil, a_ttl = nil)
         | 
| 9 | 
            +
                  @hostname = Proxy::Dns::Powerdns::Plugin.settings.powerdns_mysql_hostname || 'localhost'
         | 
| 10 | 
            +
                  @username = Proxy::Dns::Powerdns::Plugin.settings.powerdns_mysql_username
         | 
| 11 | 
            +
                  @password = Proxy::Dns::Powerdns::Plugin.settings.powerdns_mysql_password
         | 
| 12 | 
            +
                  @database = Proxy::Dns::Powerdns::Plugin.settings.powerdns_mysql_database
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  super(a_server, a_ttl)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def connection
         | 
| 18 | 
            +
                  @connection ||= Mysql2::Client.new(:host => hostname, :username => username, :password => password, :database => database)
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def get_zone name
         | 
| 22 | 
            +
                  domain = nil
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  name = connection.escape(name)
         | 
| 25 | 
            +
                  connection.query("SELECT LENGTH(name) domain_length, id, name FROM domains WHERE '#{name}' LIKE CONCAT('%%.', name) ORDER BY domain_length DESC LIMIT 1").each do |row|
         | 
| 26 | 
            +
                    domain = row
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  raise Proxy::Dns::Error, "Unable to determine zone. Zone must exist in PowerDNS." unless domain
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  domain
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def create_record domain_id, name, type, content
         | 
| 35 | 
            +
                  name = connection.escape(name)
         | 
| 36 | 
            +
                  content = connection.escape(content)
         | 
| 37 | 
            +
                  type = connection.escape(type)
         | 
| 38 | 
            +
                  connection.query("INSERT INTO records (domain_id, name, ttl, content, type) VALUES (#{domain_id}, '#{name}', #{ttl.to_i}, '#{content}', '#{type}')")
         | 
| 39 | 
            +
                  connection.affected_rows == 1
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def delete_record domain_id, name, type
         | 
| 43 | 
            +
                  name = connection.escape(name)
         | 
| 44 | 
            +
                  type = connection.escape(type)
         | 
| 45 | 
            +
                  connection.query("DELETE FROM records WHERE domain_id=#{domain_id} AND name='#{name}' AND type='#{type}'")
         | 
| 46 | 
            +
                  connection.affected_rows == 1
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            require 'pg'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Proxy::Dns::Powerdns::Backend
         | 
| 4 | 
            +
              class Postgresql < ::Proxy::Dns::Powerdns::Record
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                attr_reader :connection_str
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(a_server = nil, a_ttl = nil)
         | 
| 9 | 
            +
                  @connection_str = Proxy::Dns::Powerdns::Plugin.settings.powerdns_postgresql_connection
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  super(a_server, a_ttl)
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def connection
         | 
| 15 | 
            +
                  @connection ||= PG.connect(connection_str)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def get_zone name
         | 
| 19 | 
            +
                  domain = nil
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  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|
         | 
| 22 | 
            +
                    result.each do |row|
         | 
| 23 | 
            +
                      domain = row
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  raise Proxy::Dns::Error, "Unable to determine zone. Zone must exist in PowerDNS." unless domain
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  domain
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def create_record domain_id, name, type, content
         | 
| 33 | 
            +
                  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])
         | 
| 34 | 
            +
                  result.cmdtuples == 1
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def delete_record domain_id, name, type
         | 
| 38 | 
            +
                  result = connection.exec_params("DELETE FROM records WHERE domain_id=$1::int AND name=$2 AND type=$3", [domain_id, name, type])
         | 
| 39 | 
            +
                  result.cmdtuples == 1
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require 'dns_common/dependency_injection/dependencies'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Proxy::Dns::DependencyInjection::Dependencies
         | 
| 4 | 
            +
              case Proxy::Dns::Powerdns::Plugin.settings.powerdns_backend
         | 
| 5 | 
            +
              when 'mysql'
         | 
| 6 | 
            +
                require 'smart_proxy_dns_powerdns/backend/mysql'
         | 
| 7 | 
            +
                dependency :dns_provider, Proxy::Dns::Powerdns::Backend::Mysql
         | 
| 8 | 
            +
              when 'postgresql'
         | 
| 9 | 
            +
                require 'smart_proxy_dns_powerdns/backend/postgresql'
         | 
| 10 | 
            +
                dependency :dns_provider, Proxy::Dns::Powerdns::Backend::Postgresql
         | 
| 11 | 
            +
              when 'dummy'
         | 
| 12 | 
            +
                require 'smart_proxy_dns_powerdns/backend/dummy'
         | 
| 13 | 
            +
                dependency :dns_provider, Proxy::Dns::Powerdns::Backend::Dummy
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_plugin'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Proxy::Dns::Powerdns
         | 
| 4 | 
            +
              class ConfigurationValidator
         | 
| 5 | 
            +
                def validate_settings!(settings)
         | 
| 6 | 
            +
                  validate_choice(settings, :powerdns_backend, ['mysql', 'postgresql', 'dummy'])
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  case settings.powerdns_backend
         | 
| 9 | 
            +
                  when 'mysql'
         | 
| 10 | 
            +
                    validate_presence(settings, [:powerdns_mysql_username, :powerdns_mysql_password, :powerdns_mysql_database])
         | 
| 11 | 
            +
                  when 'postgresql'
         | 
| 12 | 
            +
                    validate_presence(settings, [:powerdns_postgresql_connection])
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def validate_choice(settings, setting, choices)
         | 
| 17 | 
            +
                  value = settings.send(setting)
         | 
| 18 | 
            +
                  unless choices.include?(value)
         | 
| 19 | 
            +
                    raise ::Proxy::Error::ConfigurationError, "Parameter '#{setting}' is expected to be one of #{choices.join(",")}"
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                  true
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def validate_presence(settings, names)
         | 
| 25 | 
            +
                  names.each do |name|
         | 
| 26 | 
            +
                    value = settings.send(name)
         | 
| 27 | 
            +
                    raise ::Proxy::Error::ConfigurationError, "Parameter '#{name}' is expected to have a non-empty value" if value.nil? || value.to_s.empty?
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                  true
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| @@ -1,120 +1,73 @@ | |
| 1 1 | 
             
            require 'dns/dns'
         | 
| 2 | 
            +
            require 'dns_common/dns_common'
         | 
| 2 3 | 
             
            require 'ipaddr'
         | 
| 3 | 
            -
            require 'mysql2'
         | 
| 4 4 |  | 
| 5 5 | 
             
            module Proxy::Dns::Powerdns
         | 
| 6 6 | 
             
              class Record < ::Proxy::Dns::Record
         | 
| 7 7 | 
             
                include Proxy::Log
         | 
| 8 8 | 
             
                include Proxy::Util
         | 
| 9 9 |  | 
| 10 | 
            -
                attr_reader : | 
| 10 | 
            +
                attr_reader :pdnssec
         | 
| 11 11 |  | 
| 12 | 
            -
                def  | 
| 13 | 
            -
                   | 
| 14 | 
            -
             | 
| 15 | 
            -
                    :powerdns_mysql_username => ::Proxy::Dns::Powerdns::Plugin.settings.powerdns_mysql_username,
         | 
| 16 | 
            -
                    :powerdns_mysql_password => ::Proxy::Dns::Powerdns::Plugin.settings.powerdns_mysql_password,
         | 
| 17 | 
            -
                    :powerdns_mysql_database => ::Proxy::Dns::Powerdns::Plugin.settings.powerdns_mysql_database,
         | 
| 18 | 
            -
                    :powerdns_pdnssec => ::Proxy::Dns::Powerdns::Plugin.settings.powerdns_pdnssec
         | 
| 19 | 
            -
                  ))
         | 
| 12 | 
            +
                def initialize(a_server = nil, a_ttl = nil)
         | 
| 13 | 
            +
                  @pdnssec = Proxy::Dns::Powerdns::Plugin.settings.powerdns_pdnssec
         | 
| 14 | 
            +
                  super(a_server, a_ttl || Proxy::Dns::Plugin.settings.dns_ttl)
         | 
| 20 15 | 
             
                end
         | 
| 21 16 |  | 
| 22 | 
            -
                def  | 
| 23 | 
            -
                   | 
| 24 | 
            -
             | 
| 25 | 
            -
                  raise "dns_powerdns provider needs 'powerdns_mysql_password' option" unless options[:powerdns_mysql_password]
         | 
| 26 | 
            -
                  raise "dns_powerdns provider needs 'powerdns_mysql_database' option" unless options[:powerdns_mysql_database]
         | 
| 27 | 
            -
                  @mysql_connection = Mysql2::Client.new(
         | 
| 28 | 
            -
                    :host => options[:powerdns_mysql_hostname],
         | 
| 29 | 
            -
                    :username => options[:powerdns_mysql_username],
         | 
| 30 | 
            -
                    :password => options[:powerdns_mysql_password],
         | 
| 31 | 
            -
                    :database => options[:powerdns_mysql_database]
         | 
| 32 | 
            -
                  )
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                  @powerdns_pdnssec = options[:powerdns_pdnssec] || false
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                  # Normalize the somewhat weird PTR API spec to name / content
         | 
| 37 | 
            -
                  case options[:type]
         | 
| 38 | 
            -
                  when "PTR"
         | 
| 39 | 
            -
                    if options[:value] =~ /\.(in-addr|ip6)\.arpa$/
         | 
| 40 | 
            -
                      @name = options[:value]
         | 
| 41 | 
            -
                    else
         | 
| 42 | 
            -
                      @name = IPAddr.new(options[:value]).reverse
         | 
| 43 | 
            -
                    end
         | 
| 44 | 
            -
                    @content = options[:fqdn]
         | 
| 45 | 
            -
                  else
         | 
| 46 | 
            -
                    @name = options[:fqdn]
         | 
| 47 | 
            -
                    @content = options[:value]
         | 
| 17 | 
            +
                def create_a_record(fqdn, ip)
         | 
| 18 | 
            +
                  if found = dns_find(fqdn)
         | 
| 19 | 
            +
                    raise Proxy::Dns::Collision, "#{fqdn} is already in use by #{ip}" unless found == ip
         | 
| 48 20 | 
             
                  end
         | 
| 49 21 |  | 
| 50 | 
            -
                   | 
| 22 | 
            +
                  do_create(fqdn, ip, "A")
         | 
| 51 23 | 
             
                end
         | 
| 52 24 |  | 
| 53 | 
            -
                def  | 
| 54 | 
            -
                   | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
                  if ip = dns_find(domain_row['id'], @name)
         | 
| 58 | 
            -
                    raise Proxy::Dns::Collision, "#{@name} is already in use by #{ip}"
         | 
| 25 | 
            +
                def create_ptr_record(fqdn, ip)
         | 
| 26 | 
            +
                  if found = dns_find(ip)
         | 
| 27 | 
            +
                    raise Proxy::Dns::Collision, "#{ip} is already in use by #{found}" unless found == fqdn
         | 
| 59 28 | 
             
                  end
         | 
| 60 29 |  | 
| 61 | 
            -
                   | 
| 62 | 
            -
             | 
| 63 | 
            -
                  rectify_zone(domain_row['name'])
         | 
| 30 | 
            +
                  name = IPAddr.new(ip).reverse
         | 
| 31 | 
            +
                  do_create(name, fqdn, "PTR")
         | 
| 64 32 | 
             
                end
         | 
| 65 33 |  | 
| 66 | 
            -
                def  | 
| 67 | 
            -
                   | 
| 68 | 
            -
                   | 
| 69 | 
            -
             | 
| 70 | 
            -
                  delete_record(domain_row['id'], @name, @type)
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                  rectify_zone(domain_row['name'])
         | 
| 34 | 
            +
                def do_create(name, value, type)
         | 
| 35 | 
            +
                  zone = get_zone(name)
         | 
| 36 | 
            +
                  create_record(zone['id'], name, type, value) and rectify_zone(zone['name'])
         | 
| 73 37 | 
             
                end
         | 
| 74 38 |  | 
| 75 | 
            -
                 | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 39 | 
            +
                def remove_a_record(fqdn)
         | 
| 40 | 
            +
                  do_remove(fqdn, "A")
         | 
| 41 | 
            +
                end
         | 
| 78 42 |  | 
| 79 | 
            -
             | 
| 80 | 
            -
                   | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 43 | 
            +
                def remove_ptr_record(ip)
         | 
| 44 | 
            +
                  name = ip # Note ip is already in-addr.arpa
         | 
| 45 | 
            +
                  do_remove(name, "PTR")
         | 
| 46 | 
            +
                end
         | 
| 83 47 |  | 
| 84 | 
            -
             | 
| 48 | 
            +
                def do_remove(name, type)
         | 
| 49 | 
            +
                  zone = get_zone(name)
         | 
| 50 | 
            +
                  delete_record(zone['id'], name, type) and rectify_zone(zone['name'])
         | 
| 85 51 | 
             
                end
         | 
| 86 52 |  | 
| 87 | 
            -
                 | 
| 88 | 
            -
             | 
| 89 | 
            -
                   | 
| 90 | 
            -
                  key = mysql_connection.escape(key)
         | 
| 91 | 
            -
                  mysql_connection.query("SELECT content FROM records WHERE domain_id=#{domain_id} AND name = '#{key}' LIMIT 1").each do |row|
         | 
| 92 | 
            -
                    value = row["content"]
         | 
| 93 | 
            -
                  end
         | 
| 94 | 
            -
                  value || false
         | 
| 53 | 
            +
                def get_zone(fqdn)
         | 
| 54 | 
            +
                  # TODO: backend specific
         | 
| 55 | 
            +
                  raise Proxy::Dns::Error, "Unable to determine zone. Zone must exist in PowerDNS."
         | 
| 95 56 | 
             
                end
         | 
| 96 57 |  | 
| 97 | 
            -
                 | 
| 98 | 
            -
             | 
| 99 | 
            -
                   | 
| 100 | 
            -
                  content = mysql_connection.escape(content)
         | 
| 101 | 
            -
                  type = mysql_connection.escape(type)
         | 
| 102 | 
            -
                  mysql_connection.query("INSERT INTO records (domain_id, name, ttl, content, type) VALUES (#{domain_id}, '#{name}', #{ttl.to_i}, '#{content}', '#{type}')")
         | 
| 103 | 
            -
                  true
         | 
| 58 | 
            +
                def create_record(domain_id, name, type, content)
         | 
| 59 | 
            +
                  # TODO: backend specific
         | 
| 60 | 
            +
                  false
         | 
| 104 61 | 
             
                end
         | 
| 105 62 |  | 
| 106 | 
            -
                 | 
| 107 | 
            -
             | 
| 108 | 
            -
                   | 
| 109 | 
            -
                  type = mysql_connection.escape(type)
         | 
| 110 | 
            -
                  mysql_connection.query("DELETE FROM records WHERE domain_id=#{domain_id} AND name='#{name}' AND type='#{type}'")
         | 
| 111 | 
            -
                  true
         | 
| 63 | 
            +
                def delete_record(domain_id, name, type)
         | 
| 64 | 
            +
                  # TODO: backend specific
         | 
| 65 | 
            +
                  false
         | 
| 112 66 | 
             
                end
         | 
| 113 67 |  | 
| 114 | 
            -
                private
         | 
| 115 68 | 
             
                def rectify_zone domain
         | 
| 116 | 
            -
                  if @ | 
| 117 | 
            -
                    %x(#{@ | 
| 69 | 
            +
                  if @pdnssec
         | 
| 70 | 
            +
                    %x(#{@pdnssec} rectify-zone "#{domain}")
         | 
| 118 71 |  | 
| 119 72 | 
             
                    $?.exitstatus == 0
         | 
| 120 73 | 
             
                  else
         | 
| @@ -2,13 +2,18 @@ require 'smart_proxy_dns_powerdns/dns_powerdns_version' | |
| 2 2 |  | 
| 3 3 | 
             
            module Proxy::Dns::Powerdns
         | 
| 4 4 | 
             
              class Plugin < ::Proxy::Provider
         | 
| 5 | 
            -
                plugin :dns_powerdns, ::Proxy::Dns::Powerdns::VERSION | 
| 6 | 
            -
                       :factory => proc { |attrs| ::Proxy::Dns::Powerdns::Record.record(attrs) }
         | 
| 5 | 
            +
                plugin :dns_powerdns, ::Proxy::Dns::Powerdns::VERSION
         | 
| 7 6 |  | 
| 8 | 
            -
                requires :dns, '>= 1. | 
| 7 | 
            +
                requires :dns, '>= 1.11'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                validate_presence :powerdns_backend
         | 
| 9 10 |  | 
| 10 11 | 
             
                after_activation do
         | 
| 12 | 
            +
                  require 'smart_proxy_dns_powerdns/dns_powerdns_configuration_validator'
         | 
| 13 | 
            +
                  ::Proxy::Dns::Powerdns::ConfigurationValidator.new.validate_settings!(settings)
         | 
| 14 | 
            +
             | 
| 11 15 | 
             
                  require 'smart_proxy_dns_powerdns/dns_powerdns_main'
         | 
| 16 | 
            +
                  require 'smart_proxy_dns_powerdns/dependencies'
         | 
| 12 17 | 
             
                end
         | 
| 13 18 | 
             
              end
         | 
| 14 19 | 
             
            end
         | 
| @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'ipaddr'
         | 
| 4 | 
            +
            require 'net/http'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            class DnsPowerdnsIntegrationTest < Test::Unit::TestCase
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def test_forward_dns
         | 
| 9 | 
            +
                data = {'fqdn' => fqdn, 'value' => ip, 'type' => 'A'}
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                uri = URI(smart_proxy_url)
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                Net::HTTP.start(uri.host, uri.port) do |http|
         | 
| 14 | 
            +
                  request = Net::HTTP::Post.new(smart_proxy_url + 'dns/')
         | 
| 15 | 
            +
                  request.form_data = data
         | 
| 16 | 
            +
                  response = http.request request
         | 
| 17 | 
            +
                  assert_equal(200, response.code.to_i)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  addresses = resolver.getaddresses(data['fqdn'])
         | 
| 20 | 
            +
                  assert_equal([Resolv::IPv4.create(data['value'])], addresses, "#{data['fqdn']} should resolve to #{data['value']}")
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  request = Net::HTTP::Delete.new(smart_proxy_url + 'dns/' + data['fqdn'])
         | 
| 23 | 
            +
                  response = http.request request
         | 
| 24 | 
            +
                  assert_equal(200, response.code.to_i)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  assert(purge_cache data['fqdn'])
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  addresses = resolver.getaddresses(data['fqdn'])
         | 
| 29 | 
            +
                  assert_equal([], addresses)
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def test_reverse_dns
         | 
| 34 | 
            +
                data = {'fqdn' => fqdn, 'value' => ip, 'type' => 'PTR'}
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                uri = URI(smart_proxy_url)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                Net::HTTP.start(uri.host, uri.port) do |http|
         | 
| 39 | 
            +
                  request = Net::HTTP::Post.new(smart_proxy_url + 'dns/')
         | 
| 40 | 
            +
                  request.form_data = data
         | 
| 41 | 
            +
                  response = http.request request
         | 
| 42 | 
            +
                  assert_equal(200, response.code.to_i)
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  name = Resolv::IPv4.create(data['value']).to_name.to_s
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  addresses = resolver.getnames(data['value'])
         | 
| 47 | 
            +
                  assert_equal([Resolv::DNS::Name.create(data['fqdn'] + '.')], addresses, "#{data['value']} should reverse to #{data['fqdn']}")
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  request = Net::HTTP::Delete.new(smart_proxy_url + 'dns/' + name)
         | 
| 50 | 
            +
                  response = http.request request
         | 
| 51 | 
            +
                  assert_equal(200, response.code.to_i)
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  assert(purge_cache name)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  addresses = resolver.getnames(data['value'])
         | 
| 56 | 
            +
                  assert_equal([], addresses)
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              private
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              def resolver
         | 
| 63 | 
            +
                Resolv::DNS.new(:nameserver_port => [['127.0.0.1', 5300]])
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              def smart_proxy_url
         | 
| 67 | 
            +
                'http://localhost:8000/'
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              def fqdn
         | 
| 71 | 
            +
                set = ('a' .. 'z').to_a + ('0' .. '9').to_a
         | 
| 72 | 
            +
                10.times.collect {|i| set[rand(set.size)] }.join + '.example.com'
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def ip
         | 
| 76 | 
            +
                IPAddr.new(rand(2 ** 32), Socket::AF_INET).to_s
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              def purge_cache name
         | 
| 80 | 
            +
                %x{#{ENV['PDNS_CONTROL'] || "pdns_control"} purge "#{name}"}
         | 
| 81 | 
            +
                $? == 0
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         | 
| @@ -0,0 +1,78 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
            require 'ostruct'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_plugin'
         | 
| 5 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_configuration_validator'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            class DnsPowerdnsConfigurationValidatorTest < Test::Unit::TestCase
         | 
| 8 | 
            +
              def setup
         | 
| 9 | 
            +
                @config_validator = Proxy::Dns::Powerdns::ConfigurationValidator.new
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def test_initialize_missing_backend
         | 
| 13 | 
            +
                settings = OpenStruct.new(:dns_provider => 'powerdns', :powerdns_backend => nil)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                assert_raise Proxy::Error::ConfigurationError do
         | 
| 16 | 
            +
                  @config_validator.validate_settings!(settings)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def test_initialize_invalid_backend
         | 
| 21 | 
            +
                settings = OpenStruct.new(:dns_provider => 'powerdns', :powerdns_backend => 'invalid')
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                assert_raise Proxy::Error::ConfigurationError do
         | 
| 24 | 
            +
                  @config_validator.validate_settings!(settings)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def test_initialize_dummy_with_settings
         | 
| 29 | 
            +
                settings = OpenStruct.new(:dns_provider => 'powerdns', :powerdns_backend => 'dummy')
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                assert_nothing_raised do
         | 
| 32 | 
            +
                  @config_validator.validate_settings!(settings)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              def test_initialize_mysql_without_settings
         | 
| 37 | 
            +
                settings = OpenStruct.new(:dns_provider => 'powerdns', :powerdns_backend => 'mysql')
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                assert_raise Proxy::Error::ConfigurationError do
         | 
| 40 | 
            +
                  @config_validator.validate_settings!(settings)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def test_initialize_mysql_with_settings
         | 
| 45 | 
            +
                settings = OpenStruct.new(
         | 
| 46 | 
            +
                  :dns_provider => 'powerdns',
         | 
| 47 | 
            +
                  :powerdns_backend => 'mysql',
         | 
| 48 | 
            +
                  :powerdns_mysql_hostname => 'localhost',
         | 
| 49 | 
            +
                  :powerdns_mysql_username => 'username',
         | 
| 50 | 
            +
                  :powerdns_mysql_password => 'password',
         | 
| 51 | 
            +
                  :powerdns_mysql_database => 'powerdns'
         | 
| 52 | 
            +
                )
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                assert_nothing_raised do
         | 
| 55 | 
            +
                  @config_validator.validate_settings!(settings)
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              def test_initialize_postgresql_without_settings
         | 
| 60 | 
            +
                settings = OpenStruct.new(:dns_provider => 'powerdns', :powerdns_backend => 'postgresql')
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                assert_raise Proxy::Error::ConfigurationError do
         | 
| 63 | 
            +
                  @config_validator.validate_settings!(settings)
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              def test_initialize_postgresql_with_settings
         | 
| 68 | 
            +
                settings = OpenStruct.new(
         | 
| 69 | 
            +
                  :dns_provider => 'powerdns',
         | 
| 70 | 
            +
                  :powerdns_backend => 'postgresql',
         | 
| 71 | 
            +
                  :powerdns_postgresql_connection => 'dbname=powerdns'
         | 
| 72 | 
            +
                )
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                assert_nothing_raised do
         | 
| 75 | 
            +
                  @config_validator.validate_settings!(settings)
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
            end
         | 
| @@ -0,0 +1,77 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_plugin'
         | 
| 4 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_main'
         | 
| 5 | 
            +
            require 'smart_proxy_dns_powerdns/backend/mysql'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            class DnsPowerdnsBackendMysqlTest < Test::Unit::TestCase
         | 
| 8 | 
            +
              # Test that correct initialization works
         | 
| 9 | 
            +
              def test_initialize_dummy_with_settings
         | 
| 10 | 
            +
                Proxy::Dns::Powerdns::Plugin.load_test_settings(
         | 
| 11 | 
            +
                  :powerdns_mysql_hostname => 'db.example.com',
         | 
| 12 | 
            +
                  :powerdns_mysql_username => 'the_user',
         | 
| 13 | 
            +
                  :powerdns_mysql_password => 'something_secure',
         | 
| 14 | 
            +
                  :powerdns_mysql_database => 'db_pdns'
         | 
| 15 | 
            +
                )
         | 
| 16 | 
            +
                provider = klass.new
         | 
| 17 | 
            +
                assert_equal 'db.example.com', provider.hostname
         | 
| 18 | 
            +
                assert_equal 'the_user', provider.username
         | 
| 19 | 
            +
                assert_equal 'something_secure', provider.password
         | 
| 20 | 
            +
                assert_equal 'db_pdns', provider.database
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def test_get_zone_with_existing_zone
         | 
| 24 | 
            +
                instance = klass.new
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                connection = mock()
         | 
| 27 | 
            +
                instance.stubs(:connection).returns(connection)
         | 
| 28 | 
            +
                connection.expects(:escape).with('test.example.com').returns('test.example.com')
         | 
| 29 | 
            +
                connection.expects(:query).with("SELECT LENGTH(name) domain_length, id, name FROM domains WHERE 'test.example.com' LIKE CONCAT('%%.', name) ORDER BY domain_length DESC LIMIT 1").returns([{'id' => 1, 'name' => 'example.com'}])
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                assert_equal(instance.get_zone('test.example.com'), {'id' => 1, 'name' => 'example.com'})
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def test_get_zone_without_existing_zone
         | 
| 35 | 
            +
                instance = klass.new
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                connection = mock()
         | 
| 38 | 
            +
                instance.stubs(:connection).returns(connection)
         | 
| 39 | 
            +
                connection.expects(:escape).with('test.example.com').returns('test.example.com')
         | 
| 40 | 
            +
                connection.expects(:query).with("SELECT LENGTH(name) domain_length, id, name FROM domains WHERE 'test.example.com' LIKE CONCAT('%%.', name) ORDER BY domain_length DESC LIMIT 1").returns([])
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                assert_raise(Proxy::Dns::Error) { instance.get_zone('test.example.com') }
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def test_create_record
         | 
| 46 | 
            +
                instance = klass.new
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                connection = mock()
         | 
| 49 | 
            +
                instance.stubs(:connection).returns(connection)
         | 
| 50 | 
            +
                connection.expects(:escape).with('test.example.com').returns('test.example.com')
         | 
| 51 | 
            +
                connection.expects(:escape).with('A').returns('A')
         | 
| 52 | 
            +
                connection.expects(:escape).with('10.1.1.1').returns('10.1.1.1')
         | 
| 53 | 
            +
                connection.expects(:query).with("INSERT INTO records (domain_id, name, ttl, content, type) VALUES (1, 'test.example.com', 86400, '10.1.1.1', 'A')")
         | 
| 54 | 
            +
                connection.expects(:affected_rows).returns(1)
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                assert instance.create_record(1, 'test.example.com', 'A', '10.1.1.1')
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              def test_delete_record
         | 
| 60 | 
            +
                instance = klass.new
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                connection = mock()
         | 
| 63 | 
            +
                instance.stubs(:connection).returns(connection)
         | 
| 64 | 
            +
                connection.expects(:escape).with('test.example.com').returns('test.example.com')
         | 
| 65 | 
            +
                connection.expects(:escape).with('A').returns('A')
         | 
| 66 | 
            +
                connection.expects(:query).with("DELETE FROM records WHERE domain_id=1 AND name='test.example.com' AND type='A'")
         | 
| 67 | 
            +
                connection.expects(:affected_rows).returns(1)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                assert instance.delete_record(1, 'test.example.com', 'A')
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              private
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              def klass
         | 
| 75 | 
            +
                Proxy::Dns::Powerdns::Backend::Mysql
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_plugin'
         | 
| 4 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_main'
         | 
| 5 | 
            +
            require 'smart_proxy_dns_powerdns/backend/postgresql'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            class DnsPowerdnsBackendPostgresqlTest < Test::Unit::TestCase
         | 
| 8 | 
            +
              # Test that correct initialization works
         | 
| 9 | 
            +
              def test_initialize_dummy_with_settings
         | 
| 10 | 
            +
                Proxy::Dns::Powerdns::Plugin.load_test_settings(:powerdns_postgresql_connection => 'dbname=powerdns')
         | 
| 11 | 
            +
                provider = klass.new
         | 
| 12 | 
            +
                assert_equal 'dbname=powerdns', provider.connection_str
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              private
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def klass
         | 
| 18 | 
            +
                Proxy::Dns::Powerdns::Backend::Postgresql
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,115 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_plugin'
         | 
| 4 | 
            +
            require 'smart_proxy_dns_powerdns/dns_powerdns_main'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            class DnsPowerdnsRecordTest < Test::Unit::TestCase
         | 
| 7 | 
            +
              # Test that correct initialization works
         | 
| 8 | 
            +
              def test_initialize_dummy_with_settings
         | 
| 9 | 
            +
                Proxy::Dns::Powerdns::Plugin.load_test_settings(:powerdns_pdnssec => 'sudo pdnssec')
         | 
| 10 | 
            +
                provider = klass.new
         | 
| 11 | 
            +
                assert_equal 'sudo pdnssec', provider.pdnssec
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              # Test A record creation
         | 
| 15 | 
            +
              def test_create_a
         | 
| 16 | 
            +
                instance = klass.new
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                instance.expects(:dns_find).with('test.example.com').returns(false)
         | 
| 19 | 
            +
                instance.expects(:get_zone).with('test.example.com').returns({'id' => 1, 'name' => 'example.com'})
         | 
| 20 | 
            +
                instance.expects(:create_record).with(1, 'test.example.com', 'A', '10.1.1.1').returns(true)
         | 
| 21 | 
            +
                instance.expects(:rectify_zone).with('example.com').returns(true)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                assert instance.create_a_record(fqdn, ip)
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              # Test A record creation fails if the record exists
         | 
| 27 | 
            +
              def test_create_a_conflict
         | 
| 28 | 
            +
                instance = klass.new
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                instance.expects(:dns_find).with('test.example.com').returns('192.168.1.1')
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                assert_raise(Proxy::Dns::Collision) { instance.create_a_record(fqdn, ip) }
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              # Test PTR record creation
         | 
| 36 | 
            +
              def test_create_ptr
         | 
| 37 | 
            +
                instance = klass.new
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                instance.expects(:dns_find).with('10.1.1.1').returns(false)
         | 
| 40 | 
            +
                instance.expects(:get_zone).with('1.1.1.10.in-addr.arpa').returns({'id' => 1, 'name' => '1.1.10.in-addr.arpa'})
         | 
| 41 | 
            +
                instance.expects(:create_record).with(1, '1.1.1.10.in-addr.arpa', 'PTR', 'test.example.com').returns(true)
         | 
| 42 | 
            +
                instance.expects(:rectify_zone).with('1.1.10.in-addr.arpa').returns(true)
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                assert instance.create_ptr_record(fqdn, ip)
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              # Test PTR record creation fails if the record exists
         | 
| 48 | 
            +
              def test_create_ptr_conflict
         | 
| 49 | 
            +
                instance = klass.new
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                instance.expects(:dns_find).with('10.1.1.1').returns('test2.example.com')
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                assert_raise(Proxy::Dns::Collision) { instance.create_ptr_record(fqdn, ip) }
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              # Test A record removal
         | 
| 57 | 
            +
              def test_remove_a
         | 
| 58 | 
            +
                instance = klass.new
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                instance.expects(:get_zone).with('test.example.com').returns({'id' => 1, 'name' => 'example.com'})
         | 
| 61 | 
            +
                instance.expects(:delete_record).with(1, 'test.example.com', 'A').returns(true)
         | 
| 62 | 
            +
                instance.expects(:rectify_zone).with('example.com').returns(true)
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                assert instance.remove_a_record(fqdn)
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              # Test PTR record removal
         | 
| 68 | 
            +
              def test_remove_ptr
         | 
| 69 | 
            +
                instance = klass.new
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                instance.expects(:get_zone).with('1.1.1.10.in-addr.arpa').returns({'id' => 1, 'name' => '1.1.10.in-addr.arpa'})
         | 
| 72 | 
            +
                instance.expects(:delete_record).with(1, '1.1.1.10.in-addr.arpa', 'PTR').returns(true)
         | 
| 73 | 
            +
                instance.expects(:rectify_zone).with('1.1.10.in-addr.arpa').returns(true)
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                assert instance.remove_ptr_record(reverse_ip)
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              def test_do_create
         | 
| 79 | 
            +
                instance = klass.new
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                instance.expects(:get_zone).with('test.example.com').returns({'id' => 1, 'name' => 'example.com'})
         | 
| 82 | 
            +
                instance.expects(:create_record).with(1, 'test.example.com', 'A', '10.1.1.1').returns(true)
         | 
| 83 | 
            +
                instance.expects(:rectify_zone).with('example.com').returns(true)
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                assert instance.do_create('test.example.com', '10.1.1.1', 'A')
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              def test_do_remove
         | 
| 89 | 
            +
                instance = klass.new
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                instance.expects(:get_zone).with('test.example.com').returns({'id' => 1, 'name' => 'example.com'})
         | 
| 92 | 
            +
                instance.expects(:delete_record).with(1, 'test.example.com', 'A').returns(true)
         | 
| 93 | 
            +
                instance.expects(:rectify_zone).with('example.com').returns(true)
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                assert instance.do_remove('test.example.com', 'A')
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              private
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              def klass
         | 
| 101 | 
            +
                Proxy::Dns::Powerdns::Record
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
              def fqdn
         | 
| 105 | 
            +
                'test.example.com'
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              def ip
         | 
| 109 | 
            +
                '10.1.1.1'
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              def reverse_ip
         | 
| 113 | 
            +
                '1.1.1.10.in-addr.arpa'
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,55 +1,69 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: smart_proxy_dns_powerdns
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Ewoud Kohl van Wijngaarden
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2016-02-21 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake
         | 
| 15 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 16 | 
             
                requirements:
         | 
| 17 | 
            -
                - -  | 
| 17 | 
            +
                - - ">="
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 19 | 
             
                    version: '0'
         | 
| 20 20 | 
             
              type: :development
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 | 
            -
                - -  | 
| 24 | 
            +
                - - ">="
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: '0'
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: mocha
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 30 | 
             
                requirements:
         | 
| 31 | 
            -
                - -  | 
| 31 | 
            +
                - - ">="
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 33 | 
             
                    version: '0'
         | 
| 34 34 | 
             
              type: :development
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 | 
            -
                - -  | 
| 38 | 
            +
                - - ">="
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 40 | 
             
                    version: '0'
         | 
| 41 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 42 | 
             
              name: mysql2
         | 
| 43 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 44 | 
             
                requirements:
         | 
| 45 | 
            -
                - -  | 
| 45 | 
            +
                - - ">="
         | 
| 46 46 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 47 | 
             
                    version: '0'
         | 
| 48 48 | 
             
              type: :runtime
         | 
| 49 49 | 
             
              prerelease: false
         | 
| 50 50 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 51 | 
             
                requirements:
         | 
| 52 | 
            -
                - -  | 
| 52 | 
            +
                - - ">="
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: pg
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :runtime
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 53 67 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 68 | 
             
                    version: '0'
         | 
| 55 69 | 
             
            description: PowerDNS DNS provider plugin for Foreman's smart proxy
         | 
| @@ -64,12 +78,20 @@ files: | |
| 64 78 | 
             
            - bundler.d/dns_powerdns.rb
         | 
| 65 79 | 
             
            - config/dns_powerdns.yml
         | 
| 66 80 | 
             
            - lib/smart_proxy_dns_powerdns.rb
         | 
| 81 | 
            +
            - lib/smart_proxy_dns_powerdns/backend/dummy.rb
         | 
| 82 | 
            +
            - lib/smart_proxy_dns_powerdns/backend/mysql.rb
         | 
| 83 | 
            +
            - lib/smart_proxy_dns_powerdns/backend/postgresql.rb
         | 
| 84 | 
            +
            - lib/smart_proxy_dns_powerdns/dependencies.rb
         | 
| 85 | 
            +
            - lib/smart_proxy_dns_powerdns/dns_powerdns_configuration_validator.rb
         | 
| 67 86 | 
             
            - lib/smart_proxy_dns_powerdns/dns_powerdns_main.rb
         | 
| 68 87 | 
             
            - lib/smart_proxy_dns_powerdns/dns_powerdns_plugin.rb
         | 
| 69 88 | 
             
            - lib/smart_proxy_dns_powerdns/dns_powerdns_version.rb
         | 
| 70 | 
            -
            - test/ | 
| 71 | 
            -
            - test/integration_tests.py
         | 
| 89 | 
            +
            - test/integration/integration_test.rb
         | 
| 72 90 | 
             
            - test/test_helper.rb
         | 
| 91 | 
            +
            - test/unit/dns_powerdns_configuration_validator_test.rb
         | 
| 92 | 
            +
            - test/unit/dns_powerdns_record_mysql_test.rb
         | 
| 93 | 
            +
            - test/unit/dns_powerdns_record_postgresql_test.rb
         | 
| 94 | 
            +
            - test/unit/dns_powerdns_record_test.rb
         | 
| 73 95 | 
             
            homepage: https://github.com/theforeman/smart_proxy_dns_powerdns
         | 
| 74 96 | 
             
            licenses:
         | 
| 75 97 | 
             
            - GPLv3
         | 
| @@ -80,12 +102,12 @@ require_paths: | |
| 80 102 | 
             
            - lib
         | 
| 81 103 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 82 104 | 
             
              requirements:
         | 
| 83 | 
            -
              - -  | 
| 105 | 
            +
              - - ">="
         | 
| 84 106 | 
             
                - !ruby/object:Gem::Version
         | 
| 85 107 | 
             
                  version: '0'
         | 
| 86 108 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 87 109 | 
             
              requirements:
         | 
| 88 | 
            -
              - -  | 
| 110 | 
            +
              - - ">="
         | 
| 89 111 | 
             
                - !ruby/object:Gem::Version
         | 
| 90 112 | 
             
                  version: '0'
         | 
| 91 113 | 
             
            requirements: []
         | 
| @@ -96,5 +118,8 @@ specification_version: 4 | |
| 96 118 | 
             
            summary: PowerDNS DNS provider plugin for Foreman's smart proxy
         | 
| 97 119 | 
             
            test_files:
         | 
| 98 120 | 
             
            - test/test_helper.rb
         | 
| 99 | 
            -
            - test/ | 
| 100 | 
            -
            - test/ | 
| 121 | 
            +
            - test/integration/integration_test.rb
         | 
| 122 | 
            +
            - test/unit/dns_powerdns_record_postgresql_test.rb
         | 
| 123 | 
            +
            - test/unit/dns_powerdns_configuration_validator_test.rb
         | 
| 124 | 
            +
            - test/unit/dns_powerdns_record_mysql_test.rb
         | 
| 125 | 
            +
            - test/unit/dns_powerdns_record_test.rb
         | 
| @@ -1,121 +0,0 @@ | |
| 1 | 
            -
            require 'test_helper'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require 'smart_proxy_dns_powerdns/dns_powerdns_main'
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            class DnsPowerdnsRecordTest < Test::Unit::TestCase
         | 
| 6 | 
            -
              # Test that a missing :powerdns_mysql_hostname throws an error
         | 
| 7 | 
            -
              def test_initialize_without_settings
         | 
| 8 | 
            -
                assert_raise(RuntimeError) do
         | 
| 9 | 
            -
                  klass.new(settings.delete_if { |k,v| k == :powerdns_mysql_hostname })
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
              end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
              # Test that correct initialization works
         | 
| 14 | 
            -
              def test_initialize_with_settings
         | 
| 15 | 
            -
                assert_nothing_raised do
         | 
| 16 | 
            -
                  mock_mysql
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  klass.new(settings)
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
              end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              # Test A record creation
         | 
| 23 | 
            -
              def test_create_a
         | 
| 24 | 
            -
                mock_mysql
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                instance = klass.new(settings)
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                instance.expects(:domain).returns({'id' => 1})
         | 
| 29 | 
            -
                instance.expects(:dns_find).with(1, 'test.example.com').returns(false)
         | 
| 30 | 
            -
                instance.expects(:create_record).with(1, 'test.example.com', 84600, '10.1.1.1', 'A').returns(true)
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                assert instance.create
         | 
| 33 | 
            -
              end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
              # Test A record creation fails if the record exists
         | 
| 36 | 
            -
              def test_create_a_conflict
         | 
| 37 | 
            -
                mock_mysql
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                instance = klass.new(settings)
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                instance.expects(:domain).returns({'id' => 1})
         | 
| 42 | 
            -
                instance.expects(:dns_find).with(1, 'test.example.com').returns('192.168.1.1')
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                assert_raise(Proxy::Dns::Collision) { instance.create }
         | 
| 45 | 
            -
              end
         | 
| 46 | 
            -
             | 
| 47 | 
            -
              # Test PTR record creation
         | 
| 48 | 
            -
              def test_create_ptr
         | 
| 49 | 
            -
                mock_mysql
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                instance = klass.new(settings.merge(:type => 'PTR'))
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                instance.expects(:domain).returns({'id' => 1, 'name' => 'example.com'})
         | 
| 54 | 
            -
                instance.expects(:dns_find).with(1, '1.1.1.10.in-addr.arpa').returns(false)
         | 
| 55 | 
            -
                instance.expects(:create_record).with(1, '1.1.1.10.in-addr.arpa', 84600, 'test.example.com', 'PTR').returns(true)
         | 
| 56 | 
            -
                instance.expects(:rectify_zone).with('example.com').returns(true)
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                assert instance.create
         | 
| 59 | 
            -
              end
         | 
| 60 | 
            -
             | 
| 61 | 
            -
              # Test PTR record creation fails if the record exists
         | 
| 62 | 
            -
              def test_create_ptr_conflict
         | 
| 63 | 
            -
                mock_mysql
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                instance = klass.new(settings.merge(:type => 'PTR'))
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                instance.expects(:domain).returns({'id' => 1, 'name' => '1.1.10.in-addr.arpa'})
         | 
| 68 | 
            -
                instance.expects(:dns_find).with(1, '1.1.1.10.in-addr.arpa').returns('test2.example.com')
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                assert_raise(Proxy::Dns::Collision) { instance.create }
         | 
| 71 | 
            -
              end
         | 
| 72 | 
            -
             | 
| 73 | 
            -
              # Test A record removal
         | 
| 74 | 
            -
              def test_remove_a
         | 
| 75 | 
            -
                mock_mysql
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                instance = klass.new(settings)
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                instance.expects(:domain).returns({'id' => 1, 'name' => 'example.com'})
         | 
| 80 | 
            -
                instance.expects(:delete_record).with(1, 'test.example.com', 'A').returns(true)
         | 
| 81 | 
            -
                instance.expects(:rectify_zone).with('example.com').returns(true)
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                assert instance.remove
         | 
| 84 | 
            -
              end
         | 
| 85 | 
            -
             | 
| 86 | 
            -
              # Test PTR record removal
         | 
| 87 | 
            -
              def test_remove_ptr
         | 
| 88 | 
            -
                mock_mysql
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                instance = klass.new(settings.merge(:type => 'PTR'))
         | 
| 91 | 
            -
             | 
| 92 | 
            -
                instance.expects(:domain).returns({'id' => 1, 'name' => '1.1.10.in-addr.arpa'})
         | 
| 93 | 
            -
                instance.expects(:delete_record).with(1, '1.1.1.10.in-addr.arpa', 'PTR').returns(true)
         | 
| 94 | 
            -
                instance.expects(:rectify_zone).with('1.1.10.in-addr.arpa').returns(true)
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                assert instance.remove
         | 
| 97 | 
            -
              end
         | 
| 98 | 
            -
             | 
| 99 | 
            -
              def mock_mysql
         | 
| 100 | 
            -
                Mysql2::Client.expects(:new).with(:host => 'localhost', :username => 'username', :password => 'password', :database => 'powerdns').returns(false)
         | 
| 101 | 
            -
              end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
              private
         | 
| 104 | 
            -
             | 
| 105 | 
            -
              def klass
         | 
| 106 | 
            -
                Proxy::Dns::Powerdns::Record
         | 
| 107 | 
            -
              end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
              def settings
         | 
| 110 | 
            -
                {
         | 
| 111 | 
            -
                  :powerdns_mysql_hostname => 'localhost',
         | 
| 112 | 
            -
                  :powerdns_mysql_username => 'username',
         | 
| 113 | 
            -
                  :powerdns_mysql_password => 'password',
         | 
| 114 | 
            -
                  :powerdns_mysql_database => 'powerdns',
         | 
| 115 | 
            -
                  :fqdn => 'test.example.com',
         | 
| 116 | 
            -
                  :value => '10.1.1.1',
         | 
| 117 | 
            -
                  :type => 'A',
         | 
| 118 | 
            -
                  :ttl => 84600,
         | 
| 119 | 
            -
                }
         | 
| 120 | 
            -
              end
         | 
| 121 | 
            -
            end
         | 
    
        data/test/integration_tests.py
    DELETED
    
    | @@ -1,79 +0,0 @@ | |
| 1 | 
            -
            #!/usr/bin/env python
         | 
| 2 | 
            -
            import dns.resolver
         | 
| 3 | 
            -
            import dns.reversename
         | 
| 4 | 
            -
            import pytest
         | 
| 5 | 
            -
            import random
         | 
| 6 | 
            -
            import requests
         | 
| 7 | 
            -
            import socket
         | 
| 8 | 
            -
            import string
         | 
| 9 | 
            -
            import struct
         | 
| 10 | 
            -
            import subprocess
         | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
            @pytest.fixture
         | 
| 14 | 
            -
            def resolver():
         | 
| 15 | 
            -
                """
         | 
| 16 | 
            -
                Return a resolver object against the configured powerdns server
         | 
| 17 | 
            -
                """
         | 
| 18 | 
            -
                resolver = dns.resolver.Resolver(configure=False)
         | 
| 19 | 
            -
                resolver.nameservers = ['127.0.0.1']
         | 
| 20 | 
            -
                resolver.port = 5300
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                return resolver
         | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
            @pytest.fixture
         | 
| 26 | 
            -
            def smart_proxy_url():
         | 
| 27 | 
            -
                return 'http://localhost:8000/'
         | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
            @pytest.fixture
         | 
| 31 | 
            -
            def fqdn():
         | 
| 32 | 
            -
                return ''.join(random.sample(string.lowercase, 10)) + '.' + 'example.com'
         | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
            @pytest.fixture
         | 
| 36 | 
            -
            def ip():
         | 
| 37 | 
            -
                return socket.inet_ntoa(struct.pack("!I", random.randint(1, 2 ** 32)))
         | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
            def purge_cache(name):
         | 
| 41 | 
            -
                subprocess.check_output(['sudo', 'pdns_control', 'purge', name])
         | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
            def test_forward_dns(resolver, smart_proxy_url, fqdn, ip):
         | 
| 45 | 
            -
                response = requests.post(smart_proxy_url + 'dns/',
         | 
| 46 | 
            -
                                         data={'fqdn': fqdn, 'value': ip, 'type': 'A'})
         | 
| 47 | 
            -
                response.raise_for_status()
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                answer = resolver.query(fqdn, 'A')
         | 
| 50 | 
            -
                assert len(answer.rrset.items) == 1
         | 
| 51 | 
            -
                assert answer.rrset.items[0].address == ip
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                response = requests.delete(smart_proxy_url + 'dns/' + fqdn)
         | 
| 54 | 
            -
                response.raise_for_status()
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                purge_cache(fqdn)
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                with pytest.raises(dns.resolver.NXDOMAIN):
         | 
| 59 | 
            -
                    resolver.query(fqdn, 'A')
         | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
            def test_reverse_dns(resolver, smart_proxy_url, fqdn, ip):
         | 
| 63 | 
            -
                response = requests.post(smart_proxy_url + 'dns/',
         | 
| 64 | 
            -
                                         data={'fqdn': fqdn, 'value': ip, 'type': 'PTR'})
         | 
| 65 | 
            -
                response.raise_for_status()
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                name = dns.reversename.from_address(ip)
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                answer = resolver.query(name, 'PTR')
         | 
| 70 | 
            -
                assert len(answer.rrset.items) == 1
         | 
| 71 | 
            -
                assert answer.rrset.items[0].target.to_text() == fqdn + '.'
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                response = requests.delete(smart_proxy_url + 'dns/' + name.to_text().rstrip('.'))
         | 
| 74 | 
            -
                response.raise_for_status()
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                purge_cache(name.to_text())
         | 
| 77 | 
            -
             | 
| 78 | 
            -
                with pytest.raises(dns.resolver.NXDOMAIN):
         | 
| 79 | 
            -
                    resolver.query(name, 'PTR')
         |