stack_master 0.4.1 → 0.5.0

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
  SHA1:
3
- metadata.gz: 134af119f4a1e7ac352e26c21921f3b1c31cdd4f
4
- data.tar.gz: b2945a13aa2168a9f4b2c8c4ae60883fa10d0f49
3
+ metadata.gz: 1e9fbbd483a550665172b60c679b887fcad750ac
4
+ data.tar.gz: 6be2fc55ee1c3bdb20b54f8e807b7482ac6000a1
5
5
  SHA512:
6
- metadata.gz: d2fb9a998fc5ac28093551d67b3fe5832ba3c0ce411812590070cff1a87552f1ff30d8d9ea30b82d2c94e40961598a0dc15ac911d1672484a2bc85d209a71a94
7
- data.tar.gz: b6f3477bdaaa9f42d8a75367a55c1b40938e7550eb9ce37f2c1bea11fa093e57064732c2b5919b2a0d215981fd9a08706fd574418ac5a079aa1b844865b2f968
6
+ metadata.gz: 6c26185a54b4b9ee4a3e1d092f51139884b8089c60679ef67334b1a1ff241b0a0ef35d24410ea2776df3b74e4ef8cdc086b230941466e0132ff22d79d649a238
7
+ data.tar.gz: 2b30a1899670f668df76ec2c4ee6135ced4cfb40c553d4b7cf69c7ce0942600c82d1fccc79f3d8e160cf9ae73468816c5f5427a63a456d1996afbffc4a35edf6
data/README.md CHANGED
@@ -211,6 +211,24 @@ web_ami:
211
211
 
212
212
  Note that the corresponding array resolver is named `latest_amis_by_tags`
213
213
 
214
+ ### Latest AMI by attribute
215
+
216
+ Looks up the latest AMI ID by a given set of attributes. By default it will only return AMIs from the account the stack is created in, but you can specify the account ID or [certain keywords mentioned in the aws documentation](http://docs.aws.amazon.com/AWSEC2/latest/CommandLineReference/ApiReference-cmd-DescribeImages.html)
217
+
218
+ This selects the latest wily hvm AMI from Ubuntu (using the account id):
219
+
220
+ ```yaml
221
+ bastion_ami:
222
+ latest_ami:
223
+ owners: 099720109477
224
+ filters:
225
+ name: ubuntu/images/hvm/ubuntu-wily-15.10-amd64-server-*
226
+ ```
227
+
228
+ A set of possible attributes is available in the [AWS documentation](https://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Client.html#describe_images-instance_method)
229
+
230
+ Any value can be an array of possible matches.
231
+
214
232
  ### Custom parameter resolvers
215
233
 
216
234
  New parameter resolvers can be created in a separate gem.
data/lib/stack_master.rb CHANGED
@@ -28,11 +28,13 @@ require "stack_master/security_group_finder"
28
28
  require "stack_master/parameter_loader"
29
29
  require "stack_master/parameter_resolver"
30
30
  require "stack_master/resolver_array"
31
+ require "stack_master/parameter_resolvers/ami_finder"
31
32
  require "stack_master/parameter_resolvers/stack_output"
32
33
  require "stack_master/parameter_resolvers/secret"
33
34
  require "stack_master/parameter_resolvers/sns_topic_name"
34
35
  require "stack_master/parameter_resolvers/security_group"
35
36
  require "stack_master/parameter_resolvers/latest_ami_by_tags"
37
+ require "stack_master/parameter_resolvers/latest_ami"
36
38
  require "stack_master/utils"
37
39
  require "stack_master/config"
38
40
  require "stack_master/paged_response_accumulator"
@@ -0,0 +1,36 @@
1
+ module StackMaster
2
+ module ParameterResolvers
3
+ class AmiFinder
4
+ def initialize(region)
5
+ @region = region
6
+ end
7
+
8
+ def build_filters_from_string(value, prefix = nil)
9
+ filters = value.split(',').map do |name_with_value|
10
+ name, value = name_with_value.strip.split('=')
11
+ name = prefix ? "#{prefix}:#{name}" : name
12
+ { name: name, values: [value] }
13
+ end
14
+ filters
15
+ end
16
+
17
+ def build_filters_from_hash(hash)
18
+ hash.map { |key, value| {name: key, values: Array(value.to_s)}}
19
+ end
20
+
21
+ def find_latest_ami(filters, owners = ['self'])
22
+ images = ec2.describe_images(owners: owners, filters: filters).images
23
+ sorted_images = images.sort do |a, b|
24
+ Time.parse(a.creation_date) <=> Time.parse(b.creation_date)
25
+ end
26
+ sorted_images.last
27
+ end
28
+
29
+ private
30
+
31
+ def ec2
32
+ @ec2 ||= Aws::EC2::Client.new(region: @region)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module StackMaster
2
+ module ParameterResolvers
3
+ class LatestAmi < Resolver
4
+ array_resolver class_name: 'LatestAmis'
5
+
6
+ def initialize(config, stack_definition)
7
+ @config = config
8
+ @stack_definition = stack_definition
9
+ @ami_finder = AmiFinder.new(@stack_definition.region)
10
+ end
11
+
12
+ def resolve(value)
13
+ owners = Array(value.fetch('owners', 'self').to_s)
14
+ filters = @ami_finder.build_filters_from_hash(value.fetch('filters'))
15
+ @ami_finder.find_latest_ami(filters, owners).try(:image_id)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -6,32 +6,12 @@ module StackMaster
6
6
  def initialize(config, stack_definition)
7
7
  @config = config
8
8
  @stack_definition = stack_definition
9
+ @ami_finder = AmiFinder.new(@stack_definition.region)
9
10
  end
10
11
 
11
12
  def resolve(value)
12
- filters = build_filters(value)
13
- find_latest_ami(filters).try(:image_id)
14
- end
15
-
16
- private
17
-
18
- def ec2
19
- @ec2 ||= Aws::EC2::Client.new(region: @stack_definition.region)
20
- end
21
-
22
- def build_filters(value)
23
- value.split(',').map do |tag_with_value|
24
- tag, value = tag_with_value.strip.split('=')
25
- { name: "tag:#{tag}", values: [value] }
26
- end
27
- end
28
-
29
- def find_latest_ami(filters)
30
- images = ec2.describe_images(filters: filters).images
31
- sorted_images = images.sort do |a, b|
32
- Time.parse(a.creation_date) <=> Time.parse(b.creation_date)
33
- end
34
- sorted_images.last
13
+ filters = @ami_finder.build_filters_from_string(value, prefix = "tag")
14
+ @ami_finder.find_latest_ami(filters).try(:image_id)
35
15
  end
36
16
  end
37
17
  end
@@ -1,3 +1,3 @@
1
1
  module StackMaster
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -0,0 +1,68 @@
1
+ RSpec.describe StackMaster::ParameterResolvers::AmiFinder do
2
+ subject(:resolver) { described_class.new('us-east-1') }
3
+ let(:ec2) { Aws::EC2::Client.new }
4
+
5
+ before do
6
+ allow(Aws::EC2::Client).to receive(:new).and_return(ec2)
7
+ end
8
+
9
+ describe '#build_filters_from_string' do
10
+ context 'when a single key-value pair is specified' do
11
+ it 'returns an array with a single hash' do
12
+ expect(resolver.build_filters_from_string('my-attr=my-value', nil)).to eq [
13
+ { name: 'my-attr', values: ['my-value']}
14
+ ]
15
+ end
16
+ end
17
+
18
+ context 'when multiple key-value pairs are specified' do
19
+ it 'returns an array with multiple hashes' do
20
+ expect(resolver.build_filters_from_string('my-attr=my-value,foo=bar', nil)).to eq [
21
+ { name: 'my-attr', values: ['my-value']},
22
+ { name: 'foo', values: ['bar']}
23
+ ]
24
+ end
25
+ end
26
+
27
+ context 'when a prefix is supplied' do
28
+ it 'adds the prefix to the filter' do
29
+ expect(resolver.build_filters_from_string('my-tag=my-value', 'tag')).to eq [
30
+ { name: 'tag:my-tag', values: ['my-value']}
31
+ ]
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '#build_filters_from_hash' do
37
+ it 'outputs a hash of values in the format expected by the AWS API' do
38
+ expect(resolver.build_filters_from_hash({'foo' => 'bacon'})).to eq([{name: 'foo', values: ['bacon']}])
39
+ end
40
+ end
41
+
42
+ describe '#find_latest_ami' do
43
+ let(:filter) { [{ name: "String", values: ["String"]}] }
44
+
45
+ context 'when matches are found' do
46
+ before do
47
+ ec2.stub_responses(:describe_images, images: [
48
+ { image_id: '1', creation_date: '2015-01-02 00:00:00', tags: [{ key: 'my-tag', value: 'my-value' }] },
49
+ { image_id: '2', creation_date: '2015-01-03 00:00:00', tags: [{ key: 'my-tag', value: 'my-value' }] }
50
+ ])
51
+ end
52
+
53
+ it 'returns the latest one' do
54
+ expect(resolver.find_latest_ami(filter).image_id).to eq '2'
55
+ end
56
+ end
57
+
58
+ context 'when no matches are found' do
59
+ before do
60
+ ec2.stub_responses(:describe_images, images: [])
61
+ end
62
+
63
+ it 'returns nil' do
64
+ expect(resolver.find_latest_ami(filter)).to be_nil
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,46 @@
1
+ RSpec.describe StackMaster::ParameterResolvers::LatestAmi do
2
+ let(:config) { double(base_dir: '/base') }
3
+ let(:stack_definition) { double(stack_name: 'mystack', region: 'us-east-1') }
4
+ subject(:resolver) { described_class.new(config, stack_definition) }
5
+ let(:ec2) { Aws::EC2::Client.new }
6
+
7
+ before do
8
+ allow(Aws::EC2::Client).to receive(:new).and_return(ec2)
9
+ end
10
+
11
+ context 'when matches are found' do
12
+ before do
13
+ ec2.stub_responses(:describe_images, images: [
14
+ { image_id: '1', creation_date: '2015-01-02 00:00:00', name: 'foo' },
15
+ { image_id: '2', creation_date: '2015-01-03 00:00:00', name: 'foo' }
16
+ ])
17
+ end
18
+
19
+ it 'returns the latest one' do
20
+ expect(resolver.resolve('filters' => {'name' => 'foo'})).to eq '2'
21
+ end
22
+ end
23
+
24
+ context 'when no matches are found' do
25
+ before do
26
+ ec2.stub_responses(:describe_images, images: [])
27
+ end
28
+
29
+ it 'returns nil' do
30
+ expect(resolver.resolve('filters' => {'name' => 'foo'})).to be_nil
31
+ end
32
+ end
33
+
34
+ context 'when an owner_id is passed' do
35
+ let(:ami_finder) { StackMaster::ParameterResolvers::AmiFinder.new('us-east-1') }
36
+ before do
37
+ expect(StackMaster::ParameterResolvers::AmiFinder).to receive(:new).and_return(ami_finder)
38
+ allow(ami_finder).to receive(:build_filters_from_hash).and_call_original
39
+ end
40
+
41
+ it 'calls find_latest_ami with the owner and filters' do
42
+ expect(ami_finder).to receive(:find_latest_ami).with([{name: 'foo', values: ['bacon']}], ['123456'])
43
+ resolver.resolve({'owners' => 123456, 'filters' => {'foo' => 'bacon'} })
44
+ end
45
+ end
46
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stack_master
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Hodgkiss
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-07 00:00:00.000000000 Z
12
+ date: 2016-05-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -335,6 +335,8 @@ files:
335
335
  - lib/stack_master/paged_response_accumulator.rb
336
336
  - lib/stack_master/parameter_loader.rb
337
337
  - lib/stack_master/parameter_resolver.rb
338
+ - lib/stack_master/parameter_resolvers/ami_finder.rb
339
+ - lib/stack_master/parameter_resolvers/latest_ami.rb
338
340
  - lib/stack_master/parameter_resolvers/latest_ami_by_tags.rb
339
341
  - lib/stack_master/parameter_resolvers/secret.rb
340
342
  - lib/stack_master/parameter_resolvers/security_group.rb
@@ -385,7 +387,9 @@ files:
385
387
  - spec/stack_master/paged_response_accumulator_spec.rb
386
388
  - spec/stack_master/parameter_loader_spec.rb
387
389
  - spec/stack_master/parameter_resolver_spec.rb
388
- - spec/stack_master/parameter_resolvers/latest_ami_by_tag_spec.rb
390
+ - spec/stack_master/parameter_resolvers/ami_finder_spec.rb
391
+ - spec/stack_master/parameter_resolvers/latest_ami_by_tags_spec.rb
392
+ - spec/stack_master/parameter_resolvers/latest_ami_spec.rb
389
393
  - spec/stack_master/parameter_resolvers/secret_spec.rb
390
394
  - spec/stack_master/parameter_resolvers/security_group_spec.rb
391
395
  - spec/stack_master/parameter_resolvers/security_groups_spec.rb
@@ -435,7 +439,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
435
439
  version: '0'
436
440
  requirements: []
437
441
  rubyforge_project:
438
- rubygems_version: 2.4.5.1
442
+ rubygems_version: 2.2.2
439
443
  signing_key:
440
444
  specification_version: 4
441
445
  summary: StackMaster is a sure-footed way of creating, updating and keeping track
@@ -473,7 +477,9 @@ test_files:
473
477
  - spec/stack_master/paged_response_accumulator_spec.rb
474
478
  - spec/stack_master/parameter_loader_spec.rb
475
479
  - spec/stack_master/parameter_resolver_spec.rb
476
- - spec/stack_master/parameter_resolvers/latest_ami_by_tag_spec.rb
480
+ - spec/stack_master/parameter_resolvers/ami_finder_spec.rb
481
+ - spec/stack_master/parameter_resolvers/latest_ami_by_tags_spec.rb
482
+ - spec/stack_master/parameter_resolvers/latest_ami_spec.rb
477
483
  - spec/stack_master/parameter_resolvers/secret_spec.rb
478
484
  - spec/stack_master/parameter_resolvers/security_group_spec.rb
479
485
  - spec/stack_master/parameter_resolvers/security_groups_spec.rb