ey_aws 0.9

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source :rubygems
2
+
3
+ gem 'aws-sdk'
4
+ gem 'rest-client'
5
+ gem 'rake'
6
+
7
+ group :test do
8
+ gem 'rspec'
9
+ gem 'webmock'
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.3.2)
5
+ aws-sdk (1.3.4)
6
+ httparty (~> 0.7)
7
+ json (~> 1.4)
8
+ nokogiri (>= 1.4.4)
9
+ uuidtools (~> 2.1)
10
+ crack (0.3.1)
11
+ diff-lcs (1.1.3)
12
+ httparty (0.8.1)
13
+ multi_json
14
+ multi_xml
15
+ json (1.6.5)
16
+ mime-types (1.19)
17
+ multi_json (1.1.0)
18
+ multi_xml (0.4.1)
19
+ nokogiri (1.5.0)
20
+ rake (0.9.2.2)
21
+ rest-client (1.6.7)
22
+ mime-types (>= 1.16)
23
+ rspec (2.11.0)
24
+ rspec-core (~> 2.11.0)
25
+ rspec-expectations (~> 2.11.0)
26
+ rspec-mocks (~> 2.11.0)
27
+ rspec-core (2.11.1)
28
+ rspec-expectations (2.11.3)
29
+ diff-lcs (~> 1.1.3)
30
+ rspec-mocks (2.11.3)
31
+ uuidtools (2.1.2)
32
+ webmock (1.8.11)
33
+ addressable (>= 2.2.7)
34
+ crack (>= 0.1.7)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ aws-sdk
41
+ rake
42
+ rest-client
43
+ rspec
44
+ webmock
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 James Martelletti
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # EYAWS
2
+
3
+ ey_aws will connect EngineYard and AWS to and retrieve environment and instance
4
+ data from both, this allows us to view which environments we have and metadata
5
+ for each instance which makes up each enironment. It can be useful to find out
6
+ instance sizes, IP addresses and attached storage for each running instance.
7
+
8
+ ## Installation
9
+
10
+ gem install ey_aws
11
+
12
+ ## Usage
13
+
14
+ This gem may be used from the command line to display a formatted Hash
15
+ describing all your environments and instances. If running from the command
16
+ line you must set some environment variables before executing ey_aws.
17
+
18
+ ACCESS_KEY_ID/SECRET_ACCESS_KEY are required for AWS authentication, and
19
+ EY_CLOUD_TOKEN (which can be found in ~/.eyrc) for EngineYard.
20
+
21
+ From the command line
22
+
23
+ export ACCESS_KEY_ID='...'
24
+ export SECRET_ACCESS_KEY='...'
25
+ export EY_CLOUD_TOKEN='...'
26
+ ey_aws
27
+
28
+ Or from your application
29
+
30
+ require 'ey_aws'
31
+
32
+ data = EYAWS.new({
33
+ :access_key_id => 'AWS_ACCESS_KEY',
34
+ :secret_access_key => 'AWS_SECRET_KEY',
35
+ :ey_cloud_token => 'EY_CLOUD_TOKEN' })
36
+
37
+ pp data[:environments]
38
+
39
+ ## Output
40
+
41
+ {:id=>12345,
42
+ :name=>"environment_name",
43
+ :ssh_username=>"deploy",
44
+ :app_server_stack_name=>"nginx_unicorn",
45
+ :framework_env=>"production",
46
+ :instance_status=>"running",
47
+ :instances_count=>2,
48
+ :load_balancer_ip_address=>"12.34.45.67",
49
+ :account=>{:id=>1234, :name=>"account"},
50
+ :stack_name=>"nginx_unicorn",
51
+ :instances=>
52
+ [{:id=>"i-sd9d123d2",
53
+ :status=>:running,
54
+ :role=>"app_master",
55
+ :name=>nil,
56
+ :amazon_id=>"i-3d932j233",
57
+ :public_hostname=> "ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com",
58
+ :bridge=>true,
59
+ :ami_launch_index=>0,
60
+ :architecture=>:i386,
61
+ :client_token=>nil,
62
+ :dns_name=>"ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com",
63
+ :hypervisor=>:xen,
64
+ :image_id=>"ami-12dj883",
65
+ :instance_type=>"c1.medium",
66
+ :ip_address=>"12.23.23.34",
67
+ :kernel_id=>"aki-dc09a2dd",
68
+ :key_name=>nil,
69
+ :launch_time=>2012-06-13 23:14:52 UTC,
70
+ :monitoring=>:disabled,
71
+ :owner_id=>"259285985555",
72
+ :platform=>nil,
73
+ :private_dns_name=>"ip-10-0-0-127.ap-northeast-1.compute.internal",
74
+ :private_ip_address=>"10.0.0.127",
75
+ :ramdisk_id=>nil,
76
+ :requester_id=>nil,
77
+ :reservation_id=>"r-72313355",
78
+ :root_device_name=>nil,
79
+ :root_device_type=>:instance_store,
80
+ :state_transition_reason=>nil,
81
+ :status_code=>16,
82
+ :subnet_id=>nil,
83
+ :virtualization_type=>:paravirtual,
84
+ :vpc_id=>nil,
85
+ :availability_zone=>"ap-northeast-1a",
86
+ :dedicated_tenancy?=>false,
87
+ :exists?=>true,
88
+ :has_elastic_ip?=>true,
89
+ :monitoring_enabled?=>false,
90
+ :spot_instance?=>false,
91
+ :key_pair=>nil,
92
+ :block_device_mappings=>
93
+ [{:device=>"/dev/sdz1",
94
+ :attach_time=>2012-06-13 23:15:59 UTC,
95
+ :delete_on_termination?=>false,
96
+ :exists?=>true,
97
+ :status=>:attached,
98
+ :volume=>
99
+ {:id=>"vol-dbafs2eba",
100
+ :availability_zone_name=>"ap-northeast-1a",
101
+ :create_time=>2012-06-13 23:15:55 UTC,
102
+ :size=>5,
103
+ :status=>:in_use,
104
+ :exists?=>true}}]}],
105
+ :app_master=>
106
+ {:id=>153125,
107
+ :status=>"running",
108
+ :role=>"app_master",
109
+ :name=>nil,
110
+ :amazon_id=>"i-hf923h9f",
111
+ :public_hostname=>"ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com",
112
+ :bridge=>true},
113
+ :apps=>
114
+ [{:id=>15085,
115
+ :name=>"appname",
116
+ :repository_uri=>"git@github.com:org/repo.git",
117
+ :app_type_id=>"rails3",
118
+ :account=>{:id=>1234, :name=>"account"}}],
119
+ :deployment_configurations=>
120
+ {:appname=>
121
+ {:id=>46952,
122
+ :domain_name=>"environment.net",
123
+ :uri=>"http://environment.net",
124
+ :migrate=>{:perform=>false, :command=>""},
125
+ :name=>"appname",
126
+ :repository_uri=>"git@github.com:org/repo.git"}}}
127
+
128
+ ## Testing
129
+
130
+ bundle exec rake spec
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ Bundler.require :development
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |task|
8
+ task.rspec_opts = [ '-c', '-f documentation' ]
9
+ task.pattern = 'spec/**/*_spec.rb'
10
+ end
11
+
12
+ task :default => :spec
data/bin/ey_aws ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../lib/ey_aws', __FILE__)
3
+ require 'pp'
4
+
5
+ newco = EYAWS.new
6
+ pp newco[:environments]
data/ey_aws.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ require File.expand_path('../lib/ey_aws/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "ey_aws"
5
+ gem.version = EYAWS::VERSION
6
+ gem.authors = [ "James Martelletti" ]
7
+ gem.email = [ "james@hooroo.com" ]
8
+
9
+ gem.summary = "EngineYard & AWS environment/host information"
10
+ gem.description = "Retrieve your EngineYard & AWS environment/host info via APIs"
11
+ gem.homepage = "http://github.com/hooroo/ey_aws"
12
+
13
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.test_files = `git ls-files -- spec/*`.split("\n")
16
+
17
+ gem.add_development_dependency "rspec", "~>2.7"
18
+ end
@@ -0,0 +1,3 @@
1
+ module EYAWS
2
+ VERSION = '0.9'
3
+ end
data/lib/ey_aws.rb ADDED
@@ -0,0 +1,93 @@
1
+ #require 'rest'
2
+ require 'rest_client'
3
+ require 'json'
4
+ require 'aws-sdk'
5
+
6
+ class EYAWS < Hash
7
+ attr_reader :environments
8
+
9
+ URL = 'https://cloud.engineyard.com/api/v2/environments'
10
+ AWS_ATTRIBUTES = [
11
+ :ami_launch_index,:architecture, :client_token, :dns_name, :hypervisor,
12
+ :id, :image_id, :instance_type, :ip_address, :kernel_id,
13
+ :key_name, :launch_time, :monitoring, :owner_id, :platform,
14
+ :private_dns_name, :private_ip_address, :ramdisk_id, :requester_id, :reservation_id,
15
+ :root_device_name, :root_device_type, :state_transition_reason, :status, :status_code,
16
+ :subnet_id, :virtualization_type, :vpc_id, :availability_zone, :dedicated_tenancy?,
17
+ :exists?, :has_elastic_ip?, :monitoring_enabled?, :spot_instance?, :key_pair ]
18
+ AWS_DEVICE_ATTRIBUTES = [ :device, :attach_time, :delete_on_termination?, :exists?, :status ]
19
+ AWS_VOLUME_ATTRIBUTES = [ :id, :availability_zone_name, :create_time, :size, :status, :exists? ]
20
+
21
+ def initialize(opts={})
22
+ regions = []
23
+
24
+ access_key_id = opts[:access_key_id] ? opts[:access_key_id] : ENV['ACCESS_KEY_ID']
25
+ secret_access_key = opts[:secret_access_key] ? opts[:secret_access_key] : ENV['SECRET_ACCESS_KEY']
26
+ ey_cloud_token = opts[:ey_cloud_token] ? opts[:ey_cloud_token] : ENV['EY_CLOUD_TOKEN']
27
+
28
+ raise "No ACCESS_KEY_ID supplied" if access_key_id.nil?
29
+ raise "No SECRET_ACCESS_KEY supplied" if secret_access_key.nil?
30
+ raise "No EY_CLOUD_TOKEN supplied" if ey_cloud_token.nil?
31
+
32
+ # Get EY environment info
33
+ @data = JSON.parse(RestClient.get(URL, 'X-EY-Cloud-Token' => ey_cloud_token).body, :symbolize_names => true)
34
+
35
+ # Figure out the region each EY host lives in
36
+ @data[:environments].each do |e|
37
+ e[:instances].each do |i|
38
+ regions << i[:public_hostname].split('.')[1]
39
+ end
40
+ end
41
+
42
+ # Clean up regions array, us-east-1 region appears to have different hostnames
43
+ regions.uniq!
44
+ regions << 'us-east-1' if regions.reject! { |r| r == 'compute-1' }
45
+
46
+ # Request instance info for each region
47
+ regions.each do |region|
48
+ ec2 = AWS::EC2.new(:access_key_id => access_key_id, :secret_access_key => secret_access_key)
49
+ AWS.memoize do
50
+ ec2.regions[region.to_s].instances.each do |inst|
51
+ add_aws_info(inst)
52
+ end
53
+ end
54
+ end
55
+
56
+ self.merge!(@data)
57
+ end
58
+
59
+ private
60
+ def add_aws_info(inst)
61
+ # Grab all our aws attributes
62
+ aws_attributes = {}
63
+ AWS_ATTRIBUTES.each do |attr|
64
+ aws_attributes[attr] = inst.send(attr.to_s)
65
+ end
66
+
67
+ # Find the instance to attach this stuff to
68
+ instance = @data[:environments].map { |e|
69
+ e[:instances].select { |i| i[:amazon_id] == aws_attributes[:id] }
70
+ }.flatten!.first
71
+
72
+ # Now grab all the block attributes
73
+ block_devices = []
74
+ inst.block_device_mappings.each do |mnt, device|
75
+ block_device = {}
76
+ AWS_DEVICE_ATTRIBUTES.map do |dattr|
77
+ block_device[dattr] = device.send(dattr.to_s)
78
+ end
79
+
80
+ # And the volume...
81
+ volume = {}
82
+ AWS_VOLUME_ATTRIBUTES.map do |vattr|
83
+ volume[vattr] = device.volume.send(vattr.to_s)
84
+ end
85
+ block_device[:volume] = volume
86
+
87
+ block_devices << block_device
88
+ end
89
+ aws_attributes[:block_device_mappings] = block_devices
90
+
91
+ instance.merge!(aws_attributes)
92
+ end
93
+ end
@@ -0,0 +1,77 @@
1
+ require File.expand_path('../../lib/ey_aws', __FILE__)
2
+ require 'aws-sdk'
3
+ require 'webmock/rspec'
4
+
5
+ CONFIG = {
6
+ :access_key_id => 'ACCESS_KEY_ID',
7
+ :secret_access_key => 'SECRET_ACCESS_KEY',
8
+ :ey_cloud_token => 'EY_CLOUD_TOKEN' }
9
+
10
+ describe EYAWS do
11
+ let(:volume) { AWS::EC2::Volume.new('vol-abc123') }
12
+ let(:instance) { AWS::EC2::Instance.new('i-abcd1234') }
13
+ let(:attachment) { AWS::EC2::Attachment.new(volume, instance, '/dev/xxx') }
14
+
15
+ before(:each) do
16
+ # Stub AWS methods
17
+ volume.stub(:send).and_return('vol')
18
+ attachment.stub(:send).and_return('dev')
19
+ instance.stub(:send).and_return('i-abcd1234')
20
+ instance.stub_chain(:block_device_mappings, :each).and_yield("/dev/xxx", attachment)
21
+ AWS::EC2.any_instance.stub_chain(:regions, :[], :instances, :each).and_yield(instance)
22
+
23
+ # Stub EY data request
24
+ WebMock.enable!
25
+ WebMock.stub_request(:get, "https://cloud.engineyard.com/api/v2/environments").to_return(
26
+ :status => 200,
27
+ :body => File.read(File.join(File.dirname(__FILE__), 'support', 'cloud_engineyard_com.json'))).times(10)
28
+
29
+ # Delete existing environment variables
30
+ ENV.delete 'ACCESS_KEY_ID'
31
+ ENV.delete 'SECRET_ACCESS_KEY'
32
+ ENV.delete 'EY_CLOUD_TOKEN'
33
+ end
34
+
35
+ context "authentication" do
36
+ it "using environment variables" do
37
+ ENV['ACCESS_KEY_ID'] = 'ENV_ACCESS_KEY_ID'
38
+ ENV['SECRET_ACCESS_KEY'] = 'ENV_SECRET_ACCESS_KEY'
39
+ ENV['EY_CLOUD_TOKEN'] = 'EY_CLOUD_TOKEN'
40
+
41
+ expect { EYAWS.new }.to_not raise_error
42
+ end
43
+
44
+ it "using argument variables" do
45
+ expect { EYAWS.new(CONFIG) }.to_not raise_error
46
+ end
47
+
48
+ it "raise exception if no credentials" do
49
+ expect { EYAWS.new }.to raise_error RuntimeError
50
+ end
51
+ end
52
+
53
+ context "lookup" do
54
+ let(:data) { EYAWS.new(CONFIG) }
55
+ let(:environment) { data[:environments].first }
56
+
57
+ it "finds environment attributes" do
58
+ environment[:name].should == "environment_name"
59
+ end
60
+
61
+ it "finds instance attributes" do
62
+ environment[:instances].first[:id].should == 'i-abcd1234'
63
+ end
64
+
65
+ it "finds device attributes" do
66
+ environment[:instances].first[:block_device_mappings].first[:device].should == 'dev'
67
+ end
68
+
69
+ it "finds volume attributes" do
70
+ environment[:instances].first[:block_device_mappings].first[:volume][:id].should == 'vol'
71
+ end
72
+ end
73
+
74
+ it "returns a hash" do
75
+ EYAWS.new(CONFIG).should be_a(Hash)
76
+ end
77
+ end
@@ -0,0 +1,73 @@
1
+ {
2
+ "environments":[
3
+ {
4
+ "id":1234,
5
+ "name":"environment_name",
6
+ "ssh_username":"ssh_username",
7
+ "app_server_stack_name":"stack_name",
8
+ "framework_env":"production",
9
+ "instance_status":"running",
10
+ "instances_count":2,
11
+ "load_balancer_ip_address":"10.0.0.1",
12
+ "account":{
13
+ "id":9876,
14
+ "name":"accountname"
15
+ },
16
+ "stack_name":"stack_name",
17
+ "instances":[
18
+ {
19
+ "id":2345,
20
+ "status":"running",
21
+ "role":"db_master",
22
+ "name":null,
23
+ "amazon_id":"i-abcd1234",
24
+ "public_hostname":"ec2-10-0-0-2.region.domain.name.com",
25
+ "bridge":false
26
+ },
27
+ {
28
+ "id":3456,
29
+ "status":"running",
30
+ "role":"app_master",
31
+ "name":null,
32
+ "amazon_id":"i-abcd2345",
33
+ "public_hostname":"ec2-10-0-0-1.region.domain.name.com",
34
+ "bridge":true
35
+ }
36
+ ],
37
+ "app_master":{
38
+ "id":3456,
39
+ "status":"running",
40
+ "role":"app_master",
41
+ "name":null,
42
+ "amazon_id":"i-abcd2345",
43
+ "public_hostname":"ec2-10-0-0-1.region.domain.name.com",
44
+ "bridge":true
45
+ },
46
+ "apps":[
47
+ {
48
+ "id":8765,
49
+ "name":"app_name",
50
+ "repository_uri":"git@github.com:organisation/repo.git",
51
+ "app_type_id":"sinatra",
52
+ "account":{
53
+ "id":9876,
54
+ "name":"accountname"
55
+ }
56
+ }
57
+ ],
58
+ "deployment_configurations":{
59
+ "environment_name":{
60
+ "id":8765,
61
+ "domain_name":"environment-name.net",
62
+ "uri":"http://environment-name.net",
63
+ "migrate":{
64
+ "perform":false,
65
+ "command":null
66
+ },
67
+ "name":"api_driver",
68
+ "repository_uri":"git@github.com:organisation/repo.git"
69
+ }
70
+ }
71
+ }
72
+ ]
73
+ }
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ey_aws
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.9'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - James Martelletti
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70268252775260 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.7'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70268252775260
25
+ description: Retrieve your EngineYard & AWS environment/host info via APIs
26
+ email:
27
+ - james@hooroo.com
28
+ executables:
29
+ - ey_aws
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - Gemfile
34
+ - Gemfile.lock
35
+ - LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - bin/ey_aws
39
+ - ey_aws.gemspec
40
+ - lib/ey_aws.rb
41
+ - lib/ey_aws/version.rb
42
+ - spec/ey_aws_spec.rb
43
+ - spec/support/cloud_engineyard_com.json
44
+ homepage: http://github.com/hooroo/ey_aws
45
+ licenses: []
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ segments:
57
+ - 0
58
+ hash: -1802294364488782302
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubyforge_project:
67
+ rubygems_version: 1.8.17
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: EngineYard & AWS environment/host information
71
+ test_files:
72
+ - spec/ey_aws_spec.rb
73
+ - spec/support/cloud_engineyard_com.json