MovableInkAWS 2.2.0 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7b1d77334dfeeb0283ce569cb62b7bce8a2518de96c73156f2b25693f0a2168
4
- data.tar.gz: 56b60538a821c7fab3e55ad7ee0a80ac85312ff003521764e0721dcf86d5577c
3
+ metadata.gz: d5b1e204235285ad22ef1eabe26e765a93cd4025680d9f5eaa1167a053510e3d
4
+ data.tar.gz: f28f6c72bf9b1b954a9400aeb1ffe1dc62b4f7984ccb36ec1ca3d30b3bb9c681
5
5
  SHA512:
6
- metadata.gz: 4132433dd73377d07d141297180ec17f983c4f124811ef45e474a78aa31d493d44ec2df98ed393707d13b095821182e54fcbcf23eff61f924d915aaf4eec1edd
7
- data.tar.gz: e317ad0ac916a54ffd6042310906310ea5be40f3b6b88f83b3f8c6b45364bcea3df1282c5106a5d9032cf1804137e1c03002fd0cbc7942142ca2f7ec45245798
6
+ metadata.gz: fcd12a5ab67c2d0c409d3689d9e3daafa942fbaa3c679ae693355b1db4293ecabd00150b67706adc65250bb438e7f021e5d436261bb607d6d2bcb319eadb3758
7
+ data.tar.gz: f2e78bbfc703c0b82c2d1678d363031a9da107c800b5dc8c62b17e7c2e432ffdcaf376e99a6e62e6d2916ed7bead4d409aad07ff0e257e56562c3b0b5d35cf55
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- MovableInkAWS (2.2.0)
4
+ MovableInkAWS (2.3.2)
5
5
  aws-sdk-athena (~> 1)
6
6
  aws-sdk-autoscaling (~> 1)
7
7
  aws-sdk-cloudwatch (~> 1)
@@ -23,51 +23,51 @@ GEM
23
23
  specs:
24
24
  addressable (2.7.0)
25
25
  public_suffix (>= 2.0.2, < 5.0)
26
- aws-eventstream (1.1.0)
27
- aws-partitions (1.416.0)
28
- aws-sdk-athena (1.33.0)
29
- aws-sdk-core (~> 3, >= 3.109.0)
26
+ aws-eventstream (1.1.1)
27
+ aws-partitions (1.445.0)
28
+ aws-sdk-athena (1.37.0)
29
+ aws-sdk-core (~> 3, >= 3.112.0)
30
30
  aws-sigv4 (~> 1.1)
31
- aws-sdk-autoscaling (1.53.0)
32
- aws-sdk-core (~> 3, >= 3.109.0)
31
+ aws-sdk-autoscaling (1.60.0)
32
+ aws-sdk-core (~> 3, >= 3.112.0)
33
33
  aws-sigv4 (~> 1.1)
34
- aws-sdk-cloudwatch (1.47.0)
35
- aws-sdk-core (~> 3, >= 3.109.0)
34
+ aws-sdk-cloudwatch (1.51.0)
35
+ aws-sdk-core (~> 3, >= 3.112.0)
36
36
  aws-sigv4 (~> 1.1)
37
- aws-sdk-core (3.111.0)
37
+ aws-sdk-core (3.114.0)
38
38
  aws-eventstream (~> 1, >= 1.0.2)
39
39
  aws-partitions (~> 1, >= 1.239.0)
40
40
  aws-sigv4 (~> 1.1)
41
41
  jmespath (~> 1.0)
42
- aws-sdk-ec2 (1.220.0)
43
- aws-sdk-core (~> 3, >= 3.109.0)
42
+ aws-sdk-ec2 (1.234.0)
43
+ aws-sdk-core (~> 3, >= 3.112.0)
44
44
  aws-sigv4 (~> 1.1)
45
- aws-sdk-eks (1.46.0)
46
- aws-sdk-core (~> 3, >= 3.109.0)
45
+ aws-sdk-eks (1.51.0)
46
+ aws-sdk-core (~> 3, >= 3.112.0)
47
47
  aws-sigv4 (~> 1.1)
48
- aws-sdk-elasticache (1.50.0)
49
- aws-sdk-core (~> 3, >= 3.109.0)
48
+ aws-sdk-elasticache (1.55.0)
49
+ aws-sdk-core (~> 3, >= 3.112.0)
50
50
  aws-sigv4 (~> 1.1)
51
- aws-sdk-kms (1.41.0)
52
- aws-sdk-core (~> 3, >= 3.109.0)
51
+ aws-sdk-kms (1.43.0)
52
+ aws-sdk-core (~> 3, >= 3.112.0)
53
53
  aws-sigv4 (~> 1.1)
54
- aws-sdk-rds (1.110.0)
55
- aws-sdk-core (~> 3, >= 3.109.0)
54
+ aws-sdk-rds (1.118.0)
55
+ aws-sdk-core (~> 3, >= 3.112.0)
56
56
  aws-sigv4 (~> 1.1)
57
- aws-sdk-route53 (1.45.0)
58
- aws-sdk-core (~> 3, >= 3.109.0)
57
+ aws-sdk-route53 (1.49.0)
58
+ aws-sdk-core (~> 3, >= 3.112.0)
59
59
  aws-sigv4 (~> 1.1)
60
- aws-sdk-s3 (1.87.0)
61
- aws-sdk-core (~> 3, >= 3.109.0)
60
+ aws-sdk-s3 (1.93.1)
61
+ aws-sdk-core (~> 3, >= 3.112.0)
62
62
  aws-sdk-kms (~> 1)
63
63
  aws-sigv4 (~> 1.1)
64
- aws-sdk-sns (1.36.0)
65
- aws-sdk-core (~> 3, >= 3.109.0)
64
+ aws-sdk-sns (1.39.0)
65
+ aws-sdk-core (~> 3, >= 3.112.0)
66
66
  aws-sigv4 (~> 1.1)
67
- aws-sdk-ssm (1.102.0)
68
- aws-sdk-core (~> 3, >= 3.109.0)
67
+ aws-sdk-ssm (1.108.0)
68
+ aws-sdk-core (~> 3, >= 3.112.0)
69
69
  aws-sigv4 (~> 1.1)
70
- aws-sigv4 (1.2.2)
70
+ aws-sigv4 (1.2.3)
71
71
  aws-eventstream (~> 1, >= 1.0.2)
72
72
  crack (0.4.3)
73
73
  safe_yaml (~> 1.0.0)
@@ -85,7 +85,7 @@ GEM
85
85
  jmespath (1.4.0)
86
86
  mime-types (3.3.1)
87
87
  mime-types-data (~> 3.2015)
88
- mime-types-data (3.2020.1104)
88
+ mime-types-data (3.2021.0225)
89
89
  multi_xml (0.6.0)
90
90
  multipart-post (2.1.1)
91
91
  public_suffix (4.0.5)
@@ -124,31 +124,60 @@ module MovableInk
124
124
  # consul service naming conventions while still retaining the role name we use
125
125
  # within MI configuration
126
126
  Diplomat::Health.service(role.gsub('_', '-'), consul_service_options).map { |endpoint|
127
- OpenStruct.new (
128
- {
129
- private_ip_address: endpoint.Node['Address'],
130
- instance_id: endpoint.Node['Meta']['instance_id'],
131
- tags: [
132
- {
133
- key: 'Name',
134
- value: endpoint.Node['Node']
135
- },
136
- {
137
- key: 'mi:roles',
138
- value: endpoint.Node['Meta']['mi_roles']
139
- },
140
- {
141
- key: 'mi:monitoring_roles',
142
- value: endpoint.Node['Meta']['mi_monitoring_roles']
143
- }
144
- ],
145
- placement: {
146
- availability_zone: endpoint.Node['Meta']['availability_zone']
147
- }
148
- })
127
+ if endpoint.Node.dig('Meta', 'external-source') == 'kubernetes'
128
+ map_k8s_consul_endpoint(endpoint, role)
129
+ else
130
+ map_ec2_consul_endpoint(endpoint)
131
+ end
149
132
  }
150
133
  end
151
134
 
135
+ def map_k8s_consul_endpoint(endpoint, role)
136
+ OpenStruct.new ({
137
+ private_ip_address: endpoint.Service.dig('Address'),
138
+ instance_id: nil,
139
+ tags: [
140
+ {
141
+ key: 'Name',
142
+ value: endpoint.Service.dig('ID')
143
+ },
144
+ {
145
+ key: 'mi:roles',
146
+ value: role
147
+ },
148
+ {
149
+ key: 'mi:monitoring_roles',
150
+ value: role
151
+ }
152
+ ],
153
+ placement: { availability_zone: nil }
154
+ })
155
+ end
156
+
157
+ def map_ec2_consul_endpoint(endpoint)
158
+ OpenStruct.new ({
159
+ private_ip_address: endpoint.Node.dig('Address'),
160
+ instance_id: endpoint.Node.dig('Meta', 'instance_id'),
161
+ tags: [
162
+ {
163
+ key: 'Name',
164
+ value: endpoint.Node.dig('Node')
165
+ },
166
+ {
167
+ key: 'mi:roles',
168
+ value: endpoint.Node.dig('Meta', 'mi_roles')
169
+ },
170
+ {
171
+ key: 'mi:monitoring_roles',
172
+ value: endpoint.Node.dig('Meta', 'mi_monitoring_roles')
173
+ }
174
+ ],
175
+ placement: {
176
+ availability_zone: endpoint.Node.dig('Meta', 'availability_zone')
177
+ }
178
+ })
179
+ end
180
+
152
181
  def instances(role:, exclude_roles: [], region: my_region, availability_zone: nil, exact_match: false, use_cache: true, discovery_type: 'ec2')
153
182
  if discovery_type == 'ec2'
154
183
  instances_with_ec2_discovery(role: role, exclude_roles: exclude_roles, region: region, availability_zone: availability_zone, exact_match: exact_match, use_cache: use_cache)
@@ -3,7 +3,7 @@ module MovableInk
3
3
  module Errors
4
4
  class ServiceError < StandardError; end
5
5
  class FailedWithBackoff < StandardError; end
6
- class EC2Required < StandardError; end
6
+ class MetadataTimeout < StandardError; end
7
7
  class NoEnvironmentTagError < StandardError; end
8
8
  class InvalidDiscoveryTypeError < StandardError; end
9
9
  class RoleNameRequiredError < StandardError; end
@@ -3,59 +3,55 @@ require 'net/http'
3
3
  module MovableInk
4
4
  class AWS
5
5
  module Metadata
6
- def http
7
- @http ||= begin
6
+ def http(timeout_seconds: 1)
7
+ @http = begin
8
8
  http = Net::HTTP.new("169.254.169.254", 80)
9
- http.open_timeout = 1
10
- http.read_timeout = 1
9
+ http.open_timeout = timeout_seconds
10
+ http.read_timeout = timeout_seconds
11
11
  http
12
12
  end
13
13
  end
14
14
 
15
- def retrieve_metadata(key)
16
- request = Net::HTTP::Get.new("/latest/meta-data/#{key}")
17
- request['X-aws-ec2-metadata-token'] = imds_token
18
- response = http.request(request)
19
- response.body
20
- rescue
21
- ""
15
+ def retrieve_metadata(key, tries: 3)
16
+ tries.times do |num|
17
+ num += 1
18
+ request = Net::HTTP::Get.new("/latest/meta-data/#{key}")
19
+ request['X-aws-ec2-metadata-token'] = imds_token
20
+ response = http(timeout_seconds: num * 3).request(request)
21
+ return response.body
22
+ rescue Net::OpenTimeout, Net::ReadTimeout, Errno::EHOSTDOWN
23
+ sleep(num * 2)
24
+ end
25
+
26
+ raise MovableInk::AWS::Errors::MetadataTimeout
22
27
  end
23
28
 
24
29
  def availability_zone
25
- @availability_zone ||= begin
26
- az = retrieve_metadata('placement/availability-zone')
27
- raise(MovableInk::AWS::Errors::EC2Required) if az.empty?
28
- az
29
- end
30
+ @availability_zone ||= retrieve_metadata('placement/availability-zone')
30
31
  end
31
32
 
32
33
  def instance_id
33
- @instance_id ||= begin
34
- id = retrieve_metadata('instance-id')
35
- raise(MovableInk::AWS::Errors::EC2Required) if id.empty?
36
- id
37
- end
34
+ @instance_id ||= retrieve_metadata('instance-id')
38
35
  end
39
36
 
40
37
  def private_ipv4
41
- @ipv4 ||= begin
42
- ipv4 = retrieve_metadata('local-ipv4')
43
- raise(MovableInk::AWS::Errors::EC2Required) if ipv4.empty?
44
- ipv4
45
- end
38
+ @ipv4 ||= retrieve_metadata('local-ipv4')
46
39
  end
47
40
 
48
41
  private
49
42
 
50
- def imds_token
51
- begin
43
+ def imds_token(tries: 3)
44
+ tries.times do |num|
45
+ num += 1
52
46
  request = Net::HTTP::Put.new('/latest/api/token')
53
47
  request['X-aws-ec2-metadata-token-ttl-seconds'] = 120
54
- response = http.request(request)
55
- response.body
56
- rescue
57
- nil
48
+ response = http(timeout_seconds: num * 3).request(request)
49
+ return response.body
50
+ rescue Net::OpenTimeout, Net::ReadTimeout, Errno::EHOSTDOWN
51
+ sleep(num * 2)
58
52
  end
53
+
54
+ raise MovableInk::AWS::Errors::MetadataTimeout
59
55
  end
60
56
  end
61
57
  end
@@ -103,7 +103,11 @@ module MovableInk
103
103
  end
104
104
 
105
105
  def my_region
106
- @my_region ||= availability_zone.chop
106
+ @my_region ||= if ENV['AWS_REGION'].nil?
107
+ availability_zone.chop
108
+ else
109
+ ENV['AWS_REGION']
110
+ end
107
111
  end
108
112
 
109
113
  def datacenter(region: my_region)
@@ -1,5 +1,5 @@
1
1
  module MovableInk
2
2
  class AWS
3
- VERSION = '2.2.0'
3
+ VERSION = '2.3.2'
4
4
  end
5
5
  end
data/spec/aws_spec.rb CHANGED
@@ -1,17 +1,37 @@
1
1
  require_relative '../lib/movable_ink/aws'
2
+ require 'webmock/rspec'
2
3
 
3
4
  describe MovableInk::AWS do
4
5
  context "outside EC2" do
6
+ before(:each) do
7
+ allow_any_instance_of(MovableInk::AWS).to receive(:sleep).and_return(true)
8
+ end
9
+
10
+ after(:each) { ENV['AWS_REGION'] = nil }
11
+
5
12
  it 'doesnt raise an error if instance_id is set' do
6
13
  aws = MovableInk::AWS.new(instance_id: 'i-987654321')
7
14
  expect(aws.instance_id).to eq('i-987654321')
8
15
  end
16
+
17
+ it 'doesnt raise if AWS_REGION is set' do
18
+ ENV['AWS_REGION'] = 'us-east-1'
19
+ miaws = MovableInk::AWS.new
20
+ expect(miaws.my_region).to eq('us-east-1')
21
+ end
22
+
23
+ it 'raises when AWS_REGION is not set and the metadata service is not available' do
24
+ miaws = MovableInk::AWS.new
25
+ # stub an error making a request to the metadata api
26
+ stub_request(:put, 'http://169.254.169.254/latest/api/token').to_raise(Net::OpenTimeout)
27
+ expect { miaws.my_region }.to raise_error(MovableInk::AWS::Errors::MetadataTimeout)
28
+ end
9
29
  end
10
30
 
11
31
  context "inside EC2" do
12
32
  it "should find the datacenter by region" do
13
33
  aws = MovableInk::AWS.new
14
- expect(aws).to receive(:retrieve_metadata).with('placement/availability-zone').and_return("us-east-1a")
34
+ expect(aws).to receive(:availability_zone).and_return("us-east-1a")
15
35
  expect(aws.datacenter).to eq('iad')
16
36
  end
17
37
 
data/spec/ec2_spec.rb CHANGED
@@ -2,12 +2,16 @@ require_relative '../lib/movable_ink/aws'
2
2
  require 'webmock/rspec'
3
3
 
4
4
  describe MovableInk::AWS::EC2 do
5
+ before(:each) do
6
+ allow_any_instance_of(MovableInk::AWS).to receive(:sleep).and_return(true)
7
+ end
8
+
5
9
  context "outside EC2" do
6
10
  it "should raise an error if trying to load mi_env outside of EC2" do
7
11
  aws = MovableInk::AWS.new
8
- allow(aws).to receive(:retrieve_metadata).with('instance-id').and_return("")
9
- allow(aws).to receive(:retrieve_metadata).with('placement/availability-zone').and_return("")
10
- expect{ aws.mi_env }.to raise_error(MovableInk::AWS::Errors::EC2Required)
12
+ # stub an error making a request to the metadata api
13
+ stub_request(:put, 'http://169.254.169.254/latest/api/token').to_raise(Net::OpenTimeout)
14
+ expect{ aws.mi_env }.to raise_error(MovableInk::AWS::Errors::MetadataTimeout)
11
15
  end
12
16
 
13
17
  it "should use the provided environment" do
@@ -17,12 +21,16 @@ describe MovableInk::AWS::EC2 do
17
21
 
18
22
  it "should not find a 'me'" do
19
23
  aws = MovableInk::AWS.new
24
+ # stub an error making a request to the metadata api
25
+ stub_request(:put, 'http://169.254.169.254/latest/api/token').to_raise(Net::OpenTimeout)
20
26
  expect(aws.me).to eq(nil)
21
27
  end
22
28
  end
23
29
 
24
30
  context "inside EC2" do
25
- WebMock.allow_net_connect!
31
+ before(:each) { WebMock.allow_net_connect! }
32
+ after(:each) { WebMock.disable_net_connect! }
33
+
26
34
  let(:aws) { MovableInk::AWS.new }
27
35
  let(:ec2) { Aws::EC2::Client.new(stub_responses: true) }
28
36
  let(:tag_data) { ec2.stub_data(:describe_tags, tags: [
@@ -386,6 +394,36 @@ describe MovableInk::AWS::EC2 do
386
394
  }]
387
395
  }
388
396
 
397
+ let(:consul_kubernetes_service_instances) do
398
+ [
399
+ {
400
+ "Node": {
401
+ "ID": "",
402
+ "Node": "k8s-sync",
403
+ "Address": "127.0.0.1",
404
+ "Datacenter": "my_datacenter",
405
+ "TaggedAddresses": nil,
406
+ "Meta": {
407
+ "external-source": "kubernetes",
408
+ "CreateIndex": 987654321,
409
+ "ModifyIndex": 123456789,
410
+ }
411
+ },
412
+ "Service": {
413
+ "ID": "pod-name-ac8f920827af",
414
+ "Service": "kubernetes-service-name",
415
+ "Tags": ["k8s"],
416
+ "Address": "10.0.0.1",
417
+ "Port": 8080,
418
+ "Meta": {
419
+ "external-source": "kubernetes",
420
+ "external-k8s-ns": "default",
421
+ }
422
+ }
423
+ }
424
+ ]
425
+ end
426
+
389
427
  before(:each) do
390
428
  allow(aws).to receive(:mi_env).and_return('test')
391
429
  allow(aws).to receive(:availability_zone).and_return(my_availability_zone)
@@ -444,6 +482,34 @@ describe MovableInk::AWS::EC2 do
444
482
 
445
483
  ojos_instances = aws.instances(role: 'ojos', availability_zone: other_availability_zone, discovery_type: 'consul')
446
484
  expect(ojos_instances.map{|i| i.tags.first[:value]}).to eq(['ojos_instance2', 'ojos_instance3'])
485
+ expect(ojos_instances.map{|i| i.tags[1][:value]}).to eq(['ojos', 'ojos'])
486
+ end
487
+
488
+ it "returns backends that are synced from consul-k8s" do
489
+ miaws = double(MovableInk::AWS)
490
+ allow(miaws).to receive(:my_region).and_return('us-east-1')
491
+
492
+ json = JSON.generate(consul_kubernetes_service_instances)
493
+ stub_request(:get, "https://localhost:8501/v1/health/service/kubernetes-service-name?cached&dc=#{my_datacenter}&passing&stale")
494
+ .with({
495
+ headers: {
496
+ 'Accept'=>'*/*',
497
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
498
+ 'User-Agent'=>'Faraday v1.0.1'
499
+ }
500
+ })
501
+ .to_return(status: 200, body: json, headers: {})
502
+
503
+ resp_instances = aws.instances(role: 'kubernetes-service-name', discovery_type: 'consul')
504
+ backend = resp_instances.first
505
+ name_tag = backend.tags.find {|t| t[:key] == 'Name' }
506
+ roles_tag = backend.tags.find {|t| t[:key] == 'mi:roles' }
507
+
508
+ expect(name_tag[:value]).to eq('pod-name-ac8f920827af')
509
+ expect(roles_tag[:value]).to eq('kubernetes-service-name')
510
+ expect(backend.instance_id).to eq(nil)
511
+ expect(backend.private_ip_address).to eq('10.0.0.1')
512
+ expect(backend.private_ip_address).to eq('10.0.0.1')
447
513
  end
448
514
  end
449
515
 
@@ -1,20 +1,25 @@
1
1
  require_relative '../lib/movable_ink/aws'
2
+ require 'webmock/rspec'
2
3
 
3
4
  describe MovableInk::AWS::Metadata do
5
+ before(:each) do
6
+ allow_any_instance_of(MovableInk::AWS).to receive(:sleep).and_return(true)
7
+ end
8
+
4
9
  context 'outside ec2' do
5
- it 'should raise an error if EC2 is required' do
10
+ it 'should raise an error if the metadata service times out' do
6
11
  aws = MovableInk::AWS.new
7
- allow(aws).to receive(:retrieve_metadata).with('instance-id').and_return("")
8
- allow(aws).to receive(:retrieve_metadata).with('placement/availability-zone').and_return("")
9
-
10
- expect{ aws.instance_id }.to raise_error(MovableInk::AWS::Errors::EC2Required)
11
- expect{ aws.availability_zone }.to raise_error(MovableInk::AWS::Errors::EC2Required)
12
+ # stub an error making a request to the metadata api
13
+ stub_request(:put, 'http://169.254.169.254/latest/api/token').to_raise(Net::OpenTimeout)
14
+ expect{ aws.instance_id }.to raise_error(MovableInk::AWS::Errors::MetadataTimeout)
15
+ expect{ aws.availability_zone }.to raise_error(MovableInk::AWS::Errors::MetadataTimeout)
12
16
  end
13
17
 
14
18
  it 'should raise an error if trying to load private_ipv4 outside of EC2' do
15
19
  aws = MovableInk::AWS.new
16
- allow(aws).to receive(:retrieve_metadata).with('local-ipv4').and_return('')
17
- expect{ aws.private_ipv4 }.to raise_error(MovableInk::AWS::Errors::EC2Required)
20
+ # stub an error making a request to the metadata api
21
+ stub_request(:put, 'http://169.254.169.254/latest/api/token').to_raise(Net::OpenTimeout)
22
+ expect{ aws.private_ipv4 }.to raise_error(MovableInk::AWS::Errors::MetadataTimeout)
18
23
  end
19
24
  end
20
25
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: MovableInkAWS
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Chesler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-23 00:00:00.000000000 Z
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core
@@ -276,7 +276,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
276
276
  - !ruby/object:Gem::Version
277
277
  version: '0'
278
278
  requirements: []
279
- rubygems_version: 3.0.3
279
+ rubygems_version: 3.0.3.1
280
280
  signing_key:
281
281
  specification_version: 4
282
282
  summary: AWS Utility methods for MovableInk