-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create latest_container resolver #250
Changes from 1 commit
f237392
3562290
8037b2e
cf54b23
4e84303
510dd94
acd2bc6
077203c
30c041d
794df12
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
module StackMaster | ||
module ParameterResolvers | ||
class LatestContainer < Resolver | ||
array_resolver class_name: 'LatestContainers' | ||
|
||
def initialize(config, stack_definition) | ||
@config = config | ||
@stack_definition = stack_definition | ||
end | ||
|
||
def resolve(parameters) | ||
@region = parameters['region'] || @stack_definition.region | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe space this function out a bit to make it easier to understand logical groupings, eg: def resolve(parameters)
if parameters['repository_name'].nil?
raise ArgumentError, "repository_name parameter is required but was not supplied"
end
@region = parameters['region'] || @stack_definition.region
ecr_client = Aws::ECR::Client.new(region: @region)
images = fetch_images(parameters['repository_name'], parameters['registry_id'], ecr_client)
return nil if images.empty?
if !parameters['tag'].nil?
images.select! { |image| image.image_tags.any? { |tag| tag == parameters['tag'] } }
end
images.sort! { |image_x, image_y| image_y.image_pushed_at <=> image_x.image_pushed_at }
latest_image = images.first
# aws_account_id.dkr.ecr.region.amazonaws.com/repository@sha256:digest
"#{latest_image.registry_id}.dkr.ecr.#{@region}.amazonaws.com/#{parameters['repository_name']}@#{latest_image.image_digest}"
end |
||
ecr_client = Aws::ECR::Client.new(region: @region) | ||
if parameters['repository_name'].nil? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is registry_id also a required parameter? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, as per the documentation it's only needed if you're fetching a container from a different account There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NM, I see the default now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, no I don't, the docs say it should default but I don't see the defaulting happening. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The API handles this for us. If we don't specify a registry ID, it defaults to the current account There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perfect, no need for tests then either :-) |
||
raise ArgumentError, "repository_name parameter is required but was not supplied" | ||
end | ||
images = fetch_images(parameters['repository_name'], parameters['registry_id'], ecr_client) | ||
return nil if images.empty? | ||
images.sort! { |image_x, image_y| image_y.image_pushed_at <=> image_x.image_pushed_at } | ||
latest_image = images.first | ||
latest_tag = latest_image.image_tags.delete_if { |tag| tag == "latest" }.first | ||
# aws_account_id.dkr.ecr.region.amazonaws.com | ||
return "#{latest_image.registry_id}.dkr.ecr.#{@region}.amazonaws.com/#{parameters['repository_name']}:#{latest_tag}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the tag safe to use here? Wouldn't we be better with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only an issue if you use mutable tags like "production". I don't think that's good practice so while I wouldn't object to such a change I don't think we should prioritise it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, recent events have made me question this view. |
||
end | ||
|
||
private | ||
|
||
def fetch_images(repository_name, registry_id, ecr) | ||
images = [] | ||
next_token = nil | ||
while | ||
resp = ecr.describe_images({ | ||
repository_name: repository_name, | ||
registry_id: registry_id, | ||
next_token: next_token, | ||
}) | ||
|
||
images.push(resp.image_details) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this will create an array of arrays containing Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I flatten it later but that's a better way |
||
next_token = resp.next_token | ||
|
||
if resp.next_token.nil? | ||
break | ||
end | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: begin/end/while is an alternative.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This breaks one of my tests... and not the pagination test I just added. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, looks like it should be |
||
images.flatten | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
RSpec.describe StackMaster::ParameterResolvers::LatestContainer do | ||
let(:config) { double(base_dir: '/base') } | ||
let(:stack_definition) { double(stack_name: 'mystack', region: 'us-east-1') } | ||
subject(:resolver) { described_class.new(config, stack_definition) } | ||
let(:ecr) { Aws::ECR::Client.new(stub_responses: true) } | ||
|
||
before do | ||
allow(Aws::ECR::Client).to receive(:new).and_return(ecr) | ||
end | ||
|
||
context 'when matches are found' do | ||
before do | ||
ecr.stub_responses(:describe_images, image_details: [ | ||
{ registry_id: '012345678910', image_digest: 'decafc0ffee', image_pushed_at: Time.utc(2015,1,2,0,0), image_tags: ['v1'] }, | ||
{ registry_id: '012345678910', image_digest: 'deadbeef', image_pushed_at: Time.utc(2015,1,3,0,0), image_tags: ['v2'] } | ||
]) | ||
end | ||
|
||
it 'returns the latest one' do | ||
expect(resolver.resolve({'repository_name' => 'foo'})).to eq '012345678910.dkr.ecr.us-east-1.amazonaws.com/foo:v2' | ||
end | ||
end | ||
|
||
context 'when there are multiple tags including latest' do | ||
before do | ||
ecr.stub_responses(:describe_images, image_details: [ | ||
{ registry_id: '012345678910', image_digest: 'decafc0ffee', image_pushed_at: Time.utc(2015,1,2,0,0), image_tags: ['v1'] }, | ||
{ registry_id: '012345678910', image_digest: 'deadbeef', image_pushed_at: Time.utc(2015,1,3,0,0), image_tags: ['latest', 'v2'] } | ||
]) | ||
end | ||
|
||
it 'does not return the latest tag' do | ||
expect(resolver.resolve({'repository_name' => 'foo'})).to eq '012345678910.dkr.ecr.us-east-1.amazonaws.com/foo:v2' | ||
end | ||
end | ||
|
||
context 'when no matches are found' do | ||
before do | ||
ecr.stub_responses(:describe_images, image_details: []) | ||
end | ||
|
||
it 'returns nil' do | ||
expect(resolver.resolve({'repository_name' => 'foo'})).to be_nil | ||
end | ||
end | ||
|
||
context 'when registry_id is passed in' do | ||
before do | ||
ecr.stub_responses(:describe_images, image_details: [ | ||
{ registry_id: '012345678910', image_digest: 'decafc0ffee', image_pushed_at: Time.utc(2015,1,2,0,0), image_tags: ['v1'] }, | ||
]) | ||
end | ||
|
||
it 'passes registry_id to describe_images' do | ||
expect(ecr).to receive(:describe_images).with(repository_name: "foo", registry_id: "012345678910", next_token: nil) | ||
resolver.resolve({'repository_name' => 'foo', 'registry_id' => "012345678910"}) | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a fun thing to find out the hard way.