smart_proxy_dns_powerdns 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91fabd73d9aa9962f5117f82375dbf50ebd42f1535ab1162b18f5af6eccb20a1
4
- data.tar.gz: ebcaed367e7e65a911d8711e881ff9471e7ef731015cf4c7935ba330b8f464ea
3
+ metadata.gz: cc2eb76a5e55de4041e57fd29bd4172673c8a643d89a56a0b264c31e4e245662
4
+ data.tar.gz: '08bcd7294a28f78ad53ff55f58dd4ab86556073125a5bbe7c9178680084a9393'
5
5
  SHA512:
6
- metadata.gz: 49e9f311cc142d0daf1ff414d715c52950e4ff3d599c267fae33932648aa8578fbd2b1ce8e298c4d4425e7d60e6dcc69b9c63a98d3fff2c3107558914af87c53
7
- data.tar.gz: d21fc640d1f82569fa90718912ebca748c17a66caef9ba8966cb1c1e65a01179a0eea692e9f4f727e215577bb1143b58ad32a49f82b6cb2086b2573a9571fbee
6
+ metadata.gz: 6c8184da940ba90aed1a4d0c5680fdcc87a8daef6647b961f4c9f87540a95e5d3e66095534b8bcf96fc7cffae2099ce69106e781961de5a60b5a85d1f0741dda
7
+ data.tar.gz: 3ab24a84d7a51006275d8425609b0cb0c4ba82f011b54ad3c18f768e8b0425b01fce0afcf605f91d6cc206f5bdbbe2170ae4017ebd1815bc5538a8a741c06db0
data/README.md CHANGED
@@ -19,6 +19,10 @@ When installing using "gem", make sure to install the bundle file:
19
19
 
20
20
  ## Upgrading
21
21
 
22
+ ### 0.5.0
23
+
24
+ * The multiple backends have been dropped and only REST is still supported.
25
+
22
26
  ### 0.4.0
23
27
 
24
28
  * The minimum Smart Proxy version is now 1.15
@@ -51,56 +55,11 @@ To use the REST backend, set the following parameters:
51
55
 
52
56
  **Note** only API v1 from PowerDNS 4.x is supported. The v0 API from 3.x is unsupported.
53
57
 
54
- ### DNSSEC with REST
55
-
56
- Domains in PowerDNS need a rectify action after modification. In the past this was done using pdnsutil (which can still be set) but since PowerDNS 4.1.0 the API can do this automatically. The [domain metadata API-RECTIFY](https://doc.powerdns.com/authoritative/domainmetadata.html#metadata-api-rectify) needs to be set to `1`. When it's unset, the config variable [default-api-rectify](https://doc.powerdns.com/authoritative/settings.html#setting-default-api-rectify) will be used. PowerDNS 4.2.0 started to default to true. When this is used, the value for `:powerdns_pdnssec` in this plugin should be empty (default).
57
-
58
- ### MySQL
59
-
60
- To use MySQL, set the following parameters:
61
-
62
- :powerdns_backend: 'mysql'
63
- :powerdns_mysql_hostname: 'localhost'
64
- :powerdns_mysql_username: 'powerdns'
65
- :powerdns_mysql_password: ''
66
- :powerdns_mysql_database: 'powerdns'
67
-
68
- **Note** use of this backend is deprecated. REST should be used.
69
-
70
- ### PostgreSQL
71
-
72
- To use PostgreSQL, set the following parameters:
73
-
74
- :powerdns_backend: 'postgresql'
75
- :powerdns_postgresql_connection: 'host=localhost user=powerdns password=mypassword dbname=powerdns'
76
-
77
- **Note** use of this backend is deprecated. REST should be used.
78
-
79
- ### DNSSEC with MySQL and PostgreSQL
80
-
81
- In case you've enabled DNSSEC (as you should), all database backends require a rectify-zone after every zone change. The REST backend ignores this setting. The pdnssec command is configurable:
82
-
83
- :powerdns_pdnssec: 'pdnsutil'
84
-
85
- Or a more complex example:
86
-
87
- :powerdns_pdnssec: 'sudo pdnsutil --config-name=myconfig'
88
-
89
- Note that PowerDNS 3.x used `pdnssec` rather than `pdnsutil` which explains the naming of the option.
90
-
91
- ### SOA autoserial with MySQL and PostgreSQL
92
-
93
- PowerDNS (>= 3.3) provides a feature called `autoserial` that takes care of managing the serial of `SOA` records.
94
-
95
- There are many options available regarding how PowerDNS generates the serial and details can be found looking for the `SOA-EDIT` option in PowerDNS.
96
-
97
- One option is to let the PowerDNS backend determine the `SOA` serial using the biggest `change_date` of the records associated with the DNS domain.
98
- `smart_proxy_dns_powerdns` uses this approach and updates the `change_date` field of changed records, setting them to the current timestamp of the database server, represented as **the number of seconds since EPOCH**.
58
+ ### Domain rectification
99
59
 
100
- * when a new record is created, its `change_date` is set accordingly
101
- * when a record is deleted, the `change_date` of the `SOA` record for the domain is updated
60
+ Domains in PowerDNS need a rectify action after modification. In the past this was done using pdnsutil but since PowerDNS 4.1.0 the API can do this automatically. The [domain metadata API-RECTIFY](https://doc.powerdns.com/authoritative/domainmetadata.html#metadata-api-rectify) needs to be set to `1`. When it's unset, the config variable [default-api-rectify](https://doc.powerdns.com/authoritative/settings.html#setting-default-api-rectify) will be used. PowerDNS 4.2.0 started to default to true.
102
61
 
103
- ### Updating the SOA serial when using the REST backend
62
+ ### Updating the SOA serial
104
63
 
105
64
  When using the REST backend, the `change_date` of records isn't modified by this plugin. To automatically increment the serial number of a zone, you can configure the [SOA-EDIT-API](https://doc.powerdns.com/authoritative/domainmetadata.html#soa-edit-api) zone metadata. For example:
106
65
 
@@ -3,8 +3,5 @@
3
3
  # Configuration file for 'dns_powerdns' dns provider
4
4
  #
5
5
 
6
- # use these settings for powerdns
7
- #:powerdns_mysql_hostname:
8
- #:powerdns_mysql_username:
9
- #:powerdns_mysql_password:
10
- #:powerdns_mysql_database:
6
+ #:powerdns_rest_url: "http://localhost:8081/api/v1/servers/localhost"
7
+ #:powerdns_rest_api_key: ""
@@ -6,59 +6,14 @@ module ::Proxy::Dns::Powerdns
6
6
  end
7
7
 
8
8
  def load_dependency_injection_wirings(container_instance, settings)
9
- valid_backends = ['mysql', 'postgresql', 'rest', 'dummy']
10
- backend = settings[:powerdns_backend]
11
- unless valid_backends.include?(backend)
12
- raise ::Proxy::Error::ConfigurationError.new("Invalid backend, is expected to be mysql, postgresql, rest or dummy")
13
- end
14
-
15
- begin
16
- require "smart_proxy_dns_powerdns/backend/#{backend}"
17
- rescue LoadError, e
18
- raise ::Proxy::Error::ConfigurationError.new("Failed to load backend #{backend}: #{e}")
19
- end
20
-
21
- case backend
22
- when 'mysql'
23
- container_instance.dependency :dns_provider, (lambda do
24
- Proxy::Dns::Powerdns::Backend::Mysql.new(
25
- settings[:dns_server],
26
- settings[:dns_ttl],
27
- settings[:powerdns_pdnssec],
28
- settings[:powerdns_mysql_hostname] || 'localhost',
29
- settings[:powerdns_mysql_username] || 'powerdns',
30
- settings[:powerdns_mysql_password] || '',
31
- settings[:powerdns_mysql_database] || 'pdns',
32
- )
33
- end)
34
- when 'postgresql'
35
- container_instance.dependency :dns_provider, (lambda do
36
- Proxy::Dns::Powerdns::Backend::Postgresql.new(
37
- settings[:dns_server],
38
- settings[:dns_ttl],
39
- settings[:powerdns_pdnssec],
40
- settings[:powerdns_postgresql_connection] || 'dbname=pdns',
9
+ container_instance.dependency :dns_provider, (lambda do
10
+ Proxy::Dns::Powerdns::Record.new(
11
+ settings[:dns_server],
12
+ settings[:dns_ttl],
13
+ settings[:powerdns_rest_url],
14
+ settings[:powerdns_rest_api_key],
41
15
  )
42
- end)
43
- when 'rest'
44
- raise ::Proxy::Error::ConfigurationError.new("Setting powerdns_rest_api_key must be non-empty") unless settings[:powerdns_rest_api_key]
45
-
46
- container_instance.dependency :dns_provider, (lambda do
47
- Proxy::Dns::Powerdns::Backend::Rest.new(
48
- settings[:dns_server],
49
- settings[:dns_ttl],
50
- settings[:powerdns_rest_url] || 'http://localhost:8081/api/v1/servers/localhost',
51
- settings[:powerdns_rest_api_key],
52
- )
53
- end)
54
- when 'dummy'
55
- container_instance.dependency :dns_provider, (lambda do
56
- Proxy::Dns::Powerdns::Backend::Dummy.new(
57
- settings[:dns_server],
58
- settings[:dns_ttl],
59
- )
60
- end)
61
- end
16
+ end)
62
17
  end
63
18
  end
64
19
  end
@@ -6,18 +6,18 @@ module Proxy::Dns::Powerdns
6
6
  include Proxy::Log
7
7
  include Proxy::Util
8
8
 
9
- attr_reader :pdnssec
9
+ attr_reader :url, :api_key
10
+
11
+ def initialize(a_server, a_ttl, url, api_key)
12
+ @url = url
13
+ @api_key = api_key
10
14
 
11
- def initialize(a_server, a_ttl, pdnssec = nil)
12
- @pdnssec = pdnssec
13
15
  super(a_server, a_ttl)
14
16
  end
15
17
 
16
18
  def do_create(name, value, type)
17
19
  zone = get_zone(name)
18
- if create_record(zone['id'], name, type, value)
19
- raise Proxy::Dns::Error.new("Failed to rectify zone #{zone['name']}") unless rectify_zone(zone['name'])
20
- else
20
+ unless create_record(zone['id'], name, type, value)
21
21
  raise Proxy::Dns::Error.new("Failed to insert record #{name} #{type} #{value}")
22
22
  end
23
23
  true
@@ -25,43 +25,85 @@ module Proxy::Dns::Powerdns
25
25
 
26
26
  def do_remove(name, type)
27
27
  zone = get_zone(name)
28
- if delete_record(zone['id'], name, type)
29
- raise Proxy::Dns::Error.new("Failed to rectify zone #{name}") unless rectify_zone(zone['name'])
30
- end
31
- true
28
+ delete_record(zone['id'], name, type)
32
29
  end
33
30
 
34
- # :nocov:
35
- def get_zone(name)
36
- # TODO: backend specific
37
- raise Proxy::Dns::Error, "Unable to determine zone for #{name}. Zone must exist in PowerDNS."
31
+ def get_zone name
32
+ fqdn = Resolv::DNS::Name.create(name)
33
+ fqdn = Resolv::DNS::Name.create(name + '.') unless fqdn.absolute?
34
+ uri = URI("#{@url}/zones")
35
+
36
+ result = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
37
+ request = Net::HTTP::Get.new uri
38
+ request['X-API-Key'] = @api_key
39
+ response = http.request request
40
+ zones = JSON.parse(response.body) rescue []
41
+
42
+ zones.select { |zone|
43
+ domain = Resolv::DNS::Name.create(zone['name'])
44
+ domain == fqdn or fqdn.subdomain_of?(domain)
45
+ }.max_by { |zone| zone['name'].length }
46
+ end
47
+
48
+ raise Proxy::Dns::Error, "Unable to determine zone for #{name}. Zone must exist in PowerDNS." unless result
49
+
50
+ result
38
51
  end
39
52
 
40
- def create_record(domain_id, name, type, content)
41
- # TODO: backend specific
42
- false
53
+ def create_record domain_id, name, type, content
54
+ content += '.' if ['PTR', 'CNAME'].include?(type)
55
+ rrset = {
56
+ :name => name + '.',
57
+ :type => type,
58
+ :ttl => @ttl.to_i,
59
+ :changetype => :REPLACE,
60
+ :records => [
61
+ {
62
+ :content => content,
63
+ :disabled => false
64
+ }
65
+ ]
66
+ }
67
+
68
+ patch_records domain_id, rrset
43
69
  end
44
70
 
45
- def delete_record(domain_id, name, type)
46
- # TODO: backend specific
47
- false
71
+ def delete_record domain_id, name, type
72
+ rrset = {
73
+ :name => name + '.',
74
+ :type => type,
75
+ :changetype => :DELETE,
76
+ :records => []
77
+ }
78
+
79
+ patch_records domain_id, rrset
48
80
  end
49
- # :nocov:
50
-
51
- def rectify_zone domain
52
- if @pdnssec
53
- logger.debug("running: #{@pdnssec} rectify-zone \"#{domain}\"")
54
- pdnsout = %x(#{@pdnssec} rectify-zone "#{domain}" 2>&1)
55
-
56
- if $?.exitstatus != 0
57
- logger.debug("#{@pdnssec} (exit: #{$?.exitstatus}) says: #{pdnsout}")
58
- false
59
- else
60
- true
81
+
82
+ private
83
+
84
+ def patch_records domain_id, rrset
85
+ uri = URI("#{@url}/zones/#{domain_id}")
86
+
87
+ data = { :rrsets => [rrset] }
88
+
89
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
90
+ request = Net::HTTP::Patch.new uri
91
+ request['X-API-Key'] = @api_key
92
+ request['Content-Type'] = 'application/json'
93
+ request.body = data.to_json
94
+ response = http.request request
95
+ unless response.is_a?(Net::HTTPSuccess)
96
+ begin
97
+ content = JSON.parse(response.body)
98
+ rescue
99
+ logger.debug "Failed to pach records for #{domain_id} with '#{rrset}': #{response.body}"
100
+ raise Proxy::Dns::Error.new("Failed to patch records")
101
+ end
102
+ raise Proxy::Dns::Error.new("Failed to patch records: #{content['error']}")
61
103
  end
62
- else
63
- true
64
104
  end
105
+
106
+ true
65
107
  end
66
108
  end
67
109
  end
@@ -7,7 +7,8 @@ module Proxy::Dns::Powerdns
7
7
 
8
8
  requires :dns, '>= 1.15'
9
9
 
10
- validate_presence :powerdns_backend
10
+ validate_presence :powerdns_rest_api_key
11
+ default_settings :powerdns_rest_url => 'http://localhost:8081/api/v1/servers/localhost'
11
12
 
12
13
  load_classes ::Proxy::Dns::Powerdns::PluginConfiguration
13
14
  load_dependency_injection_wirings ::Proxy::Dns::Powerdns::PluginConfiguration
@@ -1,7 +1,7 @@
1
1
  module Proxy
2
2
  module Dns
3
3
  module Powerdns
4
- VERSION = '0.4.0'
4
+ VERSION = '1.0.0'
5
5
  end
6
6
  end
7
7
  end
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'webmock/test_unit'
2
3
 
3
4
  require 'smart_proxy_dns_powerdns/dns_powerdns_configuration'
4
5
  require 'smart_proxy_dns_powerdns/dns_powerdns_main'
@@ -10,110 +11,16 @@ class DnsPowerdnsProductionWiringTest < Test::Unit::TestCase
10
11
  @config = ::Proxy::Dns::Powerdns::PluginConfiguration.new
11
12
  end
12
13
 
13
- def test_dns_provider_initialization_mysql_backend_minimal_settings
14
- @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
15
- :powerdns_backend => 'mysql')
16
-
17
- provider = @container.get_dependency(:dns_provider)
18
-
19
- assert_not_nil provider
20
- assert_equal 999, provider.ttl
21
- assert_equal 'localhost', provider.hostname
22
- assert_equal 'powerdns', provider.username
23
- assert_equal '', provider.password
24
- assert_equal 'pdns', provider.database
25
- end
26
-
27
- def test_dns_provider_initialization_mysql_backend_full_settings
28
- @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
29
- :powerdns_backend => 'mysql',
30
- :powerdns_mysql_hostname => 'db.example.com',
31
- :powerdns_mysql_username => 'user',
32
- :powerdns_mysql_password => 'super secret',
33
- :powerdns_mysql_database => 'the_db',
34
- )
35
-
36
- provider = @container.get_dependency(:dns_provider)
37
-
38
- assert_not_nil provider
39
- assert_equal 999, provider.ttl
40
- assert_equal 'db.example.com', provider.hostname
41
- assert_equal 'user', provider.username
42
- assert_equal 'super secret', provider.password
43
- assert_equal 'the_db', provider.database
44
- end
45
-
46
- def test_dns_provider_initialization_postgresql_backend_minimal_settings
47
- @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
48
- :powerdns_backend => 'postgresql')
49
-
50
- provider = @container.get_dependency(:dns_provider)
51
-
52
- assert_not_nil provider
53
- assert_equal 999, provider.ttl
54
- assert_equal 'dbname=pdns', provider.connection_str
55
- end
56
-
57
- def test_dns_provider_initialization_postgresql_backend_full_settings
58
- @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
59
- :powerdns_backend => 'postgresql',
60
- :powerdns_postgresql_connection => 'dbname=powerdns')
61
-
62
- provider = @container.get_dependency(:dns_provider)
63
-
64
- assert_not_nil provider
65
- assert_equal 999, provider.ttl
66
- assert_equal 'dbname=powerdns', provider.connection_str
67
- end
68
-
69
- def test_dns_provider_initialization_rest_backend_invalid_settings
70
- assert_raise Proxy::Error::ConfigurationError do
71
- @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
72
- :powerdns_backend => 'rest')
73
- end
74
- end
75
-
76
- def test_dns_provider_initialization_rest_backend_minimal_settings
77
- @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
78
- :powerdns_backend => 'rest',
79
- :powerdns_rest_api_key => 'apikey')
80
-
81
- provider = @container.get_dependency(:dns_provider)
82
-
83
- assert_not_nil provider
84
- assert_equal 999, provider.ttl
85
- assert_equal 'http://localhost:8081/api/v1/servers/localhost', provider.url
86
- assert_equal 'apikey', provider.api_key
87
- end
88
-
89
14
  def test_dns_provider_initialization_rest_backend_full_settings
90
15
  @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
91
- :powerdns_backend => 'rest',
92
- :powerdns_rest_url => 'http://apiserver',
16
+ :powerdns_rest_url => 'http://apiserver.example.com',
93
17
  :powerdns_rest_api_key => 'apikey')
94
18
 
95
19
  provider = @container.get_dependency(:dns_provider)
96
20
 
97
21
  assert_not_nil provider
98
22
  assert_equal 999, provider.ttl
99
- assert_equal 'http://apiserver', provider.url
23
+ assert_equal 'http://apiserver.example.com', provider.url
100
24
  assert_equal 'apikey', provider.api_key
101
25
  end
102
-
103
- def test_dns_provider_initialization_dummy_backend
104
- @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
105
- :powerdns_backend => 'dummy')
106
-
107
- provider = @container.get_dependency(:dns_provider)
108
-
109
- assert_not_nil provider
110
- assert_equal 999, provider.ttl
111
- end
112
-
113
- def test_dns_provider_initialization_invalid_backend
114
- assert_raise Proxy::Error::ConfigurationError do
115
- @config.load_dependency_injection_wirings(@container, :dns_ttl => 999,
116
- :powerdns_backend => 'invalid')
117
- end
118
- end
119
26
  end
@@ -4,18 +4,20 @@ require 'smart_proxy_dns_powerdns/dns_powerdns_main'
4
4
 
5
5
  class DnsPowerdnsRecordTest < Test::Unit::TestCase
6
6
  def setup
7
- @provider = Proxy::Dns::Powerdns::Record.new('localhost', 86400, 'echo pdnssec')
7
+ @provider = Proxy::Dns::Powerdns::Record.new('localhost', 86400,
8
+ 'http://localhost:8081/api/v1/servers/localhost',
9
+ 'apikey')
8
10
  end
9
11
 
10
12
  def test_initialize
11
13
  assert_equal 86400, @provider.ttl
12
- assert_equal 'echo pdnssec', @provider.pdnssec
14
+ assert_equal 'http://localhost:8081/api/v1/servers/localhost', @provider.url
15
+ assert_equal 'apikey', @provider.api_key
13
16
  end
14
17
 
15
18
  def test_do_create_success
16
19
  @provider.expects(:get_zone).with('test.example.com').returns({'id' => 1, 'name' => 'example.com'})
17
20
  @provider.expects(:create_record).with(1, 'test.example.com', 'A', '10.1.1.1').returns(true)
18
- @provider.expects(:rectify_zone).with('example.com').returns(true)
19
21
 
20
22
  assert @provider.do_create('test.example.com', '10.1.1.1', 'A')
21
23
  end
@@ -29,44 +31,58 @@ class DnsPowerdnsRecordTest < Test::Unit::TestCase
29
31
  end
30
32
  end
31
33
 
32
- def test_do_create_failure_in_rectify
33
- @provider.expects(:get_zone).with('test.example.com').returns({'id' => 1, 'name' => 'example.com'})
34
- @provider.expects(:create_record).with(1, 'test.example.com', 'A', '10.1.1.1').returns(true)
35
- @provider.expects(:rectify_zone).with('example.com').returns(false)
36
-
37
- assert_raise(Proxy::Dns::Error) do
38
- @provider.do_create('test.example.com', '10.1.1.1', 'A')
39
- end
40
- end
41
-
42
34
  def test_do_remove
43
35
  @provider.expects(:get_zone).with('test.example.com').returns({'id' => 1, 'name' => 'example.com'})
44
36
  @provider.expects(:delete_record).with(1, 'test.example.com', 'A').returns(true)
45
- @provider.expects(:rectify_zone).with('example.com').returns(true)
46
37
 
47
38
  assert @provider.do_remove('test.example.com', 'A')
48
39
  end
49
40
 
50
- def test_rectify_zone_success
51
- @provider.logger.expects(:debug).with('running: echo pdnssec rectify-zone "example.com"')
52
-
53
- assert_true @provider.rectify_zone 'example.com'
41
+ def test_get_zone_with_existing_zone
42
+ stub_request(:get, "http://localhost:8081/api/v1/servers/localhost/zones").
43
+ with(:headers => {'X-Api-Key' => 'apikey'}).
44
+ to_return(:body => '[{"id": "example.com.", "name": "example.com."}]')
45
+ assert_equal @provider.get_zone('test.example.com'), {'id' => 'example.com.', 'name' => 'example.com.'}
54
46
  end
55
47
 
56
- def test_rectify_zone_failure
57
- @provider = Proxy::Dns::Powerdns::Record.new('localhost', 86400, 'false')
58
-
59
- @provider.logger.expects(:debug).with('running: false rectify-zone "example.com"')
60
- @provider.logger.expects(:debug).with('false (exit: 1) says: ')
48
+ def test_get_zone_with_existing_zone_absolute_record
49
+ stub_request(:get, "http://localhost:8081/api/v1/servers/localhost/zones").
50
+ with(:headers => {'X-Api-Key' => 'apikey'}).
51
+ to_return(:body => '[{"id": "example.com.", "name": "example.com."}]')
52
+ assert_equal @provider.get_zone('test.example.com.'), {'id' => 'example.com.', 'name' => 'example.com.'}
53
+ end
61
54
 
62
- assert_false @provider.rectify_zone 'example.com'
55
+ def test_get_zone_without_existing_zone
56
+ stub_request(:get, "http://localhost:8081/api/v1/servers/localhost/zones").
57
+ with(:headers => {'X-Api-Key' => 'apikey'}).
58
+ to_return(:body => '[]')
59
+ assert_raise(Proxy::Dns::Error) { @provider.get_zone('test.example.com') }
63
60
  end
64
61
 
65
- def test_rectify_zone_no_pdnssec
66
- @provider = Proxy::Dns::Powerdns::Record.new('localhost', 86400, nil)
62
+ def test_create_a_record
63
+ stub_request(:patch, "http://localhost:8081/api/v1/servers/localhost/zones/example.com.").
64
+ with(
65
+ :headers => {'X-Api-Key' => 'apikey', 'Content-Type' => 'application/json'},
66
+ :body => '{"rrsets":[{"name":"test.example.com.","type":"A","ttl":86400,"changetype":"REPLACE","records":[{"content":"10.1.1.1","disabled":false}]}]}'
67
+ )
68
+ assert @provider.create_record('example.com.', 'test.example.com', 'A', '10.1.1.1')
69
+ end
67
70
 
68
- @provider.logger.stubs(:debug).raises(Exception)
71
+ def test_create_ptr_record
72
+ stub_request(:patch, "http://localhost:8081/api/v1/servers/localhost/zones/example.com.").
73
+ with(
74
+ :headers => {'X-Api-Key' => 'apikey', 'Content-Type' => 'application/json'},
75
+ :body => '{"rrsets":[{"name":"1.1.1.10.in-addr.arpa.","type":"PTR","ttl":86400,"changetype":"REPLACE","records":[{"content":"test.example.com.","disabled":false}]}]}'
76
+ )
77
+ assert @provider.create_record('example.com.', '1.1.1.10.in-addr.arpa', 'PTR', 'test.example.com')
78
+ end
69
79
 
70
- assert_true @provider.rectify_zone 'example.com'
80
+ def test_delete_record
81
+ stub_request(:patch, "http://localhost:8081/api/v1/servers/localhost/zones/example.com.").
82
+ with(
83
+ :headers => {'X-Api-Key' => 'apikey', 'Content-Type' => 'application/json'},
84
+ :body => '{"rrsets":[{"name":"test.example.com.","type":"A","changetype":"DELETE","records":[]}]}'
85
+ )
86
+ assert @provider.delete_record('example.com.', 'test.example.com', 'A')
71
87
  end
72
88
  end
@@ -26,11 +26,11 @@ class InternalApiTest < Test::Unit::TestCase
26
26
  end
27
27
 
28
28
  def setup
29
- @server = Proxy::Dns::Powerdns::Record.new('localhost', 3600)
29
+ @server = Proxy::Dns::Powerdns::Record.new('localhost', 3600, 'http://powerdns.example.com:8081/', 'apikey')
30
30
  end
31
31
 
32
32
  def test_create_a_record
33
- name = "test.com"
33
+ name = "sub.example.com"
34
34
  value = "192.168.33.33"
35
35
  type = "A"
36
36
  @server.expects(:do_create).with(name, value, type)
@@ -39,7 +39,7 @@ class InternalApiTest < Test::Unit::TestCase
39
39
  end
40
40
 
41
41
  def test_create_ptr_record
42
- name = "test.com"
42
+ name = "sub.example.com"
43
43
  value = "33.33.168.192.in-addr.arpa"
44
44
  type = "PTR"
45
45
  @server.expects(:do_create).with(value, name, type)
@@ -48,7 +48,7 @@ class InternalApiTest < Test::Unit::TestCase
48
48
  end
49
49
 
50
50
  def test_delete_a_record
51
- name = "test.com"
51
+ name = "sub.example.com"
52
52
  @server.expects(:do_remove).with(name, "A")
53
53
  delete name
54
54
  assert last_response.ok?, "Last response was not ok: #{last_response.status} #{last_response.body}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_dns_powerdns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.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: 2019-08-13 00:00:00.000000000 Z
11
+ date: 2020-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -38,34 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: mysql2
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
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
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
41
  description: PowerDNS DNS provider plugin for Foreman's smart proxy
70
42
  email:
71
43
  - ewoud@kohlvanwijngaarden.nl
@@ -78,10 +50,6 @@ files:
78
50
  - bundler.d/dns_powerdns.rb
79
51
  - config/dns_powerdns.yml
80
52
  - 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/backend/rest.rb
85
53
  - lib/smart_proxy_dns_powerdns/dns_powerdns_configuration.rb
86
54
  - lib/smart_proxy_dns_powerdns/dns_powerdns_main.rb
87
55
  - lib/smart_proxy_dns_powerdns/dns_powerdns_plugin.rb
@@ -89,10 +57,6 @@ files:
89
57
  - test/integration/integration_test.rb
90
58
  - test/test_helper.rb
91
59
  - test/unit/dns_powerdns_configuration_test.rb
92
- - test/unit/dns_powerdns_record_dummy_test.rb
93
- - test/unit/dns_powerdns_record_mysql_test.rb
94
- - test/unit/dns_powerdns_record_postgresql_test.rb
95
- - test/unit/dns_powerdns_record_rest_test.rb
96
60
  - test/unit/dns_powerdns_record_test.rb
97
61
  - test/unit/internal_api_test.rb
98
62
  homepage: https://github.com/theforeman/smart_proxy_dns_powerdns
@@ -119,12 +83,8 @@ signing_key:
119
83
  specification_version: 4
120
84
  summary: PowerDNS DNS provider plugin for Foreman's smart proxy
121
85
  test_files:
122
- - test/unit/dns_powerdns_record_rest_test.rb
123
86
  - test/unit/dns_powerdns_record_test.rb
124
- - test/unit/dns_powerdns_record_mysql_test.rb
125
87
  - test/unit/dns_powerdns_configuration_test.rb
126
88
  - test/unit/internal_api_test.rb
127
- - test/unit/dns_powerdns_record_postgresql_test.rb
128
- - test/unit/dns_powerdns_record_dummy_test.rb
129
89
  - test/test_helper.rb
130
90
  - test/integration/integration_test.rb
@@ -1,24 +0,0 @@
1
- module Proxy::Dns::Powerdns::Backend
2
- class Dummy < ::Proxy::Dns::Powerdns::Record
3
-
4
- def initialize(a_server, a_ttl)
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, content, type
16
- false
17
- end
18
-
19
- def delete_record domain_id, name, type
20
- false
21
- end
22
- end
23
- end
24
-
@@ -1,58 +0,0 @@
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, a_ttl, pdnssec, hostname, username, password, database)
9
- @hostname = hostname
10
- @username = username
11
- @password = password
12
- @database = database
13
-
14
- super(a_server, a_ttl, pdnssec)
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 for #{name}. 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, change_date) VALUES (#{domain_id}, '#{name}', #{ttl.to_i}, '#{content}', '#{type}', UNIX_TIMESTAMP())")
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
- return false if connection.affected_rows == 0
47
-
48
- connection.query("UPDATE records SET change_date=UNIX_TIMESTAMP() WHERE domain_id=#{domain_id} AND type='SOA'")
49
- affected_rows = connection.affected_rows
50
- if affected_rows > 1
51
- logger.warning("Updated multiple SOA records (host=#{name}, domain_id=#{domain_id}). Check your zone records for duplicate SOA entries.")
52
- elsif affected_rows == 0
53
- logger.info("No SOA record updated (host=#{name}, domain_id=#{domain_id}). This can be caused by either a missing SOA record for the zone or consecutive updates of the same zone during the same second.")
54
- end
55
- true
56
- end
57
- end
58
- end
@@ -1,51 +0,0 @@
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, a_ttl, pdnssec, connection)
9
- @connection_str = connection
10
-
11
- super(a_server, a_ttl, pdnssec)
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 for #{name}. 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, change_date) VALUES ($1::int, $2, $3::int, $4, $5, extract(epoch from now()))", [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
- return false if result.cmdtuples == 0
40
-
41
- result = connection.exec_params("UPDATE records SET change_date=extract(epoch from now()) WHERE domain_id=$1::int AND type='SOA'", [domain_id])
42
- affected_rows = result.cmdtuples
43
- if affected_rows > 1
44
- logger.warning("Updated multiple SOA records (host=#{name}, domain_id=#{domain_id}). Check your zone records for duplicate SOA entries.")
45
- elsif affected_rows == 0
46
- logger.info("No SOA record updated (host=#{name}, domain_id=#{domain_id}). This can be caused by either a missing SOA record for the zone or consecutive updates of the same zone during the same second.")
47
- end
48
- true
49
- end
50
- end
51
- end
@@ -1,97 +0,0 @@
1
- require 'json'
2
- require 'net/http'
3
- require 'resolv'
4
-
5
- module Proxy::Dns::Powerdns::Backend
6
- extend ::Proxy::Log
7
-
8
- class Rest < ::Proxy::Dns::Powerdns::Record
9
-
10
- attr_reader :url, :api_key
11
-
12
- def initialize(a_server, a_ttl, url, api_key)
13
- @url = url
14
- @api_key = api_key
15
-
16
- super(a_server, a_ttl)
17
- end
18
-
19
- def get_zone name
20
- fqdn = Resolv::DNS::Name.create(name)
21
- fqdn = Resolv::DNS::Name.create(name + '.') unless fqdn.absolute?
22
- uri = URI("#{@url}/zones")
23
-
24
- result = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
25
- request = Net::HTTP::Get.new uri
26
- request['X-API-Key'] = @api_key
27
- response = http.request request
28
- zones = JSON.parse(response.body) rescue []
29
-
30
- zones.select { |zone|
31
- domain = Resolv::DNS::Name.create(zone['name'])
32
- domain == fqdn or fqdn.subdomain_of?(domain)
33
- }.max_by { |zone| zone['name'].length }
34
- end
35
-
36
- raise Proxy::Dns::Error, "Unable to determine zone for #{name}. Zone must exist in PowerDNS." unless result
37
-
38
- result
39
- end
40
-
41
- def create_record domain_id, name, type, content
42
- content += '.' if ['PTR', 'CNAME'].include?(type)
43
- rrset = {
44
- :name => name + '.',
45
- :type => type,
46
- :ttl => @ttl.to_i,
47
- :changetype => :REPLACE,
48
- :records => [
49
- {
50
- :content => content,
51
- :disabled => false
52
- }
53
- ]
54
- }
55
-
56
- patch_records domain_id, rrset
57
- end
58
-
59
- def delete_record domain_id, name, type
60
- rrset = {
61
- :name => name + '.',
62
- :type => type,
63
- :changetype => :DELETE,
64
- :records => []
65
- }
66
-
67
- patch_records domain_id, rrset
68
- end
69
-
70
- private
71
-
72
- def patch_records domain_id, rrset
73
- uri = URI("#{@url}/zones/#{domain_id}")
74
-
75
- data = { :rrsets => [rrset] }
76
-
77
- Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
78
- request = Net::HTTP::Patch.new uri
79
- request['X-API-Key'] = @api_key
80
- request['Content-Type'] = 'application/json'
81
- request.body = data.to_json
82
- response = http.request request
83
- unless response.is_a?(Net::HTTPSuccess)
84
- begin
85
- content = JSON.parse(response.body)
86
- rescue
87
- logger.debug "Failed to pach records for #{domain_id} with '#{rrset}': #{response.body}"
88
- raise Proxy::Dns::Error.new("Failed to patch records")
89
- end
90
- raise Proxy::Dns::Error.new("Failed to patch records: #{content['error']}")
91
- end
92
- end
93
-
94
- true
95
- end
96
- end
97
- end
@@ -1,26 +0,0 @@
1
- require 'test_helper'
2
-
3
- require 'smart_proxy_dns_powerdns/dns_powerdns_main'
4
- require 'smart_proxy_dns_powerdns/backend/dummy'
5
-
6
- class DnsPowerdnsBackendDummyTest < Test::Unit::TestCase
7
- def setup
8
- @provider = Proxy::Dns::Powerdns::Backend::Dummy.new('localhost', 86400)
9
- end
10
-
11
- def test_initialize
12
- assert_equal 86400, @provider.ttl
13
- end
14
-
15
- def test_get_zone
16
- assert_equal @provider.get_zone('test.example.com'), {'id' => 1, 'name' => 'example.com'}
17
- end
18
-
19
- def test_create_record
20
- assert_false @provider.create_record(1, 'test.example.com', '10.1.2.3', 'A')
21
- end
22
-
23
- def test_delete_record
24
- assert_false @provider.delete_record(1, 'test.example.com', 'A')
25
- end
26
- end
@@ -1,114 +0,0 @@
1
- require 'test_helper'
2
-
3
- require 'smart_proxy_dns_powerdns/dns_powerdns_main'
4
- require 'smart_proxy_dns_powerdns/backend/mysql'
5
-
6
- class DnsPowerdnsBackendMysqlTest < Test::Unit::TestCase
7
- def setup
8
- @provider = Proxy::Dns::Powerdns::Backend::Mysql.new('localhost', 86400, 'sudo pdnssec',
9
- 'db.example.com', 'the_user',
10
- 'something_secure', 'db_pdns')
11
- @connection = mock()
12
- @provider.stubs(:connection).returns(@connection)
13
- end
14
-
15
- def test_initialize
16
- assert_equal 86400, @provider.ttl
17
- assert_equal 'sudo pdnssec', @provider.pdnssec
18
- assert_equal 'db.example.com', @provider.hostname
19
- assert_equal 'the_user', @provider.username
20
- assert_equal 'something_secure', @provider.password
21
- assert_equal 'db_pdns', @provider.database
22
- end
23
-
24
- def test_get_zone_with_existing_zone
25
- @connection.expects(:escape).with('test.example.com').returns('test.example.com')
26
- @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'}])
27
-
28
- assert_equal(@provider.get_zone('test.example.com'), {'id' => 1, 'name' => 'example.com'})
29
- end
30
-
31
- def test_get_zone_without_existing_zone
32
- @connection.expects(:escape).with('test.example.com').returns('test.example.com')
33
- @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([])
34
-
35
- assert_raise(Proxy::Dns::Error) { @provider.get_zone('test.example.com') }
36
- end
37
-
38
- def test_create_record
39
- @connection.expects(:escape).with('test.example.com').returns('test.example.com')
40
- @connection.expects(:escape).with('A').returns('A')
41
- @connection.expects(:escape).with('10.1.1.1').returns('10.1.1.1')
42
- @connection.expects(:query).with("INSERT INTO records (domain_id, name, ttl, content, type, change_date) VALUES (1, 'test.example.com', 86400, '10.1.1.1', 'A', UNIX_TIMESTAMP())")
43
- @connection.expects(:affected_rows).returns(1)
44
-
45
- assert @provider.create_record(1, 'test.example.com', 'A', '10.1.1.1')
46
- end
47
-
48
- def test_delete_record
49
- mock_escapes(fqdn, 'A')
50
- @connection.expects(:query).with(query_delete)
51
- @connection.expects(:query).with(query_update_soa)
52
- @connection.expects(:affected_rows).twice.returns(1)
53
- assert @provider.delete_record(domain_id, fqdn, 'A')
54
- end
55
-
56
- def test_delete_no_record
57
- mock_escapes(fqdn, 'A')
58
- @connection.expects(:query).with(query_delete)
59
- @connection.expects(:affected_rows).returns(0)
60
-
61
- assert_false @provider.delete_record(domain_id, fqdn, 'A')
62
- end
63
-
64
- def test_delete_record_no_soa
65
- mock_escapes(fqdn, 'A')
66
- @connection.expects(:query).with(query_delete)
67
- @connection.expects(:query).with(query_update_soa)
68
- @connection.expects(:affected_rows).twice.returns(1, 0)
69
- logger = mock()
70
- logger.expects(:info)
71
- @provider.stubs(:logger).returns(logger)
72
-
73
- assert @provider.delete_record(domain_id, fqdn, 'A')
74
- end
75
-
76
- def test_delete_record_multiple_soa
77
- mock_escapes(fqdn, 'A')
78
- @connection.expects(:query).with(query_delete)
79
- @connection.expects(:query).with(query_update_soa)
80
- @connection.expects(:affected_rows).twice.returns(1, 2)
81
- logger = mock()
82
- logger.expects(:warning)
83
- @provider.stubs(:logger).returns(logger)
84
-
85
- assert @provider.delete_record(domain_id, fqdn, 'A')
86
- end
87
-
88
- private
89
-
90
- def mock_escapes(*elts)
91
- elts.each { |e| @connection.expects(:escape).with(e).returns(e) }
92
- end
93
-
94
- def domain
95
- 'example.com'
96
- end
97
-
98
- def fqdn
99
- "test.#{domain}"
100
- end
101
-
102
- def domain_id
103
- 1
104
- end
105
-
106
- def query_delete(type='A')
107
- "DELETE FROM records WHERE domain_id=#{domain_id} AND name='#{fqdn}' AND type='#{type}'"
108
- end
109
-
110
- def query_update_soa
111
- "UPDATE records SET change_date=UNIX_TIMESTAMP() WHERE domain_id=#{domain_id} AND type='SOA'"
112
- end
113
-
114
- end
@@ -1,125 +0,0 @@
1
- require 'test_helper'
2
-
3
- require 'smart_proxy_dns_powerdns/dns_powerdns_main'
4
- require 'smart_proxy_dns_powerdns/backend/postgresql'
5
-
6
- class DnsPowerdnsBackendPostgresqlTest < Test::Unit::TestCase
7
- def setup
8
- @provider = Proxy::Dns::Powerdns::Backend::Postgresql.new('localhost', 86400, 'sudo pdnssec',
9
- 'dbname=powerdns')
10
- @connection = mock()
11
- @provider.stubs(:connection).returns(@connection)
12
- end
13
-
14
- def test_initialize
15
- assert_equal 86400, @provider.ttl
16
- assert_equal 'sudo pdnssec', @provider.pdnssec
17
- assert_equal 'dbname=powerdns', @provider.connection_str
18
- end
19
-
20
- def test_get_zone_with_existing_zone
21
- @connection.expects(:exec_params).
22
- with("SELECT LENGTH(name) domain_length, id, name FROM domains WHERE $1 LIKE CONCAT('%%.', name) ORDER BY domain_length DESC LIMIT 1", ['test.example.com']).
23
- yields([{'id' => 1, 'name' => 'example.com'}])
24
-
25
- assert_equal(@provider.get_zone('test.example.com'), {'id' => 1, 'name' => 'example.com'})
26
- end
27
-
28
- def test_get_zone_without_existing_zone
29
- @connection.expects(:exec_params).
30
- with("SELECT LENGTH(name) domain_length, id, name FROM domains WHERE $1 LIKE CONCAT('%%.', name) ORDER BY domain_length DESC LIMIT 1", ['test.example.com']).
31
- yields([])
32
-
33
- assert_raise(Proxy::Dns::Error) { @provider.get_zone('test.example.com') }
34
- end
35
-
36
- def test_create_record
37
- @connection.expects(:exec_params).
38
- with("INSERT INTO records (domain_id, name, ttl, content, type, change_date) VALUES ($1::int, $2, $3::int, $4, $5, extract(epoch from now()))", [1, 'test.example.com', 86400, '10.1.1.1', 'A']).
39
- returns(mock(:cmdtuples => 1))
40
-
41
- assert_true @provider.create_record(1, 'test.example.com', 'A', '10.1.1.1')
42
- end
43
-
44
- def test_delete_record_no_records
45
- mock_delete_tuples(0)
46
- assert_false run_delete_record
47
- end
48
-
49
- def test_delete_record_single_record
50
- mock_delete_tuples(1)
51
- mock_update_soa_tuples(1)
52
-
53
- assert_true run_delete_record
54
- end
55
-
56
- def test_delete_record_multiple_records
57
- mock_delete_tuples(2)
58
- mock_update_soa_tuples(1)
59
-
60
- assert_true run_delete_record
61
- end
62
-
63
- def test_delete_record_no_soa
64
- mock_delete_tuples(1)
65
- mock_update_soa_tuples(0)
66
- logger = mock()
67
- logger.expects(:info)
68
- @provider.stubs(:logger).returns(logger)
69
-
70
- assert_true run_delete_record
71
- end
72
-
73
- def test_delete_record_multiple_soa
74
- mock_delete_tuples(1)
75
- mock_update_soa_tuples(2)
76
- logger = mock()
77
- logger.expects(:warning)
78
- @provider.stubs(:logger).returns(logger)
79
-
80
- assert_true run_delete_record
81
- end
82
-
83
- private
84
-
85
- def mock_delete_tuples(cmdtuples)
86
- @connection.expects(:exec_params).
87
- with(query_delete, [domain_id, fqdn, record_type]).
88
- returns(mock(:cmdtuples => cmdtuples))
89
- end
90
-
91
- def mock_update_soa_tuples(cmdtuples)
92
- @connection.expects(:exec_params).
93
- with(query_update_soa, [domain_id]).
94
- returns(mock(:cmdtuples => cmdtuples))
95
- end
96
-
97
- def run_delete_record
98
- @provider.delete_record(domain_id, fqdn, record_type)
99
- end
100
-
101
- def domain
102
- 'example.com'
103
- end
104
-
105
- def fqdn
106
- "test.#{domain}"
107
- end
108
-
109
- def domain_id
110
- 1
111
- end
112
-
113
- def record_type
114
- 'A'
115
- end
116
-
117
- def query_delete
118
- "DELETE FROM records WHERE domain_id=$1::int AND name=$2 AND type=$3"
119
- end
120
-
121
- def query_update_soa
122
- "UPDATE records SET change_date=extract(epoch from now()) WHERE domain_id=$1::int AND type='SOA'"
123
- end
124
-
125
- end
@@ -1,67 +0,0 @@
1
- require 'test_helper'
2
- require 'webmock/test_unit'
3
-
4
- require 'smart_proxy_dns_powerdns/dns_powerdns_main'
5
- require 'smart_proxy_dns_powerdns/backend/rest'
6
-
7
- class DnsPowerdnsBackendRestTest < Test::Unit::TestCase
8
- def setup
9
- @provider = Proxy::Dns::Powerdns::Backend::Rest.new('localhost', 86400,
10
- 'http://localhost:8081/api/v1/servers/localhost',
11
- 'apikey')
12
- end
13
-
14
- def test_initialize
15
- assert_equal 86400, @provider.ttl
16
- assert_equal 'http://localhost:8081/api/v1/servers/localhost', @provider.url
17
- assert_equal 'apikey', @provider.api_key
18
- end
19
-
20
- def test_get_zone_with_existing_zone
21
- stub_request(:get, "http://localhost:8081/api/v1/servers/localhost/zones").
22
- with(:headers => {'X-Api-Key' => 'apikey'}).
23
- to_return(:body => '[{"id": "example.com.", "name": "example.com."}]')
24
- assert_equal @provider.get_zone('test.example.com'), {'id' => 'example.com.', 'name' => 'example.com.'}
25
- end
26
-
27
- def test_get_zone_with_existing_zone_absolute_record
28
- stub_request(:get, "http://localhost:8081/api/v1/servers/localhost/zones").
29
- with(:headers => {'X-Api-Key' => 'apikey'}).
30
- to_return(:body => '[{"id": "example.com.", "name": "example.com."}]')
31
- assert_equal @provider.get_zone('test.example.com.'), {'id' => 'example.com.', 'name' => 'example.com.'}
32
- end
33
-
34
- def test_get_zone_without_existing_zone
35
- stub_request(:get, "http://localhost:8081/api/v1/servers/localhost/zones").
36
- with(:headers => {'X-Api-Key' => 'apikey'}).
37
- to_return(:body => '[]')
38
- assert_raise(Proxy::Dns::Error) { @provider.get_zone('test.example.com') }
39
- end
40
-
41
- def test_create_a_record
42
- stub_request(:patch, "http://localhost:8081/api/v1/servers/localhost/zones/example.com.").
43
- with(
44
- :headers => {'X-Api-Key' => 'apikey', 'Content-Type' => 'application/json'},
45
- :body => '{"rrsets":[{"name":"test.example.com.","type":"A","ttl":86400,"changetype":"REPLACE","records":[{"content":"10.1.1.1","disabled":false}]}]}'
46
- )
47
- assert @provider.create_record('example.com.', 'test.example.com', 'A', '10.1.1.1')
48
- end
49
-
50
- def test_create_ptr_record
51
- stub_request(:patch, "http://localhost:8081/api/v1/servers/localhost/zones/example.com.").
52
- with(
53
- :headers => {'X-Api-Key' => 'apikey', 'Content-Type' => 'application/json'},
54
- :body => '{"rrsets":[{"name":"1.1.1.10.in-addr.arpa.","type":"PTR","ttl":86400,"changetype":"REPLACE","records":[{"content":"test.example.com.","disabled":false}]}]}'
55
- )
56
- assert @provider.create_record('example.com.', '1.1.1.10.in-addr.arpa', 'PTR', 'test.example.com')
57
- end
58
-
59
- def test_delete_record
60
- stub_request(:patch, "http://localhost:8081/api/v1/servers/localhost/zones/example.com.").
61
- with(
62
- :headers => {'X-Api-Key' => 'apikey', 'Content-Type' => 'application/json'},
63
- :body => '{"rrsets":[{"name":"test.example.com.","type":"A","changetype":"DELETE","records":[]}]}'
64
- )
65
- assert @provider.delete_record('example.com.', 'test.example.com', 'A')
66
- end
67
- end