module Aws::ENI::Client

Public Instance Methods

available_addresses() click to toggle source

retrieve a list of available addresses

# File lib/aws-eni/client.rb, line 79
def available_addresses
  filters = [{ name: 'domain', values: ['vpc'] }]
  describe_addresses(filters: filters)[:addresses].select{ |addr| !addr.association_id }
end
client() click to toggle source

lazy-load our ec2 client

# File lib/aws-eni/client.rb, line 26
def client
  @client ||= EC2::Client.new(region: region)
rescue Errors::ServiceError
  raise
rescue
  raise Errors::EnvironmentError, 'Unable to initialize EC2 client'
end
describe_address(address) click to toggle source

retrieve a single address resource by public ip, associated private ip, allocation id, or association id

# File lib/aws-eni/client.rb, line 55
def describe_address(address)
  filter_by = case address
    when /^eipalloc-/
      'allocation-id'
    when /^eipassoc-/
      'association-id'
    else
      if IPAddr.new(vpc_cidr) === IPAddr.new(address)
        'private-ip-address'
      else
        'public-ip'
      end
    end
  resp = describe_addresses(filters: [
    { name: 'domain', values: ['vpc'] },
    { name: filter_by, values: [address] }
  ])
  raise Errors::UnknownAddress, "No EIP with #{address} could be located" if resp[:addresses].empty?
  resp[:addresses].first
rescue IPAddr::InvalidAddressError
  raise Errors::InvalidAddress, "Invalid address: #{address}"
end
describe_interface(id) click to toggle source

retrieve a single interface resource

# File lib/aws-eni/client.rb, line 47
def describe_interface(id)
  resp = describe_network_interfaces(filters: [{ name: 'network-interface-id', values: [id] }])
  raise Errors::UnknownInterface, "Interface #{id} could not be located" if resp[:network_interfaces].empty?
  resp[:network_interfaces].first
end
has_access?() click to toggle source

test whether we have the appropriate permissions within our AWS access credentials to perform all possible API calls

# File lib/aws-eni/client.rb, line 103
def has_access?
  test_methods = {
    describe_network_interfaces: {},
    create_network_interface: {
      subnet_id: 'subnet-abcd1234'
    },
    attach_network_interface: {
      network_interface_id: 'eni-abcd1234',
      instance_id: 'i-abcd1234',
      device_index: 0
    },
    detach_network_interface: {
      attachment_id: 'eni-attach-abcd1234'
    },
    delete_network_interface: {
      network_interface_id: 'eni-abcd1234'
    },
    create_tags: {
      resources: ['eni-abcd1234'],
      tags: []
    },
    describe_addresses: {},
    allocate_address: {},
    release_address: {
      allocation_id: 'eipalloc-abcd1234'
    },
    associate_address: {
      allocation_id: 'eipalloc-abcd1234',
      network_interface_id: 'eni-abcd1234'
    },
    disassociate_address: {
      association_id: 'eipassoc-abcd1234'
    }
    # these have no dry_run method
    # assign_private_ip_addresses: {
    #   network_interface_id: 'eni-abcd1234'
    # }
    # unassign_private_ip_addresses: {
    #   network_interface_id: 'eni-abcd1234',
    #   private_ip_addresses: ['0.0.0.0']
    # }
  }
  test_methods.all? do |method, params|
    begin
      client.public_send(method, params.merge(dry_run: true))
    rescue EC2::Errors::DryRunOperation
      true
    rescue EC2::Errors::InvalidAllocationIDNotFound, EC2::Errors::InvalidAssociationIDNotFound
      true
    rescue EC2::Errors::UnauthorizedOperation
      false
    rescue EC2::Errors::ServiceError
      # raise Errors::ClientOperationError, 'Unexpected behavior while testing EC2 client permissions'
      true
    else
      raise Errors::ClientOperationError, 'Unexpected behavior while testing EC2 client permissions'
    end
  end
end
interface_attached(id) click to toggle source

determine whether a given interface is attached or free

# File lib/aws-eni/client.rb, line 97
def interface_attached(id)
  describe_interface(id)[:status] == 'in-use'
end
interface_private_ips(id) click to toggle source

retrieve an array of private ips associated with the given interface

# File lib/aws-eni/client.rb, line 85
def interface_private_ips(id)
  interface = describe_interface(id)
  if interface[:private_ip_addresses]
    primary = interface[:private_ip_addresses].find { |ip| ip[:primary] }
    interface[:private_ip_addresses].map { |ip| ip[:private_ip_address] }.tap do |ips|
      # ensure primary ip is first in the list
      ips.unshift(*ips.delete(primary[:private_ip_address])) if primary
    end
  end
end
method_missing(method, *args) click to toggle source

pass along method calls to our lazy-loaded api client

# File lib/aws-eni/client.rb, line 35
def method_missing(method, *args)
  client.public_send(method, *args)
rescue EC2::Errors::AttachmentLimitExceeded, EC2::Errors::PrivateIpAddressLimitExceeded, EC2::Errors::AddressLimitExceeded => e
  raise Errors::LimitExceeded, "Limit exceeded: #{e.message}"
rescue EC2::Errors::UnauthorizedOperation => e
  raise Errors::ClientPermissionError, "Operation not permitted: #{e.message}"
rescue EC2::Errors::ServiceError => e
  error = e.class.to_s.gsub(/^.*::/, '')
  raise Errors::ClientOperationError, "EC2 service error (#{error}: #{e.message})"
end
region() click to toggle source

determine the region from instance metadata

# File lib/aws-eni/client.rb, line 11
def region
  Meta.instance('placement/availability-zone').sub(/^(.*)[a-z]$/,'\1')
rescue Errors::MetaConnectionFailed
  raise Errors::EnvironmentError, 'Unable to load EC2 meta-data'
end
vpc_cidr() click to toggle source

determine the vpc cidr block from instance metadata

# File lib/aws-eni/client.rb, line 18
def vpc_cidr
  hwaddr = Meta.instance('network/interfaces/macs/').lines.first.strip.chomp('/')
  Meta.interface(hwaddr, 'vpc-ipv4-cidr-block')
rescue Errors::MetaConnectionFailed, Errors::MetaNotFound
  raise Errors::EnvironmentError, 'Unable to load EC2 meta-data'
end