stack_master 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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