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 +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
|