Skip to content
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

Add support for looking up AMIs with the EC2 API #177

Merged
merged 5 commits into from
Oct 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,23 @@ token) through config. See the `aws_access_key_id` and `aws_secret_access_key`
config sections below to see how to specify these in your .kitchen.yml or
through environment variables. If you would like to specify your session token
use the environment variable `AWS_SESSION_TOKEN`.
1. The shared credentials ini file at `~/.aws/credentials`. You can specify
1. The shared credentials ini file at `~/.aws/credentials`. You can specify
multiple profiles in this file and select one with the `AWS_PROFILE`
environment variable or the `shared_credentials_profile` driver config. Read
[this][credentials_docs] for more information.
1. From an instance profile when running on EC2. This accesses the local
metadata service to discover the local instance's IAM instance profile.

This precedence order is taken from http://docs.aws.amazon.com/sdkforruby/api/index.html#Configuration

The first method attempted that works will be used. IE, if you want to auth
using the instance profile, you must not set any of the access key configs
or environment variables, and you must not specify a `~/.aws/credentials`
file.

Because the Test Kitchen test should be checked into source control and ran
through CI we no longer recommend storing the AWS credentials in the
`.kitchen.yml` file. Instead, specify them as environment variables or in the
`.kitchen.yml` file. Instead, specify them as environment variables or in the
`~/.aws/credentials` file.

## Windows Configuration
Expand Down Expand Up @@ -186,6 +186,18 @@ The default will be determined by the `aws_region` chosen and the Platform
name, if a default exists (see [amis.json][ami_json]). If a default cannot be
computed, then the default is `nil`.

### image\_search

Searches the EC2 API for the latest AMI ID that matches the given [filters](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html).

For example, a search for the latest AMI that matches a given image name looks
like:

```yaml
image_search:
name: Windows_Server-2012-R2_RTM-English-64Bit-Base-*
```

### region

**Required** The AWS [region][region_docs] to use.
Expand Down
13 changes: 13 additions & 0 deletions lib/kitchen/driver/ec2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,17 @@ def destroy(state)
state.delete(:hostname)
end

def lookup_ami(filters_hash)
filters = []
filters_hash.each do |key, value|
filters.push(:name => key.to_s, :values => Array(value))
end
images = ec2.resource.images(:filters => filters).sort do |ami1, ami2|
Time.parse(ami1.creation_date) <=> Time.parse(ami2.creation_date)
end
images.last && images.last.id
end

def ubuntu_ami(region, platform_name)
release = amis["ubuntu_releases"][platform_name]
Ubuntu.release(release).amis.find do |ami|
Expand All @@ -251,6 +262,8 @@ def default_ami
if instance.platform.name.start_with?("ubuntu")
ami = ubuntu_ami(config[:region], instance.platform.name)
ami && ami.name
elsif !config[:image_search].nil?
lookup_ami(config[:image_search])
else
region = amis["regions"][config[:region]]
region && region[instance.platform.name]
Expand Down
55 changes: 55 additions & 0 deletions spec/kitchen/driver/ec2_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,50 @@
end
end

describe "#lookup_ami" do
let(:resource) { double("actual resource") }

let(:filters) { { :name => "ami_name" } }
let(:aws_filters) do
{ :filters => [{ :name => "name", :values => ["ami_name"] }] }
end

before do
allow(client).to receive(:resource).and_return(resource)
end

context "when one ami found" do
let(:ami_id) { "ami-a1b2c3d4" }
let(:date) { "2015-06-10T03:47:20.000Z" }
let(:ami_list) { [double("ami", :id => ami_id, :creation_date => date)] }

it "returns the ami id" do
expect(resource).to receive(:images).with(aws_filters). \
and_return(ami_list)
expect(driver.lookup_ami(filters)).to eq(ami_id)
end
end

context "when more than one ami found" do
let(:date_older) { "2015-06-10T03:47:20.000Z" }
let(:date_newer) { "2015-06-11T03:47:20.000Z" }
let(:ami_id_older) { "ami-a1b2c3d4" }
let(:ami_id_newer) { "ami-e5f6g7h8" }
let(:ami_list) do
[
double("ami", :id => ami_id_older, :creation_date => date_older),
double("ami", :id => ami_id_newer, :creation_date => date_newer)
]
end

it "returns most recently created ami id" do
expect(resource).to receive(:images).with(aws_filters). \
and_return(ami_list)
expect(driver.lookup_ami(filters)).to eq(ami_id_newer)
end
end
end

describe "#default_ami" do
context "when platform is ubuntu" do
let(:config) { { :aws_ssh_key_id => "key" } }
Expand All @@ -436,6 +480,17 @@
expect(driver.default_ami).to eq(ami_data[0])
end
end

context "when ami_search is provided" do
let(:config) { { :image_search => {} } }
let(:ami_id) { "ami-xxxxxxxx" }

it "searches for an image id" do
expect(driver).to receive(:lookup_ami).with(config[:image_search]). \
and_return(ami_id)
expect(driver.default_ami).to eq(ami_id)
end
end
end

end