Module: Aws::ENI::Client

Extended by:
Client
Included in:
Client
Defined in:
lib/aws-eni/client.rb

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

pass along method calls to our lazy-loaded api client



35
36
37
38
39
40
41
42
43
44
# 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

Instance Method Details

#available_addressesObject

retrieve a list of available addresses



79
80
81
82
# 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

#clientObject

lazy-load our ec2 client



26
27
28
29
30
31
32
# 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) ⇒ Object

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



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# 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) ⇒ Object

retrieve a single interface resource



47
48
49
50
51
# 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?Boolean

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

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# 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) ⇒ Object

determine whether a given interface is attached or free



97
98
99
# File 'lib/aws-eni/client.rb', line 97

def interface_attached(id)
  describe_interface(id)[:status] == 'in-use'
end

#interface_private_ips(id) ⇒ Object

retrieve an array of private ips associated with the given interface



85
86
87
88
89
90
91
92
93
94
# 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

#regionObject

determine the region from instance metadata



11
12
13
14
15
# 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_cidrObject

determine the vpc cidr block from instance metadata



18
19
20
21
22
23
# 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