class Zonify::AWS

Set up for AWS interfaces and access to EC2 instance metadata.

Attributes

ec2_proc[R]
elb_proc[R]
r53_proc[R]

Public Class Methods

create(options) click to toggle source

Initialize all AWS interfaces with the same access keys and logger (probably what you want to do). These are set up lazily; unused interfaces will not be initialized.

# File lib/zonify.rb, line 19
def create(options)
  options_ec2 = options.merge( :provider=>'AWS',
                               :connection_options=>{:nonblock=>false} )
  options_ec2.delete(:reverse)
  options_ec2.delete(:zone)
  ec2 = Proc.new{|| Fog::Compute.new(options_ec2) }
  options_elb = options_ec2.dup.delete_if{|k, _| k == :provider }
  elb = Proc.new{|| Fog::AWS::ELB.new(options_elb) }
  options_r53 = options_ec2.dup.delete_if{|k, _| k == :region }
  r53 = Proc.new{|| Fog::DNS.new(options_r53) }
  options.merge!(:ec2_proc=>ec2, :elb_proc=>elb, :r53_proc=>r53)
  Zonify::AWS.new(options)
end
local_instance_id() click to toggle source

Retrieve the EC2 instance ID of this instance.

# File lib/zonify.rb, line 12
def local_instance_id
  s = `curl -s http://169.254.169.254/latest/meta-data/instance-id`
  s.strip if $?.success?
end
new(opts={}) click to toggle source
# File lib/zonify.rb, line 34
def initialize(opts={})
  @ec2      = opts[:ec2]
  @elb      = opts[:elb]
  @r53      = opts[:r53]
  @ec2_proc = opts[:ec2_proc]
  @elb_proc = opts[:elb_proc]
  @r53_proc = opts[:r53_proc]
  @reverse  = opts[:reverse]
  @zone     = opts[:zone]
end

Public Instance Methods

apply(changes, comment='Synced with Zonify tool.') click to toggle source

Apply a changeset to the records in Route53. The records must all be under the same zone and suffix.

# File lib/zonify.rb, line 84
def apply(changes, comment='Synced with Zonify tool.')
  filtered = changes.select{|change| change[:value].length > 100 }
  # For all the SRV records that were considered too long, get the names of
  # the associated weighted CNAMEs.
  filtered_correlates = filtered.map do |change|
    case change[:name]
    when /^_[*][.]_[*][.]/
      change[:name][6, change[:name].length]
    end
  end.compact
  keep = changes.select do |change|
    change[:value].length <= 100 and not
      filtered_correlates.include?(change[:name])
  end
  unless keep.empty?
    suffix  = keep.first[:name] # Works because of longest submatch rule.
    zone, _ = route53_zone(suffix)
    Zonify.chunk_changesets(keep).each do |changeset|
      rekeyed = changeset.map do |record|
        record.inject({}) do |acc, pair|
          k, v = pair
          k_ = k == :value ? :resource_records : k
          acc[k_] = v
          acc
        end
      end
      begin
        r53.change_resource_record_sets(zone.id, rekeyed, :comment=>comment)
      rescue Fog::Errors::Error => e
        STDERR.puts("Failed with some records, due to:\n#{e}")
      end
    end
  end
  filtered
end
ec2() click to toggle source
# File lib/zonify.rb, line 47
def ec2
  @ec2 ||= @ec2_proc.call
end
ec2_zone() click to toggle source

Generate DNS entries based on EC2 instances, security groups and ELB load balancers under the user's AWS account.

# File lib/zonify.rb, line 58
def ec2_zone
  Zonify.tree(Zonify.zone(instances, load_balancers))
end
eip_scan() click to toggle source
# File lib/zonify.rb, line 152
def eip_scan
  addresses = eips.map{|eip| eip.public_ip }
  result = {}
  addresses.each{|a| result[a] = [] }
  r53.zones.sort_by{|zone| zone.domain.reverse }.each do |zone|
    zone.records.all!.each do |rr|
      check = case rr.type
              when 'CNAME'
                rr.value.map do |s|
                  Zonify.ec2_dns_to_ip(s)
                end.compact
              when 'A','AAAA'
                rr.value
              end
      check ||= []
      found = addresses.select{|a| check.member? a }.sort
      unless found.empty?
        name = Zonify.read_octal(rr.name)
        found.each{|a| result[a] << name }
      end
    end
  end
  result
end
eips() click to toggle source
# File lib/zonify.rb, line 149
def eips
  ec2.addresses
end
elb() click to toggle source
# File lib/zonify.rb, line 50
def elb
  @elb ||= @elb_proc.call
end
instances() click to toggle source
# File lib/zonify.rb, line 119
def instances
  ec2.servers.inject({}) do |acc, i|
    dns = if reverse_public_ip? and not i.public_ip_address.nil?
            pub = i.public_ip_address
            dns = "ec2-#{pub.gsub(".", "-")}.compute-1.amazonaws.com"
          else
            i.dns_name or i.private_dns_name
          end
    # The default hostname for EC2 instances is derived from their internal
    # DNS entry.
    terminal_states = %w| terminated shutting-down |
    unless dns.nil? or dns.empty? or terminal_states.member? i.state
      groups = (i.groups or [])
      attrs = { :sg => groups,
                :tags => (i.tags or []),
                :dns => Zonify.dot_(dns).downcase }
      if i.private_dns_name
        attrs[:priv] = i.private_dns_name.split('.').first.downcase
      end
      acc[i.id] = attrs
    end
    acc
  end
end
load_balancers() click to toggle source
# File lib/zonify.rb, line 143
def load_balancers
  elb.load_balancers.map do |elb|
    { :instances => elb.instances,
      :prefix    => Zonify.cut_down_elb_name(elb.dns_name.downcase) }
  end
end
r53() click to toggle source
# File lib/zonify.rb, line 53
def r53
  @r53 ||= @r53_proc.call
end
reverse_public_ip?() click to toggle source
# File lib/zonify.rb, line 44
def reverse_public_ip?
  !!@reverse
end
route53_zone(suffix) click to toggle source

Retrieve Route53 zone data – the zone ID as well as resource records – relevant to the given suffix. When there is any ambiguity, the zone with the longest name is chosen.

# File lib/zonify.rb, line 64
def route53_zone(suffix)
  suffix_ = Zonify.dot_(suffix)
  relevant_zone = r53.zones.select do |zone|
    if @zone
      @zone == zone.id
    else
      suffix_.end_with?(zone.domain)
    end
  end.sort_by{|zone| zone.domain.length }.last
  if relevant_zone
    relevant_records = relevant_zone.records.all!.map do |rr|
      if rr.name.end_with?(suffix_)
        rr.attributes.merge(:name=>Zonify.read_octal(rr.name))
      end
    end.compact
    [relevant_zone, Zonify.tree_from_right_aws(relevant_records)]
  end
end