Class: RecordStore::Zone

Inherits:
Object
  • Object
show all
Extended by:
YamlDefinitions
Includes:
ActiveModel::Validations
Defined in:
lib/record_store/zone.rb,
lib/record_store/zone/config.rb,
lib/record_store/zone/yaml_definitions.rb,
lib/record_store/zone/config/ignore_pattern.rb,
lib/record_store/zone/config/implicit_record_template.rb

Defined Under Namespace

Modules: YamlDefinitions Classes: Config

Constant Summary collapse

DEFAULT_MAX_PARALLEL_THREADS =
10
ROOT_SERVERS =
%w(
  a.root-servers.net
  b.root-servers.net
  c.root-servers.net
  d.root-servers.net
  e.root-servers.net
  f.root-servers.net
  g.root-servers.net
  h.root-servers.net
  i.root-servers.net
  j.root-servers.net
  k.root-servers.net
  l.root-servers.net
  m.root-servers.net
)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from YamlDefinitions

[], defined, each, find, reset

Constructor Details

#initialize(name:, records: [], config: {}, abstract_syntax_trees: {}) ⇒ Zone

Returns a new instance of Zone.



81
82
83
84
85
86
# File 'lib/record_store/zone.rb', line 81

def initialize(name:, records: [], config: {}, abstract_syntax_trees: {})
  @name = Record.ensure_ends_with_dot(name)
  @config = RecordStore::Zone::Config.new(**config.deep_symbolize_keys)
  @records = build_records(records)
  @abstract_syntax_trees = abstract_syntax_trees
end

Instance Attribute Details

#configObject

Returns the value of attribute config.



7
8
9
# File 'lib/record_store/zone.rb', line 7

def config
  @config
end

#nameObject

Returns the value of attribute name.



6
7
8
# File 'lib/record_store/zone.rb', line 6

def name
  @name
end

Class Method Details

.download(name, provider_name, **write_options) ⇒ Object

Raises:

  • (ArgumentError)


28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/record_store/zone.rb', line 28

def download(name, provider_name, **write_options)
  zone = Zone.new(name: name, config: { providers: [provider_name] })
  raise ArgumentError, zone.errors.full_messages.join("\n") unless zone.valid?

  zone.records = zone.providers.first.retrieve_current_records(zone: name)

  zone.config = Zone::Config.new(
    providers: [provider_name],
    ignore_patterns: [{ type: "NS", fqdn: "#{name}." }],
    supports_alias: zone.records.map(&:type).include?('ALIAS') || nil,
  )

  zone.write(**write_options)
end

.filter_records(current_records, ignore_patterns) ⇒ Object



43
44
45
46
47
48
49
# File 'lib/record_store/zone.rb', line 43

def filter_records(current_records, ignore_patterns)
  ignore_patterns.inject(current_records) do |remaining_records, pattern|
    remaining_records.reject do |record|
      pattern.ignore?(record)
    end
  end
end

.max_parallel_threadsObject



53
54
55
# File 'lib/record_store/zone.rb', line 53

def max_parallel_threads
  (ENV['RECORD_STORE_MAX_THREADS'] || DEFAULT_MAX_PARALLEL_THREADS).to_i
end

.modified(verbose: false) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/record_store/zone.rb', line 57

def modified(verbose: false)
  modified_zones = []
  mutex = Mutex.new
  zones = all

  (1..max_parallel_threads).map do
    Thread.new do
      current_zone = nil
      while zones.any?
        mutex.synchronize { current_zone = zones.shift }
        break if current_zone.nil? # account for the race between `zones.any?` and `zones.shift`

        # `unchanged?` is deliberately outside locked context since it's a bit CPU/time heavy
        unless current_zone.unchanged?
          mutex.synchronize { modified_zones << current_zone }
        end
      end
    end
  end.each(&:join)

  modified_zones
end

Instance Method Details

#allObject



102
103
104
# File 'lib/record_store/zone.rb', line 102

def all
  @records
end

#build_changesets(all: false) ⇒ Object



88
89
90
91
92
# File 'lib/record_store/zone.rb', line 88

def build_changesets(all: false)
  @changesets ||= providers.map do |provider|
    Changeset.build_from(provider: provider, zone: self, all: all)
  end
end

#fetch_authority(nameserver = ROOT_SERVERS.sample) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/record_store/zone.rb', line 144

def fetch_authority(nameserver = ROOT_SERVERS.sample)
  authority = fetch_soa(nameserver) do |reply, _name|
    break if reply.answer.any?

    raise "No authority found (#{name})" if reply.authority.none?

    break extract_authority(reply.authority)
  end

  # candidate DNS name is returned instead when NXDomain or other error
  return if unrooted_name.casecmp?(Array(authority).first.to_s)

  authority
end

#providersObject



120
121
122
# File 'lib/record_store/zone.rb', line 120

def providers
  @providers ||= config.providers.map { |provider| Provider.const_get(provider) }
end

#recordsObject



106
107
108
# File 'lib/record_store/zone.rb', line 106

def records
  @records_cache ||= Zone.filter_records(@records, config.ignore_patterns)
end

#records=(records) ⇒ Object



110
111
112
113
# File 'lib/record_store/zone.rb', line 110

def records=(records)
  @records_cache = nil
  @records = records
end

#unchanged?Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/record_store/zone.rb', line 94

def unchanged?
  build_changesets.all?(&:empty?)
end

#unrooted_nameObject



98
99
100
# File 'lib/record_store/zone.rb', line 98

def unrooted_name
  @name.chomp('.')
end

#write(**write_options) ⇒ Object



124
125
126
# File 'lib/record_store/zone.rb', line 124

def write(**write_options)
  self.class.write(name, config: config, records: records, **write_options)
end