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 +4 -4
- data/README.md +18 -0
- data/lib/stack_master.rb +2 -0
- data/lib/stack_master/parameter_resolvers/ami_finder.rb +36 -0
- data/lib/stack_master/parameter_resolvers/latest_ami.rb +19 -0
- data/lib/stack_master/parameter_resolvers/latest_ami_by_tags.rb +3 -23
- data/lib/stack_master/version.rb +1 -1
- data/spec/stack_master/parameter_resolvers/ami_finder_spec.rb +68 -0
- data/spec/stack_master/parameter_resolvers/{latest_ami_by_tag_spec.rb → latest_ami_by_tags_spec.rb} +0 -0
- data/spec/stack_master/parameter_resolvers/latest_ami_spec.rb +46 -0
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e9fbbd483a550665172b60c679b887fcad750ac
|
4
|
+
data.tar.gz: 6be2fc55ee1c3bdb20b54f8e807b7482ac6000a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 =
|
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
|
data/lib/stack_master/version.rb
CHANGED
@@ -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
|
data/spec/stack_master/parameter_resolvers/{latest_ami_by_tag_spec.rb → latest_ami_by_tags_spec.rb}
RENAMED
File without changes
|
@@ -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
|
+
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-
|
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/
|
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.
|
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/
|
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
|