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

Example listing and filtering EC2 instances and using stubs #3

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--color
--require spec_helper
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
source 'https://rubygems.org'
gem 'aws-sdk', '~> 2.0.22'
gem 'uuid', '~> 2.3.7'

group :test do
gem 'rspec', '~> 3.2'
end
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ You can also install the SDK directly with:
## Basic Configuration

You need to set up your AWS security credentials before the sample code is able
to connect to AWS. You can do this by creating a file named "credentials" at ~/.aws/
to connect to AWS. You can do this by creating a file named "credentials" at ~/.aws/
(C:\Users\USER_NAME\.aws\ for Windows users) and saving the following lines in the file:

[default]
Expand All @@ -37,6 +37,28 @@ you need to do is run it:
The S3 documentation has a good overview of the [restrictions for bucket names](http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html)
for when you start making your own buckets.

## Running the InstanceManager sample

This sample application connects to Amazon's [Elastic Compute Cloud (EC2)](http://aws.amazon.com/ec2/),
lists the available instances, filters them based on Name tag, and then prints
useful information about each instance.

All you need to do is run it:

ruby list_instances.rb

The default regular expression will probably not match any instances in your
account. To list all instances run:

ruby list_instances.rb '.*'

RSpec tests for `InstanceManager` are included to demonstrate use of
[ClientStubs](http://docs.aws.amazon.com/sdkforruby/api/Aws/ClientStubs.html).

Execute rspec to run all the tests:

rspec

## License

This sample application is distributed under the
Expand Down
42 changes: 42 additions & 0 deletions lib/instance_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require "aws-sdk"

# An example using AWS Ruby SDK v2 to list and filter EC2 instances.
class InstanceManager
# By default manage EC2 instance whose Name tag matches this pattern.
DEFAULT_NAME_RE = /^example-\d+$/

attr_reader :ec2_resource
attr_reader :name_re

# @param instance [Aws::EC2::Instance]
# @return [String] Instance name as judged by its Name tag.
def self.instance_name(instance)
name_tag = instance.tags.find { |t| t.key == "Name" }
name_tag.value if name_tag
end

# @param ec2_client [Aws::EC2::Client]
# @param name_re [Regexp] Manage EC2 instance whose Name tag matches this
# pattern.
def initialize(ec2_client, name_re = DEFAULT_NAME_RE)
@ec2_resource = Aws::EC2::Resource.new(:client => ec2_client)
@name_re = name_re
end

# @return [Array<Aws::EC2::Instance>] Instance whose Name tag matches the
# given pattern.
def instances
ec2_resource.instances.select { |i| name_matches?(i) }
end

protected

# @param instance [Aws::EC2::Instance]
# @return [Boolean] true if the given instance has a Name tag that matches
# the requested pattern.
def name_matches?(instance)
name = self.class.instance_name(instance)
name && name.match(name_re)
end

end
18 changes: 18 additions & 0 deletions list_instances.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env ruby

lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "instance_manager"

name_re = Regexp.new(ARGV[0] || InstanceManager::DEFAULT_NAME_RE)
client = Aws::EC2::Client.new(:region => 'us-east-1')
manager = InstanceManager.new(client, name_re)

puts "Listing instances with Name tag matching #{manager.name_re}"

manager.instances.each do |instance|
name = InstanceManager.instance_name(instance)
# Stopped instances do not have any private IP address.
private_ip_display = " (#{instance.private_ip_address})" if instance.private_ip_address
puts "#{name} (#{instance.id}) => #{instance.state.name}#{private_ip_display}"
end
29 changes: 29 additions & 0 deletions spec/ec2_stub_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require "aws-sdk"

RSpec.describe Aws::EC2 do
let(:client) { Aws::EC2::Client.new(:region => 'us-east-1', :stub_responses => true) }
let(:resource) { Aws::EC2::Resource.new(:client => client) }

context "when describe_instances is stubbed to return a single instance" do
before do
client.stub_responses(
:describe_instances, {
:next_token => nil,
:reservations => [{:instances=>[{:instance_id => "i-1", :state => {:name => "running"}, :tags =>[{:key => "Name", :value => "example-1" }]}]}]
}
)

end
context Aws::EC2::Client do
it "#describe_instances to return 1 instance" do
expect(client.describe_instances.reservations.first.instances.size).to eq 1
end
end

context Aws::EC2::Resource do
it "#instances to return 1 instance" do
expect(resource.instances.to_a.size).to eq 1
end
end
end
end
59 changes: 59 additions & 0 deletions spec/instance_manager_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require "instance_manager"
RSpec.describe InstanceManager do
let(:ec2_client) do
Aws::EC2::Client.new(:region => 'us-east-1', :stub_responses => true)
end

subject do
described_class.new(ec2_client)
end

context "#instances" do
before do
ec2_client.stub_responses(
:describe_instances,
{
:next_token => nil,
:reservations => [{ :instances => [
{
:instance_id => "i-1",
:state => {:name => "running" },
:tags => [
{ :key => "Name", :value => "example-1" },
{ :key => "color", :value => "red" },
]
},
{
:instance_id => "i-2",
:state => {:name => "running" },
:tags => [
{ :key => "Name", :value => "example-2" },
{ :key => "color", :value => "green" },
]
},
{
:instance_id => "i-3",
:state => {:name => "running" },
:tags => [
{ :key => "Name", :value => "webapp-3" },
{ :key => "color", :value => "green" },
]
},
{
:instance_id => "i-4",
:state => {:name => "stopped" },
:tags => [],
},
]}]},
)
end

it "returns two matching EC2 instances" do
expect(subject.instances.to_a.size).to eq 2
end

it "returns only EC2 instances with matching Name tag" do
expect(subject.instances.map(&:id)).to eq ["i-1", "i-2"]
end
end
end
15 changes: 15 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This is the configuration recommended by rspec --init with RSpec 3.2.0
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.filter_run :focus
config.run_all_when_everything_filtered = true
config.disable_monkey_patching!
config.default_formatter = 'doc' if config.files_to_run.one?
config.order = :random
Kernel.srand config.seed
end