Page MenuHomeGRNET

No OneTemporary

File Metadata

Created
Sun, May 18, 4:36 PM
diff --git a/app/models/domain.rb b/app/models/domain.rb
index ca828fb..2fdf4c6 100644
--- a/app/models/domain.rb
+++ b/app/models/domain.rb
@@ -1,28 +1,33 @@
class Domain < ActiveRecord::Base
self.inheritance_column = :nx
def self.domain_types
[
'NATIVE',
'MASTER',
'SLAVE',
]
end
has_many :records
has_one :soa, class_name: SOA
validates :name, uniqueness: true, presence: true
validates :type, presence: true, inclusion: { in: domain_types }
after_create :generate_soa
+ attr_writer :serial_strategy
+ def serial_strategy
+ @serial_strategy ||= WebDNS.settings[:serial_strategy]
+ end
+
private
# Hooks
def generate_soa
soa_record = SOA.new(domain: self)
soa_record.save
end
end
diff --git a/app/models/soa.rb b/app/models/soa.rb
index 8cf823d..bac20ac 100644
--- a/app/models/soa.rb
+++ b/app/models/soa.rb
@@ -1,73 +1,77 @@
class SOA < Record
validates :domain_id, uniqueness: true
validates_numericality_of :serial, :refresh, :retry, :expire
validates_presence_of :contact
SOA_DEFAULTS = WebDNS.settings[:soa_defaults]
SOA_FIELDS = SOA_DEFAULTS.keys
SOA_FIELDS.each { |soa_entry|
attr_accessor soa_entry
}
# Handle SOA Fields
after_initialize :set_soa_fields
# Load soa fields on reload
def reload_with_soa_fields(*args)
reload_without_soa_fields(*args).tap {
set_soa_fields
}
end
alias_method_chain :reload, :soa_fields
before_validation :set_content
before_validation :update_serial, on: :update
def bump_serial!
with_lock {
reload
- self.serial += 1
+ generate_serial
save!
}
end
def serial_changed?
return false if not self.content_changed?
serial_index = SOA_FIELDS.index(:serial)
old, new = content_change.map { |c|
(c || '').split(/\s+/)[serial_index]
}
old != new
end
private
+ def generate_serial
+ self.serial = domain.serial_strategy.generate_serial(serial)
+ end
+
# Callbacks
def set_soa_fields
content_values = (content || '').split(/\s+/)
SOA_DEFAULTS.each { |field, default_value|
val = content_values.shift || default_value
val = Integer(val) if default_value.is_a?(Integer)
send("#{field}=", val)
}
end
def set_content
self.content = SOA_FIELDS.map { |field| send(field) }.join(' ')
end
def update_serial
# Don't update if nothing has changed
return if not self.content_changed?
# Don't updade if serial is already changed
return if self.serial_changed?
- self.serial += 1
+ generate_serial
set_content
end
end
diff --git a/config/initializers/00_settings.rb b/config/initializers/00_settings.rb
index 991c443..88695d4 100644
--- a/config/initializers/00_settings.rb
+++ b/config/initializers/00_settings.rb
@@ -1,12 +1,13 @@
WebDNS = Base
WebDNS.settings[:soa_defaults] = {
primary_ns: 'ns.example.com',
contact: 'domainmaster@example.com',
serial: 1,
refresh: 10_800,
retry: 3600,
expire: 604_800,
nx: 3600
}
+WebDNS.settings[:serial_strategy] = Strategies::Date
diff --git a/lib/strategies/date.rb b/lib/strategies/date.rb
new file mode 100644
index 0000000..ed4e145
--- /dev/null
+++ b/lib/strategies/date.rb
@@ -0,0 +1,19 @@
+module Strategies
+ module Date
+ module_function
+
+ def generate_serial(current_serial)
+ # Optimization for the case that current_serial is a lot larger
+ # than the generated serial
+ new = [
+ Time.now.strftime('%Y%m%d00').to_i,
+ current_serial
+ ].max
+
+ # Increment until we find a spot
+ new += 1 while new <= current_serial
+
+ new
+ end
+ end
+end
diff --git a/lib/strategies/incremental.rb b/lib/strategies/incremental.rb
new file mode 100644
index 0000000..75a4772
--- /dev/null
+++ b/lib/strategies/incremental.rb
@@ -0,0 +1,9 @@
+module Strategies
+ module Incremental
+ module_function
+
+ def generate_serial(current_serial)
+ current_serial + 1
+ end
+ end
+end
diff --git a/test/factories/domain.rb b/test/factories/domain.rb
index f216127..6ff5abf 100644
--- a/test/factories/domain.rb
+++ b/test/factories/domain.rb
@@ -1,7 +1,14 @@
FactoryGirl.define do
sequence(:domain) { |n| "example#{n}.com" }
factory :domain do
name { generate(:domain) }
+ serial_strategy Strategies::Date
+ type 'NATIVE'
+ end
+
+ factory :date_domain, class: Domain do
+ name { generate(:domain) }
+ serial_strategy Strategies::Date
type 'NATIVE'
end
end
diff --git a/test/models/soa_test.rb b/test/models/soa_test.rb
index 3ad4cfa..a96a30f 100644
--- a/test/models/soa_test.rb
+++ b/test/models/soa_test.rb
@@ -1,25 +1,60 @@
require 'test_helper'
class SOATest < ActiveSupport::TestCase
def setup
domain = create(:domain)
@record = domain.soa
end
test 'bump_serial!' do
@record.save!
assert_serial_update @record do
@record.bump_serial!
end
end
test 'updating attributes bumps serial' do
@record.save!
assert_serial_update @record do
@record.contact = 'admin@example.com'
@record.save!
end
end
+
+ class DateSerialTests < ActiveSupport::TestCase
+ setup do
+ domain = create(:date_domain)
+ @record = domain.soa
+ end
+
+ test 'last bump of the day' do
+ assert_equal Strategies::Date, @record.domain.serial_strategy
+
+ freeze_time do
+ last_for_day = Time.now.strftime('%Y%m%d99').to_i
+ @record.serial = last_for_day
+ @record.save!
+
+ assert_serial_update @record do
+ @record.bump_serial!
+ end
+ end
+ end
+
+ test 'existing serial points to a future date' do
+ assert_equal Strategies::Date, @record.domain.serial_strategy
+
+ freeze_time do
+ future_day = (Time.now + 1.week).strftime('%Y%m%d00').to_i
+ @record.serial = future_day
+ @record.save!
+
+ assert_serial_update @record do
+ @record.bump_serial!
+ end
+ end
+ end
+ end
end

Event Timeline