MovableInkAWS 1.3.3 → 2.1.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: a474efe41182db10e521fd3df11b259261591f6113f2ab71cf66b0e603199578
4
- data.tar.gz: 527f38ea7a18d93366b1fe9cbf16f75c3d8f79c8d6f29d6b44e8a4b7eb92d82f
3
+ metadata.gz: 6de21c0fdb46ad5c3506f242a6a2732abe711831fbde4b70c72ad24147e37bce
4
+ data.tar.gz: 035f21cb39b733f31bc05b86e877cf81cc62b7c2e7a5a80832df2d2ce147053b
5
5
  SHA512:
6
- metadata.gz: 778adf6177659e449ee6a4c4fea6007120d7397bd5acd109111dfaf3f673af6289e1e9b82f8b8c2a34583c86d9b567283836cedbaa822a183bdd730b074fb9e7
7
- data.tar.gz: 6f94b899d09790472b843e2fd69f895ed349f97a4b21443d413b61713d464c8eb864cdfce1a495139a2eb67c31cd36ab3fe0f485d333ab2b5f58e178c87ee167
6
+ metadata.gz: 65af327d97a4fddc422eac4b212ff9444b4d70e82c045baf4c96627e37152415fa183417399a189aa6c47f26176fab07640662e7a092063f48665bf214b9f13c
7
+ data.tar.gz: b91d80649d4f32bd8b878125e1c2d4a9c7fd6825194b82d563c43017897a85b3e784ff2cc6e6c3cb28f714f17a49d0bec57da754b67eea67698a4663cdc9c4a8
data/Gemfile CHANGED
@@ -3,4 +3,5 @@ gemspec
3
3
 
4
4
  group :test do
5
5
  gem 'rspec', '~> 3.6'
6
+ gem 'webmock'
6
7
  end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- MovableInkAWS (1.3.3)
4
+ MovableInkAWS (2.1.2)
5
5
  aws-sdk-athena (~> 1)
6
6
  aws-sdk-autoscaling (~> 1)
7
7
  aws-sdk-cloudwatch (~> 1)
@@ -15,66 +15,80 @@ PATH
15
15
  aws-sdk-sns (~> 1)
16
16
  aws-sdk-ssm (~> 1)
17
17
  aws-sigv4 (~> 1.1)
18
+ diplomat (= 2.4.2)
18
19
  httparty (= 0.16.3)
19
20
 
20
21
  GEM
21
22
  remote: https://rubygems.org/
22
23
  specs:
24
+ addressable (2.7.0)
25
+ public_suffix (>= 2.0.2, < 5.0)
23
26
  aws-eventstream (1.1.0)
24
- aws-partitions (1.383.0)
27
+ aws-partitions (1.416.0)
25
28
  aws-sdk-athena (1.33.0)
26
29
  aws-sdk-core (~> 3, >= 3.109.0)
27
30
  aws-sigv4 (~> 1.1)
28
- aws-sdk-autoscaling (1.47.0)
31
+ aws-sdk-autoscaling (1.53.0)
29
32
  aws-sdk-core (~> 3, >= 3.109.0)
30
33
  aws-sigv4 (~> 1.1)
31
- aws-sdk-cloudwatch (1.45.0)
34
+ aws-sdk-cloudwatch (1.47.0)
32
35
  aws-sdk-core (~> 3, >= 3.109.0)
33
36
  aws-sigv4 (~> 1.1)
34
- aws-sdk-core (3.109.1)
37
+ aws-sdk-core (3.111.0)
35
38
  aws-eventstream (~> 1, >= 1.0.2)
36
39
  aws-partitions (~> 1, >= 1.239.0)
37
40
  aws-sigv4 (~> 1.1)
38
41
  jmespath (~> 1.0)
39
- aws-sdk-ec2 (1.200.0)
42
+ aws-sdk-ec2 (1.220.0)
40
43
  aws-sdk-core (~> 3, >= 3.109.0)
41
44
  aws-sigv4 (~> 1.1)
42
- aws-sdk-eks (1.45.0)
45
+ aws-sdk-eks (1.46.0)
43
46
  aws-sdk-core (~> 3, >= 3.109.0)
44
47
  aws-sigv4 (~> 1.1)
45
- aws-sdk-elasticache (1.44.0)
48
+ aws-sdk-elasticache (1.50.0)
46
49
  aws-sdk-core (~> 3, >= 3.109.0)
47
50
  aws-sigv4 (~> 1.1)
48
- aws-sdk-kms (1.39.0)
51
+ aws-sdk-kms (1.41.0)
49
52
  aws-sdk-core (~> 3, >= 3.109.0)
50
53
  aws-sigv4 (~> 1.1)
51
- aws-sdk-rds (1.104.0)
54
+ aws-sdk-rds (1.110.0)
52
55
  aws-sdk-core (~> 3, >= 3.109.0)
53
56
  aws-sigv4 (~> 1.1)
54
- aws-sdk-route53 (1.44.0)
57
+ aws-sdk-route53 (1.45.0)
55
58
  aws-sdk-core (~> 3, >= 3.109.0)
56
59
  aws-sigv4 (~> 1.1)
57
- aws-sdk-s3 (1.83.1)
60
+ aws-sdk-s3 (1.87.0)
58
61
  aws-sdk-core (~> 3, >= 3.109.0)
59
62
  aws-sdk-kms (~> 1)
60
63
  aws-sigv4 (~> 1.1)
61
- aws-sdk-sns (1.33.0)
64
+ aws-sdk-sns (1.36.0)
62
65
  aws-sdk-core (~> 3, >= 3.109.0)
63
66
  aws-sigv4 (~> 1.1)
64
- aws-sdk-ssm (1.95.0)
67
+ aws-sdk-ssm (1.102.0)
65
68
  aws-sdk-core (~> 3, >= 3.109.0)
66
69
  aws-sigv4 (~> 1.1)
67
70
  aws-sigv4 (1.2.2)
68
71
  aws-eventstream (~> 1, >= 1.0.2)
72
+ crack (0.4.3)
73
+ safe_yaml (~> 1.0.0)
74
+ deep_merge (1.2.1)
69
75
  diff-lcs (1.3)
76
+ diplomat (2.4.2)
77
+ deep_merge (~> 1.0, >= 1.0.1)
78
+ faraday (>= 0.9, < 1.1.0)
79
+ faraday (1.0.1)
80
+ multipart-post (>= 1.2, < 3)
81
+ hashdiff (1.0.0)
70
82
  httparty (0.16.3)
71
83
  mime-types (~> 3.0)
72
84
  multi_xml (>= 0.5.2)
73
85
  jmespath (1.4.0)
74
86
  mime-types (3.3.1)
75
87
  mime-types-data (~> 3.2015)
76
- mime-types-data (3.2020.0512)
88
+ mime-types-data (3.2020.1104)
77
89
  multi_xml (0.6.0)
90
+ multipart-post (2.1.1)
91
+ public_suffix (4.0.5)
78
92
  rspec (3.9.0)
79
93
  rspec-core (~> 3.9.0)
80
94
  rspec-expectations (~> 3.9.0)
@@ -88,6 +102,11 @@ GEM
88
102
  diff-lcs (>= 1.2.0, < 2.0)
89
103
  rspec-support (~> 3.9.0)
90
104
  rspec-support (3.9.3)
105
+ safe_yaml (1.0.5)
106
+ webmock (3.7.6)
107
+ addressable (>= 2.3.6)
108
+ crack (>= 0.3.2)
109
+ hashdiff (>= 0.4.0, < 2.0.0)
91
110
 
92
111
  PLATFORMS
93
112
  ruby
@@ -95,6 +114,7 @@ PLATFORMS
95
114
  DEPENDENCIES
96
115
  MovableInkAWS!
97
116
  rspec (~> 3.6)
117
+ webmock
98
118
 
99
119
  BUNDLED WITH
100
120
  2.1.3
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_runtime_dependency 'aws-sdk-ssm', '~> 1'
24
24
  s.add_runtime_dependency 'aws-sigv4', '~> 1.1'
25
25
  s.add_runtime_dependency 'httparty', '0.16.3'
26
+ s.add_runtime_dependency 'diplomat', '2.4.2'
26
27
 
27
28
  all_files = `git ls-files`.split("\n")
28
29
  test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -10,6 +10,7 @@ require_relative 'aws/s3'
10
10
  require_relative 'aws/eks'
11
11
  require_relative 'aws/elasticache'
12
12
  require_relative 'aws/api_gateway'
13
+ require_relative 'consul/consul'
13
14
  require 'aws-sdk-cloudwatch'
14
15
 
15
16
 
@@ -1,4 +1,5 @@
1
1
  require 'aws-sdk-ec2'
2
+ require 'diplomat'
2
3
 
3
4
  module MovableInk
4
5
  class AWS
@@ -75,7 +76,7 @@ module MovableInk
75
76
  @me ||= all_instances.select{|instance| instance.instance_id == instance_id}.first rescue nil
76
77
  end
77
78
 
78
- def instances(role:, exclude_roles: [], region: my_region, availability_zone: nil, exact_match: false, use_cache: true)
79
+ def instances_with_ec2_discovery(role:, exclude_roles: [], region: my_region, availability_zone: nil, exact_match: false, use_cache: true)
79
80
  roles = role.split(/\s*,\s*/)
80
81
  if use_cache == false
81
82
  filter = default_filter.push({
@@ -106,6 +107,58 @@ module MovableInk
106
107
  end
107
108
  end
108
109
 
110
+ def instances_with_consul_discovery(role:, region: my_region, availability_zone: nil)
111
+ if role == nil || role == ''
112
+ raise MovableInk::AWS::Errors::RoleNameRequiredError
113
+ end
114
+
115
+ consul_service_options = {
116
+ dc: datacenter(region: region),
117
+ stale: true,
118
+ cached: true,
119
+ passing: true,
120
+ }
121
+ consul_service_options[:node_meta] = "availability_zone:#{availability_zone}" unless availability_zone.nil?
122
+
123
+ # We replace underscores with dashes in the role name in order to comply with
124
+ # consul service naming conventions while still retaining the role name we use
125
+ # within MI configuration
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
+ })
149
+ }
150
+ end
151
+
152
+ def instances(role:, exclude_roles: [], region: my_region, availability_zone: nil, exact_match: false, use_cache: true, discovery_type: 'ec2')
153
+ if discovery_type == 'ec2'
154
+ instances_with_ec2_discovery(role: role, exclude_roles: exclude_roles, region: region, availability_zone: availability_zone, exact_match: exact_match, use_cache: use_cache)
155
+ elsif discovery_type == 'consul'
156
+ instances_with_consul_discovery(role: role, region: region, availability_zone: availability_zone)
157
+ else
158
+ raise MovableInk::AWS::Errors::InvalidDiscoveryTypeError
159
+ end
160
+ end
161
+
109
162
  def thopter
110
163
  private_ip_addresses(thopter_instance).first
111
164
  end
@@ -5,6 +5,9 @@ module MovableInk
5
5
  class FailedWithBackoff < StandardError; end
6
6
  class EC2Required < StandardError; end
7
7
  class NoEnvironmentTagError < StandardError; end
8
+ class InvalidDiscoveryTypeError < StandardError; end
9
+ class RoleNameRequiredError < StandardError; end
10
+ class RoleNameInvalidError < StandardError; end
8
11
  end
9
12
  end
10
13
  end
@@ -0,0 +1,21 @@
1
+ require 'diplomat'
2
+
3
+ Diplomat.configure do |config|
4
+ config.url = "https://localhost:8501"
5
+ config.options = { ssl: { verify: false } }
6
+ end
7
+
8
+ module MovableInk
9
+ module Consul
10
+ module Kv
11
+ def self.get(*args)
12
+ begin
13
+ result = Diplomat::Kv.get(*args)
14
+ JSON.parse(result) if !result.nil?
15
+ rescue JSON::ParserError
16
+ result
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  module MovableInk
2
2
  class AWS
3
- VERSION = '1.3.3'
3
+ VERSION = '2.1.2'
4
4
  end
5
5
  end
@@ -0,0 +1,22 @@
1
+ require_relative '../lib/movable_ink/aws'
2
+ require 'webmock/rspec'
3
+
4
+ describe MovableInk::Consul do
5
+ describe MovableInk::Consul::Kv do
6
+ it 'get returns a hash of json content' do
7
+ allow(Diplomat::Kv).to receive(:get).and_return({ hello: 'world' }.to_json)
8
+ expect(MovableInk::Consul::Kv.get('ham')).to eq({ 'hello' => 'world' })
9
+ end
10
+
11
+ it 'returns a string if the stored value is not json' do
12
+ value = 'some-database-password'
13
+ allow(Diplomat::Kv).to receive(:get).and_return(value)
14
+ expect(MovableInk::Consul::Kv.get('db_password')).to eq(value)
15
+ end
16
+
17
+ it 'forwards all arguments to Diplomat' do
18
+ expect(Diplomat::Kv).to receive(:get).with('foo/', recurse: true)
19
+ MovableInk::Consul::Kv.get('foo/', recurse: true)
20
+ end
21
+ end
22
+ end
data/spec/ec2_spec.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative '../lib/movable_ink/aws'
2
+ require 'webmock/rspec'
2
3
 
3
4
  describe MovableInk::AWS::EC2 do
4
5
  context "outside EC2" do
@@ -21,6 +22,7 @@ describe MovableInk::AWS::EC2 do
21
22
  end
22
23
 
23
24
  context "inside EC2" do
25
+ WebMock.allow_net_connect!
24
26
  let(:aws) { MovableInk::AWS.new }
25
27
  let(:ec2) { Aws::EC2::Client.new(stub_responses: true) }
26
28
  let(:tag_data) { ec2.stub_data(:describe_tags, tags: [
@@ -305,6 +307,146 @@ describe MovableInk::AWS::EC2 do
305
307
  end
306
308
  end
307
309
 
310
+ context "instances with consul discovery" do
311
+ let(:my_availability_zone) { 'us-east-1a' }
312
+ let(:my_datacenter) { 'iad' }
313
+ let(:other_availability_zone) { 'us-east-1b' }
314
+ let(:consul_app_service_instances) {
315
+ [{
316
+ Node: {
317
+ Node: 'app_instance1',
318
+ Address: '10.0.0.1',
319
+ Datacenter: my_datacenter,
320
+ Meta: {
321
+ availability_zone: my_availability_zone,
322
+ instance_id: 'i-12345',
323
+ mi_monitoring_roles: 'app',
324
+ mi_roles: 'app'
325
+ },
326
+ ServiceID: 'app',
327
+ ServiceName: 'app',
328
+ ServiceTags: ['foo', 'bar'],
329
+ ServicePort: 80,
330
+ }
331
+ },
332
+ {
333
+ Node: {
334
+ Node: 'app_instance2',
335
+ Address: '10.0.0.2',
336
+ Datacenter: my_datacenter,
337
+ Meta: {
338
+ availability_zone: my_availability_zone,
339
+ instance_id: 'i-54321',
340
+ mi_monitoring_roles: 'app',
341
+ mi_roles: 'app'
342
+ },
343
+ ServiceID: 'app',
344
+ ServiceName: 'app',
345
+ ServiceTags: ['foo', 'bar'],
346
+ ServicePort: 80,
347
+ }
348
+ }]
349
+ }
350
+
351
+ let(:consul_ojos_service_instances) {
352
+ [
353
+ {
354
+ Node: {
355
+ Node: 'ojos_instance2',
356
+ Address: '10.0.0.4',
357
+ Datacenter: my_datacenter,
358
+ Meta: {
359
+ availability_zone: other_availability_zone,
360
+ instance_id: 'i-zyx987',
361
+ mi_monitoring_roles: 'ojos',
362
+ mi_roles: 'ojos'
363
+ },
364
+ ServiceID: 'ojos',
365
+ ServiceName: 'ojos',
366
+ ServiceTags: ['foo', 'bar'],
367
+ ServicePort: 2702,
368
+ },
369
+ },
370
+ {
371
+ Node: {
372
+ Node: 'ojos_instance3',
373
+ Address: '10.0.0.5',
374
+ Datacenter: my_datacenter,
375
+ Meta: {
376
+ availability_zone: other_availability_zone,
377
+ instance_id: 'i-987654',
378
+ mi_monitoring_roles: 'ojos',
379
+ mi_roles: 'ojos'
380
+ },
381
+ ServiceID: 'ojos',
382
+ ServiceName: 'ojos',
383
+ ServiceTags: ['foo', 'bar'],
384
+ ServicePort: 2702,
385
+ }
386
+ }]
387
+ }
388
+
389
+ before(:each) do
390
+ allow(aws).to receive(:mi_env).and_return('test')
391
+ allow(aws).to receive(:availability_zone).and_return(my_availability_zone)
392
+ allow(aws).to receive(:my_region).and_return('us-east-1')
393
+ allow(aws).to receive(:ec2).and_return(ec2)
394
+ end
395
+
396
+ it "returns an error if no role is defined" do
397
+ expect{ aws.instances(role: nil, discovery_type: 'consul') }.to raise_error(MovableInk::AWS::Errors::RoleNameRequiredError)
398
+ end
399
+
400
+ it "returns all instances matching a consul service" do
401
+ miaws = double(MovableInk::AWS)
402
+ allow(miaws).to receive(:my_region).and_return('us-east-1')
403
+
404
+ json = JSON.generate(consul_app_service_instances)
405
+ stub_request(:get, "https://localhost:8501/v1/health/service/app?cached&dc=#{my_datacenter}&passing&stale").
406
+ with(
407
+ headers: {
408
+ 'Accept'=>'*/*',
409
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
410
+ 'User-Agent'=>'Faraday v1.0.1'
411
+ }).
412
+ to_return(status: 200, body: json, headers: {})
413
+
414
+ app_instances = aws.instances(role: 'app', discovery_type: 'consul')
415
+ expect(app_instances.map{|i| i.tags.first[:value]}).to eq(['app_instance1', 'app_instance2'])
416
+
417
+ json = JSON.generate(consul_ojos_service_instances)
418
+ stub_request(:get, "https://localhost:8501/v1/health/service/ojos?cached&dc=#{my_datacenter}&passing&stale").
419
+ with(
420
+ headers: {
421
+ 'Accept'=>'*/*',
422
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
423
+ 'User-Agent'=>'Faraday v1.0.1'
424
+ }).
425
+ to_return(status: 200, body: json, headers: {})
426
+
427
+ ojos_instances = aws.instances(role: 'ojos', discovery_type: 'consul')
428
+ expect(ojos_instances.map{|i| i.tags.first[:value ]}).to eq(['ojos_instance2', 'ojos_instance3'])
429
+ end
430
+
431
+ it "returns all instances matching a consul service filtered by availability_zone" do
432
+ miaws = double(MovableInk::AWS)
433
+ allow(miaws).to receive(:my_region).and_return('us-east-1')
434
+
435
+ json = JSON.generate(consul_ojos_service_instances)
436
+ stub_request(:get, "https://localhost:8501/v1/health/service/ojos?cached&dc=#{my_datacenter}&node-meta=availability_zone:#{other_availability_zone}&passing&stale").
437
+ with(
438
+ headers: {
439
+ 'Accept'=>'*/*',
440
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
441
+ 'User-Agent'=>'Faraday v1.0.1'
442
+ }).
443
+ to_return(status: 200, body: json, headers: {})
444
+
445
+ ojos_instances = aws.instances(role: 'ojos', availability_zone: other_availability_zone, discovery_type: 'consul')
446
+ expect(ojos_instances.map{|i| i.tags.first[:value]}).to eq(['ojos_instance2', 'ojos_instance3'])
447
+ end
448
+ end
449
+
308
450
  context "ordered roles" do
309
451
  let(:my_availability_zone) { 'us-east-1a' }
310
452
  let(:other_availability_zone) { 'us-east-1b' }
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: 1.3.3
4
+ version: 2.1.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: 2020-10-20 00:00:00.000000000 Z
11
+ date: 2021-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core
@@ -206,6 +206,20 @@ dependencies:
206
206
  - - '='
207
207
  - !ruby/object:Gem::Version
208
208
  version: 0.16.3
209
+ - !ruby/object:Gem::Dependency
210
+ name: diplomat
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - '='
214
+ - !ruby/object:Gem::Version
215
+ version: 2.4.2
216
+ type: :runtime
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - '='
221
+ - !ruby/object:Gem::Version
222
+ version: 2.4.2
209
223
  description: AWS Utility methods for MovableInk
210
224
  email: mchesler@movableink.com
211
225
  executables: []
@@ -232,9 +246,11 @@ files:
232
246
  - lib/movable_ink/aws/s3.rb
233
247
  - lib/movable_ink/aws/sns.rb
234
248
  - lib/movable_ink/aws/ssm.rb
249
+ - lib/movable_ink/consul/consul.rb
235
250
  - lib/movable_ink/version.rb
236
251
  - spec/autoscaling_spec.rb
237
252
  - spec/aws_spec.rb
253
+ - spec/consul_spec.rb
238
254
  - spec/ec2_spec.rb
239
255
  - spec/elasticache_spec.rb
240
256
  - spec/metadata_spec.rb