ec2-starter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ gem "amazon-ec2", ">= 0.9.17"
5
+ gem 'net-ssh', '>= 2.1.4'
6
+
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "shoulda", ">= 0"
11
+ gem "bundler", "~> 1.0.0"
12
+ gem "jeweler", "~> 1.5.2"
13
+ gem "rcov", ">= 0"
14
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,26 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ amazon-ec2 (0.9.17)
5
+ xml-simple (>= 1.0.12)
6
+ git (1.2.5)
7
+ jeweler (1.5.2)
8
+ bundler (~> 1.0.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ net-ssh (2.1.4)
12
+ rake (0.9.2)
13
+ rcov (0.9.9)
14
+ shoulda (2.11.3)
15
+ xml-simple (1.1.0)
16
+
17
+ PLATFORMS
18
+ ruby
19
+
20
+ DEPENDENCIES
21
+ amazon-ec2 (>= 0.9.17)
22
+ bundler (~> 1.0.0)
23
+ jeweler (~> 1.5.2)
24
+ net-ssh (>= 2.1.4)
25
+ rcov
26
+ shoulda
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Oliver Kiessler
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,12 @@
1
+ ec2-starter
2
+ -----------
3
+
4
+ Very Ruby DSL to perform standard tasks on a single EC2 instance. With this you can start an instance, assign an IP, assign volumes and perform SSH shell commands.
5
+
6
+ See example.rb
7
+
8
+ Copyright
9
+ ---------
10
+
11
+ Copyright (c) 2011 Oliver Kiessler. See LICENSE.txt for
12
+ further details.
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ gem.name = "ec2-starter"
15
+ gem.homepage = "http://github.com/okiess/ec2-starter"
16
+ gem.license = "MIT"
17
+ gem.summary = %Q{Very simple EC2 instance starter}
18
+ gem.description = %Q{Very simple EC2 instance starter for single server deployments}
19
+ gem.email = "kiessler@inceedo.com"
20
+ gem.authors = ["Oliver Kiessler"]
21
+ gem.add_runtime_dependency 'amazon-ec2'
22
+ gem.add_development_dependency 'net-ssh'
23
+ end
24
+ Jeweler::RubygemsDotOrgTasks.new
25
+
26
+ require 'rake/testtask'
27
+ Rake::TestTask.new(:test) do |test|
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/**/test_*.rb'
30
+ test.verbose = true
31
+ end
32
+
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/test_*.rb'
37
+ test.verbose = true
38
+ end
39
+
40
+ task :default => :test
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
45
+
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = "ec2-starter #{version}"
48
+ rdoc.rdoc_files.include('README*')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/example.rb ADDED
@@ -0,0 +1,26 @@
1
+ require "lib/ec2-starter"
2
+
3
+ service_options = {
4
+ :access_key_id => "YOUR KEY",
5
+ :secret_access_key => "YOUR SECRET",
6
+ :server => "eu-west-1.ec2.amazonaws.com" # Target Zone
7
+ }
8
+
9
+ start_options = {
10
+ :instance_type => "t1.micro",
11
+ :key_name => "YOUR KEY",
12
+ :availability_zone => "eu-west-1a",
13
+ :architecture => "x86_64",
14
+ :kernel_id => 'aki-4feec43b', # your kernel, remove if not needed
15
+ :ssh_user => 'deploy',
16
+ :ssh_keys => ['/Users/your_user/.ssh/your_key']
17
+ :sudo_password => nil # set if necessary
18
+ }
19
+
20
+ Ec2Starter.start 'YOUR AMI_ID', service_options, start_options do
21
+ ip 'YOUR ELASTIC IP'
22
+ volume :volume_id => 'YOUR VOLUME', :mount_point => '/dev/sdf'
23
+
24
+ command :sudo => '/root/attach_volume.sh' # Shell command on the instance
25
+ command '/home/your_user/some_script.sh'
26
+ end
data/lib/.DS_Store ADDED
Binary file
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ gem "net-ssh"
3
+ require 'net/ssh'
4
+ gem 'amazon-ec2'
5
+ require 'AWS'
6
+
7
+ require File.dirname(__FILE__) + '/ec2-starter/starter'
8
+ require File.dirname(__FILE__) + '/ec2-starter/execution'
@@ -0,0 +1,148 @@
1
+ module Ec2Starter
2
+ class Execution
3
+ attr_accessor :ec2_instance, :dns_name
4
+
5
+ def initialize(ec2_instance)
6
+ @ec2_instance = ec2_instance
7
+ end
8
+
9
+ def start
10
+ success = false
11
+ result = launch_ami(@ec2_instance.ami_id)
12
+ instance_id = result.instancesSet.item[0].instanceId
13
+ puts "=> Starting Instance Id: #{instance_id.white}"
14
+
15
+ instance_state = nil
16
+ while(instance_state != 'running')
17
+ instance_state, @dns_name = get_instance_state(instance_id)
18
+ puts "=> Checking for running state... #{output_running_state(instance_state)}"
19
+ puts "=> Public DNS: #{@dns_name.white}" if instance_state == 'running'
20
+ sleep 10 unless instance_state == 'running'
21
+ end
22
+
23
+ if @ec2_instance.ips.size > 0
24
+ result = ec2.associate_address(:instance_id => instance_id, :public_ip => @ec2_instance.ips.first)
25
+ puts "=> Elastic IP: #{@ec2_instance.ips.first.white}" if result["return"] == "true"
26
+ else
27
+ skip_ip = true
28
+ end
29
+ if result["return"] == "true" or skip_ip
30
+ if @ec2_instance.volumes.size > 0
31
+ result = ec2.attach_volume(:volume_id => @ec2_instance.volumes.first[:volume_id], :instance_id => instance_id,
32
+ :device => @ec2_instance.volumes.first[:mount_point])
33
+
34
+ volume_state = nil
35
+ while(volume_state != 'attached')
36
+ volume_state = get_volume_state(@ec2_instance.volumes.first[:volume_id])
37
+ puts "=> Checking for attachment state... #{output_running_state(volume_state)}"
38
+ sleep 10 unless volume_state == 'attached'
39
+ end
40
+
41
+ success = true
42
+ puts "=> EBS Volume attached: #{@ec2_instance.volumes.first[:volume_id]}"
43
+ end
44
+ if @ec2_instance.commands.size > 0
45
+ ip = @ec2_instance.ips.first || @dns_name
46
+ system("ssh-keygen -R #{ip}")
47
+ i = 0
48
+ while(i < 3) do
49
+ begin
50
+ ssh
51
+ break
52
+ rescue => e
53
+ puts e.message
54
+ puts "Retrying in 10sec..."
55
+ sleep 10
56
+ end
57
+ i += 1
58
+ end
59
+ success = true
60
+ puts "=> SSH Commands were executed!"
61
+ end
62
+ else
63
+ puts "=> Could not assign Elastic IP!"
64
+ end
65
+
66
+ unless success
67
+ puts "Terminating instance: #{instance_id}".red
68
+ @ec2.terminate_instances(:instance_id => instance_id)
69
+ end
70
+ end
71
+
72
+ def ssh
73
+ ip = @ec2_instance.ips.first || @dns_name
74
+ Net::SSH.start(ip, @ec2_instance.default_options[:ssh_user], :keys => @ec2_instance.default_options[:ssh_keys]) do |ssh|
75
+ @ec2_instance.commands.each do |command|
76
+ if command.is_a?(String)
77
+ ssh.exec(command)
78
+ elsif command.is_a?(Hash) and command.include?(:sudo)
79
+ ssh.sudo @ec2_instance.default_options[:sudo_password], command[:sudo]
80
+ end
81
+ end
82
+ ssh.close
83
+ end
84
+ end
85
+
86
+ def ec2
87
+ @ec2 ||= AWS::EC2::Base.new(:access_key_id => @ec2_instance.service_options[:access_key_id],
88
+ :secret_access_key => @ec2_instance.service_options[:secret_access_key],
89
+ :server => @ec2_instance.service_options[:server])
90
+ end
91
+
92
+ def get_instance_state(instance_id)
93
+ result = ec2.describe_instances(:instance_id => instance_id)
94
+ instance_state = result["reservationSet"]["item"].first["instancesSet"]["item"].first["instanceState"]["name"]
95
+ dns_name = result["reservationSet"]["item"].first["instancesSet"]["item"].first["dnsName"]
96
+ return instance_state, dns_name
97
+ end
98
+
99
+ def get_volume_state(volume_id)
100
+ result = ec2.describe_volumes(:volume_id => volume_id)
101
+ volume_state = result["volumeSet"]["item"].first["attachmentSet"]["item"].first["status"]
102
+ return volume_state
103
+ end
104
+
105
+ def launch_ami(ami_id, options = {})
106
+ default_options = @ec2_instance.default_options.merge(:image_id => ami_id).merge(options)
107
+ run_options = default_options.merge(options)
108
+ puts "Launch Options: #{run_options.inspect}"
109
+ ec2.run_instances(run_options)
110
+ end
111
+
112
+ def output_running_state(running_state)
113
+ if running_state == 'running' or running_state == 'attached'
114
+ running_state.green
115
+ elsif running_state == 'terminated' or running_state == 'shutting-down'
116
+ running_state.red
117
+ elsif running_state == 'pending' or running_state == 'attaching'
118
+ running_state.yellow
119
+ else
120
+ running_state
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ class String
127
+ def green
128
+ "\033[32m#{self}\033[0m"
129
+ end
130
+
131
+ def red
132
+ "\033[31m#{self}\033[0m"
133
+ end
134
+
135
+ def yellow
136
+ "\033[33m#{self}\033[0m"
137
+ end
138
+
139
+ def white
140
+ "\033[1m#{self}\033[0m"
141
+ end
142
+ end
143
+
144
+ class Net::SSH::Connection::Session
145
+ def sudo(password, command)
146
+ exec %Q%echo "#{password}" | sudo -S #{command}%
147
+ end
148
+ end
@@ -0,0 +1,34 @@
1
+ module Ec2Starter
2
+ def self.start(ami_id, service_options, run_options, &block)
3
+ instance = Instance.new(ami_id, service_options, run_options)
4
+ instance.instance_eval(&block)
5
+ ec2_starter = Ec2Starter::Execution.new(instance)
6
+ ec2_starter.start
7
+ return instance
8
+ end
9
+
10
+ class Instance
11
+ attr_accessor :service_options, :default_options, :ami_id, :instance_id, :ips, :volumes, :commands
12
+
13
+ def initialize(ami_id, service_options, options)
14
+ @ami_id = ami_id.to_s
15
+ @ips = []
16
+ @volumes = []
17
+ @commands = []
18
+ @default_options = {}.merge(options)
19
+ @service_options = {}.merge(service_options)
20
+ end
21
+
22
+ def ip(ip_address)
23
+ @ips << ip_address
24
+ end
25
+
26
+ def volume(volume_hash)
27
+ @volumes << volume_hash
28
+ end
29
+
30
+ def command(command)
31
+ @commands << command
32
+ end
33
+ end
34
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'ec2-starter'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestEc2Starter < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,199 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ec2-starter
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Oliver Kiessler
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-06-05 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: amazon-ec2
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 25
28
+ segments:
29
+ - 0
30
+ - 9
31
+ - 17
32
+ version: 0.9.17
33
+ type: :runtime
34
+ requirement: *id001
35
+ prerelease: false
36
+ - !ruby/object:Gem::Dependency
37
+ name: net-ssh
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 2
46
+ - 1
47
+ - 4
48
+ version: 2.1.4
49
+ type: :runtime
50
+ requirement: *id002
51
+ prerelease: false
52
+ - !ruby/object:Gem::Dependency
53
+ name: shoulda
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ type: :development
64
+ requirement: *id003
65
+ prerelease: false
66
+ - !ruby/object:Gem::Dependency
67
+ name: bundler
68
+ version_requirements: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ hash: 23
74
+ segments:
75
+ - 1
76
+ - 0
77
+ - 0
78
+ version: 1.0.0
79
+ type: :development
80
+ requirement: *id004
81
+ prerelease: false
82
+ - !ruby/object:Gem::Dependency
83
+ name: jeweler
84
+ version_requirements: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ hash: 7
90
+ segments:
91
+ - 1
92
+ - 5
93
+ - 2
94
+ version: 1.5.2
95
+ type: :development
96
+ requirement: *id005
97
+ prerelease: false
98
+ - !ruby/object:Gem::Dependency
99
+ name: rcov
100
+ version_requirements: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ type: :development
110
+ requirement: *id006
111
+ prerelease: false
112
+ - !ruby/object:Gem::Dependency
113
+ name: amazon-ec2
114
+ version_requirements: &id007 !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ type: :runtime
124
+ requirement: *id007
125
+ prerelease: false
126
+ - !ruby/object:Gem::Dependency
127
+ name: net-ssh
128
+ version_requirements: &id008 !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ hash: 3
134
+ segments:
135
+ - 0
136
+ version: "0"
137
+ type: :development
138
+ requirement: *id008
139
+ prerelease: false
140
+ description: Very simple EC2 instance starter for single server deployments
141
+ email: kiessler@inceedo.com
142
+ executables: []
143
+
144
+ extensions: []
145
+
146
+ extra_rdoc_files:
147
+ - LICENSE.txt
148
+ - README.md
149
+ files:
150
+ - .document
151
+ - Gemfile
152
+ - Gemfile.lock
153
+ - LICENSE.txt
154
+ - README.md
155
+ - Rakefile
156
+ - VERSION
157
+ - example.rb
158
+ - lib/.DS_Store
159
+ - lib/ec2-starter.rb
160
+ - lib/ec2-starter/execution.rb
161
+ - lib/ec2-starter/starter.rb
162
+ - test/helper.rb
163
+ - test/test_ec2-starter.rb
164
+ homepage: http://github.com/okiess/ec2-starter
165
+ licenses:
166
+ - MIT
167
+ post_install_message:
168
+ rdoc_options: []
169
+
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ none: false
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ hash: 3
178
+ segments:
179
+ - 0
180
+ version: "0"
181
+ required_rubygems_version: !ruby/object:Gem::Requirement
182
+ none: false
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ hash: 3
187
+ segments:
188
+ - 0
189
+ version: "0"
190
+ requirements: []
191
+
192
+ rubyforge_project:
193
+ rubygems_version: 1.8.24
194
+ signing_key:
195
+ specification_version: 3
196
+ summary: Very simple EC2 instance starter
197
+ test_files:
198
+ - test/helper.rb
199
+ - test/test_ec2-starter.rb