class Google::Cloud::Dns::Importer

@private # DNS Importer

Reads a [DNS zone file](en.wikipedia.org/wiki/Zone_file) and parses it, creating a collection of Record instances. The returned records are unsaved, as they are not yet associated with a Zone. Use {Zone#import} to add zone file records to a Zone.

Because the Google Cloud DNS API only accepts a single resource record for each `name` and `type` combination (with multiple `data` elements), the zone file's records are merged as necessary. During this merge, the lowest `ttl` of the merged records is used. If none of the merged records have a `ttl` value, the zone file's global TTL is used for the record.

The following record types are supported: A, AAAA, CNAME, MX, NAPTR, NS, PTR, SOA, SPF, SRV, and TXT.

Public Class Methods

new(zone, path_or_io) click to toggle source

Creates a new Importer that immediately parses the provided zone file data and creates Record instances.

@param [String, IO] path_or_io The path to a zone file on the

filesystem, or an IO instance from which zone file data can be read.
# File lib/google/cloud/dns/importer.rb, line 48
def initialize zone, path_or_io
  @zone = zone
  @merged_zf_records = {}
  @records = []
  @zonefile = create_zonefile path_or_io
  merge_zonefile_records
  from_zonefile_records
  @records.unshift soa_record
end

Public Instance Methods

records(only: nil, except: nil) click to toggle source

Returns the Record instances created from the zone file.

@param [String, Array<String>] only Include only records of this type

or types.

@param [String, Array<String>] except Exclude records of this type or

types.

@return [Array<Record>] An array of unsaved {Record} instances

# File lib/google/cloud/dns/importer.rb, line 68
def records only: nil, except: nil
  ret = @records
  ret = ret.select { |r| Array(only).include? r.type } if only
  ret = ret.reject { |r| Array(except).include? r.type } if except
  ret
end

Protected Instance Methods

data_from_zonefile_record(type, zf_record) click to toggle source

Rubocop's line-length and branch condition restrictions prevent the most straightforward approach to converting zonefile's records to our own. So disable rubocop for this operation.

# File lib/google/cloud/dns/importer.rb, line 131
def data_from_zonefile_record type, zf_record
  case type.to_s.upcase
  when "A"
    String zf_record[:host]
  when "AAAA"
    String zf_record[:host]
  when "CNAME"
    String zf_record[:host]
  when "MX"
    "#{zf_record[:pri]} #{zf_record[:host]}"
  when "NAPTR"
    "#{zf_record[:order]} #{zf_record[:preference]} " \
      "#{zf_record[:flags]} #{zf_record[:service]} " \
      "#{zf_record[:regexp]} #{zf_record[:replacement]}"
  when "NS"
    String zf_record[:host]
  when "PTR"
    String zf_record[:host]
  when "SOA"
    "#{zf_record[:primary]} #{zf_record[:email]} " \
      "#{zf_record[:serial]} #{zf_record[:refresh]} " \
      "#{zf_record[:retry]} #{zf_record[:expire]} " \
      "#{zf_record[:minimumTTL]}"
  when "SPF"
    String zf_record[:data]
  when "SRV"
    "#{zf_record[:pri]} #{zf_record[:weight]} " \
      "#{zf_record[:port]} #{zf_record[:host]}"
  when "TXT"
    String zf_record[:text]
  else
    raise ArgumentError, "record type '#{type}' is not supported"
  end
end
from_zonefile_records() click to toggle source

Convert the grouped records to single array of records, merging records of the same name and type into a single record with an array of rrdatas.

# File lib/google/cloud/dns/importer.rb, line 98
def from_zonefile_records
  @records = @merged_zf_records.map do |key, zf_records|
    ttl = ttl_from_zonefile_records zf_records
    data = zf_records.map do |zf_record|
      data_from_zonefile_record key[1], zf_record
    end
    @zone.record key[0], key[1], ttl, data
  end
end
merge_zonefile_records() click to toggle source

The zonefile library returns a two-element array in which the first element is a symbol type (:a, :mx, and so on), and the second element is an array containing the records of that type. Group the records by name and type instead.

# File lib/google/cloud/dns/importer.rb, line 82
def merge_zonefile_records
  @zonefile.records.map do |r|
    type = r.first
    type = :aaaa if type == :a4
    r.last.each do |zf_record|
      name = Service.fqdn zf_record[:name], @zonefile.origin
      key = [name, type]
      (@merged_zf_records[key] ||= []) << zf_record
    end
  end
end
soa_record() click to toggle source
# File lib/google/cloud/dns/importer.rb, line 108
def soa_record
  zf_soa = @zonefile.soa
  ttl = ttl_to_i(zf_soa[:ttl]) || ttl_to_i(@zonefile.ttl)
  data = data_from_zonefile_record :soa, zf_soa
  @zone.record zf_soa[:origin], "SOA", ttl, data
end
ttl_from_zonefile_records(zf_records) click to toggle source

From a collection of records, take the lowest ttl

# File lib/google/cloud/dns/importer.rb, line 117
def ttl_from_zonefile_records zf_records
  ttls = zf_records.map do |zf_record|
    ttl_to_i zf_record[:ttl]
  end
  min_ttl = ttls.compact.min
  min_ttl || ttl_to_i(@zonefile.ttl)
end
ttl_to_i(ttl) click to toggle source
# File lib/google/cloud/dns/importer.rb, line 176
def ttl_to_i ttl
  if ttl.respond_to?(:to_int) || ttl.to_s =~ /\A\d+\z/
    ttl.to_i
  elsif (m = /\A(\d+)(w|d|h|m|s)\z/.match ttl)
    m[1].to_i * MULTIPLIER[m[2]].to_i
  end
end