smart_proxy_dns_powerdns 0.4.0 → 1.0.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 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