MovableInkAWS 1.0.12 → 1.0.17

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: '092c81ea23dd01ec27099a68d8ee17510239f9d18b75992c13e7c17600fa3c13'
4
- data.tar.gz: 9c1696ebf069bb8db288509014599a62dc4d4c23b9c569e88dae3a858addf054
3
+ metadata.gz: 4563a27230a7711f44768ef561751a2366e03195de236dfb18a29bbff559c78b
4
+ data.tar.gz: b42568ac0c14f98d09420d4c2819b58eb047be5c31ca9a2e576c61685f69445b
5
5
  SHA512:
6
- metadata.gz: e42ac78ca0f620398222aa285f1792e257229327c7d8595ac3a4d1548b335c97dec2a3682d5d828aecae956ede68ed5336f790d91beda46a85d29b90b4d97138
7
- data.tar.gz: 4f25f6de7c875a960ae306c8c337f8f9b943d132ede56b5135761449228b745c15a8a06415c48061d64197e98d8a272627b3fe775ff179897ce6f5f46e5f31a8
6
+ metadata.gz: e9d9d52abbe8c75ce57a6cbd4165ea5188341106c4cf79cdc49fb96b9eda8db2b1e2216b948c750867c6333a9d29c682ef12084fd75186619b29d435606a99b7
7
+ data.tar.gz: c956e15226b703d33fdf7d74b367dac8259106cea459f5ca00ddfbe7fd05b17ccca18bdee22bde39c697370c7fb33ddd1ddf6210141efeea329f35b23f0a95c8
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - 2.2
4
+ - 2.5
5
+ - 2.6
5
6
 
6
7
  bundler_args: "--retry=3"
7
8
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- MovableInkAWS (1.0.12)
4
+ MovableInkAWS (1.0.17)
5
5
  aws-sdk-athena (~> 1)
6
6
  aws-sdk-autoscaling (~> 1)
7
7
  aws-sdk-cloudwatch (~> 1)
@@ -19,48 +19,48 @@ PATH
19
19
  GEM
20
20
  remote: https://rubygems.org/
21
21
  specs:
22
- aws-eventstream (1.0.3)
23
- aws-partitions (1.280.0)
24
- aws-sdk-athena (1.22.0)
22
+ aws-eventstream (1.1.0)
23
+ aws-partitions (1.322.0)
24
+ aws-sdk-athena (1.26.0)
25
25
  aws-sdk-core (~> 3, >= 3.71.0)
26
26
  aws-sigv4 (~> 1.1)
27
- aws-sdk-autoscaling (1.32.0)
27
+ aws-sdk-autoscaling (1.37.0)
28
28
  aws-sdk-core (~> 3, >= 3.71.0)
29
29
  aws-sigv4 (~> 1.1)
30
- aws-sdk-cloudwatch (1.33.0)
30
+ aws-sdk-cloudwatch (1.38.0)
31
31
  aws-sdk-core (~> 3, >= 3.71.0)
32
32
  aws-sigv4 (~> 1.1)
33
- aws-sdk-core (3.90.1)
34
- aws-eventstream (~> 1.0, >= 1.0.2)
33
+ aws-sdk-core (3.97.0)
34
+ aws-eventstream (~> 1, >= 1.0.2)
35
35
  aws-partitions (~> 1, >= 1.239.0)
36
36
  aws-sigv4 (~> 1.1)
37
37
  jmespath (~> 1.0)
38
- aws-sdk-ec2 (1.147.0)
38
+ aws-sdk-ec2 (1.164.0)
39
39
  aws-sdk-core (~> 3, >= 3.71.0)
40
40
  aws-sigv4 (~> 1.1)
41
- aws-sdk-elasticache (1.29.0)
41
+ aws-sdk-elasticache (1.35.0)
42
42
  aws-sdk-core (~> 3, >= 3.71.0)
43
43
  aws-sigv4 (~> 1.1)
44
- aws-sdk-kms (1.29.0)
44
+ aws-sdk-kms (1.32.0)
45
45
  aws-sdk-core (~> 3, >= 3.71.0)
46
46
  aws-sigv4 (~> 1.1)
47
- aws-sdk-rds (1.78.0)
47
+ aws-sdk-rds (1.85.0)
48
48
  aws-sdk-core (~> 3, >= 3.71.0)
49
49
  aws-sigv4 (~> 1.1)
50
- aws-sdk-route53 (1.30.0)
50
+ aws-sdk-route53 (1.35.0)
51
51
  aws-sdk-core (~> 3, >= 3.71.0)
52
52
  aws-sigv4 (~> 1.1)
53
- aws-sdk-s3 (1.60.2)
54
- aws-sdk-core (~> 3, >= 3.83.0)
53
+ aws-sdk-s3 (1.67.0)
54
+ aws-sdk-core (~> 3, >= 3.96.1)
55
55
  aws-sdk-kms (~> 1)
56
56
  aws-sigv4 (~> 1.1)
57
- aws-sdk-sns (1.21.0)
57
+ aws-sdk-sns (1.24.0)
58
58
  aws-sdk-core (~> 3, >= 3.71.0)
59
59
  aws-sigv4 (~> 1.1)
60
- aws-sdk-ssm (1.71.0)
60
+ aws-sdk-ssm (1.79.0)
61
61
  aws-sdk-core (~> 3, >= 3.71.0)
62
62
  aws-sigv4 (~> 1.1)
63
- aws-sigv4 (1.1.1)
63
+ aws-sigv4 (1.1.4)
64
64
  aws-eventstream (~> 1.0, >= 1.0.2)
65
65
  diff-lcs (1.3)
66
66
  httparty (0.16.3)
@@ -69,7 +69,7 @@ GEM
69
69
  jmespath (1.4.0)
70
70
  mime-types (3.3.1)
71
71
  mime-types-data (~> 3.2015)
72
- mime-types-data (3.2019.1009)
72
+ mime-types-data (3.2020.0512)
73
73
  multi_xml (0.6.0)
74
74
  rspec (3.9.0)
75
75
  rspec-core (~> 3.9.0)
@@ -93,4 +93,4 @@ DEPENDENCIES
93
93
  rspec (~> 3.6)
94
94
 
95
95
  BUNDLED WITH
96
- 1.17.1
96
+ 1.17.3
@@ -59,6 +59,7 @@ module MovableInk
59
59
  return yield
60
60
  rescue Aws::EC2::Errors::RequestLimitExceeded,
61
61
  Aws::EC2::Errors::ResourceAlreadyAssociated,
62
+ Aws::EC2::Errors::Unavailable,
62
63
  Aws::SNS::Errors::ThrottledException,
63
64
  Aws::AutoScaling::Errors::ThrottledException,
64
65
  Aws::S3::Errors::SlowDown,
@@ -76,12 +77,15 @@ module MovableInk
76
77
  notify_and_sleep(sleep_time, $!.class)
77
78
  end
78
79
  rescue Aws::Errors::ServiceError => e
79
- message = "#{e.class}: #{e.message}\nFrom `#{e.backtrace.last.gsub("`","'")}`"
80
+ message = "#{e.class}: #{e.message}\nFrom #{$0}\n```\n#{e.backtrace.first(3).join("\n").gsub("`","'")}\n```"
80
81
  notify_slack(subject: 'Unhandled AWS API Error', message: message)
81
82
  puts message
82
83
  raise MovableInk::AWS::Errors::ServiceError
83
84
  end
84
85
  end
86
+ message = "From: #{$0}\n```\n#{Thread.current.backtrace.first(3).join("\n").gsub("`","'")}\n```"
87
+ notify_slack(subject: "AWS API failed after #{tries} attempts", message: message)
88
+ puts message
85
89
  raise MovableInk::AWS::Errors::FailedWithBackoff
86
90
  end
87
91
 
@@ -14,7 +14,8 @@ module MovableInk
14
14
 
15
15
  def mi_env
16
16
  @mi_env ||= if File.exist?(mi_env_cache_file_path)
17
- File.read(mi_env_cache_file_path)
17
+ value = File.read(mi_env_cache_file_path)
18
+ value.empty? ? load_mi_env : value
18
19
  else
19
20
  load_mi_env
20
21
  end
@@ -28,23 +29,12 @@ module MovableInk
28
29
  raise MovableInk::AWS::Errors::NoEnvironmentTagError
29
30
  end
30
31
 
31
- def thopter_filter
32
- [{
33
- name: 'tag:mi:roles',
34
- values: ['*thopter*']
35
- },
36
- {
37
- name: 'tag:mi:env',
38
- values: [mi_env]
39
- },
40
- {
41
- name: 'instance-state-name',
42
- values: ['running']
43
- }]
44
- end
45
-
46
32
  def thopter_instance
47
- @thopter_instance ||= load_all_instances('us-east-1', filter: thopter_filter)
33
+ @thopter_instance ||= all_instances(region: 'us-east-1').select do |instance|
34
+ instance.tags.select{ |tag| tag.key == 'mi:roles' }.detect do |tag|
35
+ tag.value.include?('thopter')
36
+ end
37
+ end
48
38
  end
49
39
 
50
40
  def all_instances(region: my_region, no_filter: false)
@@ -101,18 +91,27 @@ module MovableInk
101
91
  @me ||= all_instances.select{|instance| instance.instance_id == instance_id}.first rescue nil
102
92
  end
103
93
 
104
- def instances(role:, exclude_roles: [], region: my_region, availability_zone: nil, exact_match: false)
105
- instances = all_instances(region: region).select { |instance|
106
- instance.tags.select{ |tag| tag.key == 'mi:roles' }.detect { |tag|
107
- roles = tag.value.split(/\s*,\s*/)
108
- if exact_match
109
- roles == [role]
110
- else
111
- exclude_roles.push('decommissioned')
112
- roles.include?(role) && !roles.any? { |role| exclude_roles.include?(role) }
113
- end
94
+ def instances(role:, exclude_roles: [], region: my_region, availability_zone: nil, exact_match: false, use_cache: true)
95
+ roles = role.split(/\s*,\s*/)
96
+ if use_cache == false
97
+ filter = default_filter.push({
98
+ name: 'tag:mi:roles',
99
+ values: roles
100
+ })
101
+ instances = load_all_instances(my_region, filter: filter)
102
+ else
103
+ instances = all_instances(region: region).select { |instance|
104
+ instance.tags.select{ |tag| tag.key == 'mi:roles' }.detect { |tag|
105
+ tag_roles = tag.value.split(/\s*,\s*/)
106
+ if exact_match
107
+ tag_roles == roles
108
+ else
109
+ exclude_roles.push('decommissioned')
110
+ tag_roles.any? { |tag_role| roles.include?(tag_role) } && !tag_roles.any? { |role| exclude_roles.include?(role) }
111
+ end
112
+ }
114
113
  }
115
- }
114
+ end
116
115
 
117
116
  if availability_zone
118
117
  instances.select { |instance|
@@ -1,5 +1,5 @@
1
1
  module MovableInk
2
2
  class AWS
3
- VERSION = '1.0.12'
3
+ VERSION = '1.0.17'
4
4
  end
5
5
  end
@@ -42,9 +42,9 @@ describe MovableInk::AWS do
42
42
  ec2 = Aws::EC2::Client.new(stub_responses: true)
43
43
  ec2.stub_responses(:describe_instances, 'RequestLimitExceeded')
44
44
 
45
- expect(aws).to receive(:notify_slack).exactly(9).times
45
+ expect(aws).to receive(:notify_slack).exactly(10).times
46
46
  expect(aws).to receive(:sleep).exactly(9).times.and_return(true)
47
- expect(STDOUT).to receive(:puts).exactly(9).times
47
+ expect(STDOUT).to receive(:puts).exactly(10).times
48
48
 
49
49
  aws.run_with_backoff { ec2.describe_instances } rescue nil
50
50
  end
@@ -64,9 +64,9 @@ describe MovableInk::AWS do
64
64
  ec2 = Aws::EC2::Client.new(stub_responses: true)
65
65
  ec2.stub_responses(:describe_instances, 'RequestLimitExceeded')
66
66
 
67
- expect(aws).to receive(:notify_slack).exactly(1).times
67
+ expect(aws).to receive(:notify_slack).exactly(2).times
68
68
  expect(aws).to receive(:sleep).exactly(9).times.and_return(true)
69
- expect(STDOUT).to receive(:puts).exactly(1).times
69
+ expect(STDOUT).to receive(:puts).exactly(2).times
70
70
 
71
71
  aws.run_with_backoff(quiet: true) { ec2.describe_instances } rescue nil
72
72
  end
@@ -77,6 +77,8 @@ describe MovableInk::AWS do
77
77
  ec2.stub_responses(:describe_instances, 'RequestLimitExceeded')
78
78
 
79
79
  expect(aws).to receive(:notify_and_sleep).exactly(9).times
80
+ expect(aws).to receive(:notify_slack).exactly(1).times
81
+ expect(STDOUT).to receive(:puts).exactly(1).times
80
82
  expect{ aws.run_with_backoff { ec2.describe_instances } }.to raise_error(MovableInk::AWS::Errors::FailedWithBackoff)
81
83
  end
82
84
  end
@@ -45,6 +45,19 @@ describe MovableInk::AWS::EC2 do
45
45
  expect(aws.mi_env).to eq('staging')
46
46
  end
47
47
 
48
+ it 'will read tag data if the cache file is empty' do
49
+ ec2.stub_responses(:describe_tags, tag_data)
50
+ allow(aws).to receive(:my_region).and_return('us-east-1')
51
+ allow(aws).to receive(:instance_id).and_return('i-12345')
52
+ allow(aws).to receive(:ec2).and_return(ec2)
53
+
54
+ f = Tempfile.new('cache')
55
+ f.write('')
56
+ f.close
57
+ allow(aws).to receive(:mi_env_cache_file_path).and_return(f.path)
58
+ expect(aws.mi_env).to eq('test')
59
+ end
60
+
48
61
  it "should find the environment from the current instance's tags" do
49
62
  ec2.stub_responses(:describe_tags, tag_data)
50
63
  allow(aws).to receive(:my_region).and_return('us-east-1')
@@ -170,8 +183,8 @@ describe MovableInk::AWS::EC2 do
170
183
  context "instances" do
171
184
  let(:my_availability_zone) { 'us-east-1a' }
172
185
  let(:other_availability_zone) { 'us-east-1b' }
173
- let(:instance_data) { ec2.stub_data(:describe_instances, reservations: [
174
- instances: [
186
+ let(:instances) {
187
+ [
175
188
  {
176
189
  tags: [
177
190
  {
@@ -239,12 +252,54 @@ describe MovableInk::AWS::EC2 do
239
252
  placement: {
240
253
  availability_zone: other_availability_zone
241
254
  }
255
+ },
256
+ {
257
+ tags: [
258
+ {
259
+ key: 'mi:name',
260
+ value: 'instance5'
261
+ },
262
+ {
263
+ key: 'mi:roles',
264
+ value: 'app_db'
265
+ }
266
+ ],
267
+ instance_id: 'i-321cba',
268
+ private_ip_address: '10.0.0.5',
269
+ placement: {
270
+ availability_zone: other_availability_zone
271
+ }
242
272
  }
243
- ]])
273
+ ]
274
+ }
275
+ let(:single_role_instance_data) { ec2.stub_data(:describe_instances, reservations: [
276
+ instances: instances.select { |instance|
277
+ instance[:tags].detect { |tag| tag[:key] == 'mi:roles' && tag[:value] == 'app_db_replica' }
278
+ }
279
+ ])}
280
+ let(:multi_role_instance_data) { ec2.stub_data(:describe_instances, reservations: [
281
+ instances: instances.select { |instance|
282
+ instance[:tags].detect { |tag|
283
+ tag[:key] == 'mi:roles' && ['app_db', 'app_db_replica'].any?(tag[:value])
284
+ }
285
+ }
286
+ ])}
287
+ let(:all_roles_instance_data) { ec2.stub_data(:describe_instances, reservations: [ instances: instances ])
244
288
  }
245
289
 
246
290
  before(:each) do
247
- ec2.stub_responses(:describe_instances, instance_data)
291
+ ec2.stub_responses(:describe_instances, -> (context) {
292
+ if (context.params[:filters].length == 2)
293
+ all_roles_instance_data
294
+ else
295
+ role_filter = context.params[:filters].detect { |filter| filter[:name] == 'tag:mi:roles' }
296
+ if role_filter[:values].length == 1
297
+ single_role_instance_data
298
+ else
299
+ multi_role_instance_data
300
+ end
301
+ end
302
+ })
248
303
  allow(aws).to receive(:mi_env).and_return('test')
249
304
  allow(aws).to receive(:availability_zone).and_return(my_availability_zone)
250
305
  allow(aws).to receive(:my_region).and_return('us-east-1')
@@ -270,6 +325,16 @@ describe MovableInk::AWS::EC2 do
270
325
  expect(instances.map{|i| i.tags.first.value }).to eq(['instance4'])
271
326
  end
272
327
 
328
+ it "returns roles with exactly the specified role, letting the API to the filtering" do
329
+ instances = aws.instances(role: 'app_db_replica', use_cache: false)
330
+ expect(instances.map{|i| i.tags.first.value }).to eq(['instance4'])
331
+ end
332
+
333
+ it "returns roles with any of the specified roles, letting the API to the filtering" do
334
+ instances = aws.instances(role: 'app_db,app_db_replica', use_cache: false)
335
+ expect(instances.map{|i| i.tags.first.value }).to eq(['instance4', 'instance5'])
336
+ end
337
+
273
338
  it "excludes requested roles" do
274
339
  instances = aws.instances(role: 'app_db_replica', exclude_roles: ['db'])
275
340
  expect(instances.map{|i| i.tags.first.value }).to eq(['instance1', 'instance4'])
@@ -82,6 +82,8 @@ describe MovableInk::AWS::SSM do
82
82
  allow(aws).to receive(:ssm_client).and_return(1)
83
83
  allow(aws).to receive(:ssm_client_failover).and_return(2)
84
84
  allow(aws).to receive(:notify_and_sleep).and_return(nil)
85
+ allow(aws).to receive(:notify_slack).and_return(nil)
86
+ allow(STDOUT).to receive(:puts).and_return(nil)
85
87
 
86
88
  results = []
87
89
  calls = 0
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.0.12
4
+ version: 1.0.17
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-05-08 00:00:00.000000000 Z
11
+ date: 2020-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core