GoEC2 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ lib/installer/cert-6BM4YUMOROLWBDVJSJKTGZWXOQHJFOKG.pem
2
+ lib/installer/default-key-pair.pem
3
+ lib/installer/ec2-api-tools.tar.gz
4
+ lib/installer/pk-6BM4YUMOROLWBDVJSJKTGZWXOQHJFOKG.pem
5
+ lib/installer/use-ec2
6
+ pkg/*
data/GoEC2.gemspec ADDED
@@ -0,0 +1,51 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{GoEC2}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Within3", "Joe Fiorini", "Jonathan Penn"]
12
+ s.date = %q{2009-10-09}
13
+ s.default_executable = %q{goec2}
14
+ s.description = %q{Simple and opinionated helper for creating and managing Rubygem projects on GitHub}
15
+ s.email = %q{jfiorini@within3.com}
16
+ s.executables = ["goec2"]
17
+ s.files = [
18
+ ".gitignore",
19
+ "GoEC2.gemspec",
20
+ "Rakefile",
21
+ "VERSION",
22
+ "bin/goec2",
23
+ "lib/installer/goec2",
24
+ "lib/installer/install-goec2",
25
+ "lib/installer/uninstall_goec2",
26
+ "lib/options.rb",
27
+ "lib/runner.rb",
28
+ "lib/utils.rb"
29
+ ]
30
+ s.homepage = %q{http://github.com/faithfulgeek/goec2}
31
+ s.rdoc_options = ["--charset=UTF-8"]
32
+ s.require_paths = ["lib"]
33
+ s.rubygems_version = %q{1.3.5}
34
+ s.summary = %q{Simple and opinionated helper for creating and managing Rubygem projects on GitHub}
35
+
36
+ if s.respond_to? :specification_version then
37
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
38
+ s.specification_version = 3
39
+
40
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
41
+ s.add_runtime_dependency(%q<sevenwire-forgery>, [">= 0.2.2"])
42
+ s.add_development_dependency(%q<jeweler>, [">= 1.2.1"])
43
+ else
44
+ s.add_dependency(%q<sevenwire-forgery>, [">= 0.2.2"])
45
+ s.add_dependency(%q<jeweler>, [">= 1.2.1"])
46
+ end
47
+ else
48
+ s.add_dependency(%q<sevenwire-forgery>, [">= 0.2.2"])
49
+ s.add_dependency(%q<jeweler>, [">= 1.2.1"])
50
+ end
51
+ end
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "GoEC2"
5
+ gemspec.summary = "Simple and opinionated helper for creating and managing Rubygem projects on GitHub"
6
+ gemspec.description = "Simple and opinionated helper for creating and managing Rubygem projects on GitHub"
7
+ gemspec.email = "jfiorini@within3.com"
8
+ gemspec.homepage = "http://github.com/faithfulgeek/goec2"
9
+ gemspec.authors = ["Within3", "Joe Fiorini", "Jonathan Penn"]
10
+ gemspec.add_dependency('sevenwire-forgery', '>=0.2.2')
11
+ gemspec.add_development_dependency('jeweler', '>=1.2.1')
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
16
+ end
17
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/bin/goec2 ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby -rubygems
2
+ require 'runner'
3
+
4
+ Runner.new.run(ARGV)
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'yaml'
4
+ require 'forgery'
5
+ require 'dictionaries'
6
+ require 'file_reader'
7
+ require 'optparse'
8
+
9
+ IDREGEX = /i-[0-9a-f]{8}/
10
+
11
+ EC2_SSH_KEY_NAME = ENV['EC2_KEYPAIR_NAME'] || 'default'
12
+ EC2_SSH_KEY_PATH = ENV['EC2_KEYPAIR_PATH'] || '~/.ec2/default-key-pair.pem'
13
+
14
+ #AMI_ID = "ami-5647a33f" # Amazon Base Fedora 8
15
+ #AMI_ID = "ami-c8ac48a1" # RightImage CentOS 5 Base
16
+ #AMI_ID = "ami-d510f1bc" # Within3 App Image
17
+ #AMI_ID = "ami-155cba7c" # RightImage CentOS 5.2 Base
18
+ #AMI_ID = "ami-4f1dfc26" # Within3 App Base Image
19
+ #AMI_ID = "ami-af6283c6" # Within3 App Base Image
20
+ AMI_ID = "ami-3f688956" # Within3 App Base Image
21
+
22
+ Instance = Struct.new(:line, :instance_id, :image, :status, :url, :name)
23
+
24
+ def main
25
+ case ARGV[0]
26
+ when /spinup/
27
+ options = {}
28
+ opts = OptionParser.new
29
+ opts.on('-n', '--name NAME') { |name| options[:name] = name }
30
+ opts.on('-s', '--size SIZE') { |size| options[:instance_size] = size }
31
+ opts.on('-f', '--user-data-file PATH') { |path| options[:user_data_file] = path }
32
+ opts.on('-a', '--ami-id AMI_ID') { |ami_id| options[:ami_id] = ami_id }
33
+ opts.on('-z', '--zone ZONE') { |zone| options[:zone] = zone }
34
+ opts.parse!(ARGV)
35
+ options[:name] ||= get_name_for_instance
36
+ options[:ami_id] ||= AMI_ID
37
+ options[:instance_size] ||= 'm1.large'
38
+ options[:zone] ||= 'us-east-1c'
39
+ puts "Spining up image with options: #{options.inspect}"
40
+ spinup(options)
41
+ when /spindown/
42
+ raise "Need an instance name" unless ARGV[1]
43
+ spindown ARGV[1]
44
+ when /status/
45
+ puts "Getting the status"
46
+ instances = if ARGV[1] then [get_instance(ARGV[1])].compact else get_instances end
47
+ instances.each do |instance|
48
+ puts "%s\t%s\t%s\t%s" % [instance.name, instance.instance_id, instance.status, instance.url]
49
+ end
50
+ when /ssh/
51
+ raise "Need an instance name" unless ARGV[1]
52
+ instance = get_instance(ARGV[1])
53
+ raise "Unknown instance name #{ARGV[1]}" unless instance
54
+ ssh instance.url
55
+ when /scp_up/
56
+ raise "Need an istance name" unless ARGV[1]
57
+ raise "Need a source path" unless ARGV[2]
58
+ raise "Need a destination path" unless ARGV[3]
59
+ instance = get_instance(ARGV[1])
60
+ scp_up instance, ARGV[2], ARGV[3]
61
+ when /webopen/
62
+ raise "Need an instance name" unless ARGV[1]
63
+ instance = get_instance(ARGV[1])
64
+ raise "Unknown instance name #{ARGV[1]}" unless instance
65
+ `open http://#{instance.url}`
66
+ when /output/
67
+ raise "Need an instance name" unless ARGV[1]
68
+ console_output get_instance(ARGV[1])
69
+ when /address/
70
+ raise "Need an instance name" unless ARGV[1]
71
+ instance = get_instance(ARGV[1])
72
+ puts instance.url
73
+ else
74
+ puts "Fail."
75
+ end
76
+ end
77
+
78
+
79
+ def run_instance(options={})
80
+ instance_size = options.delete(:instance_size)
81
+ image_id = options.delete(:ami_id)
82
+ name = options.delete(:name)
83
+ zone = options.delete(:zone)
84
+ user_data_file = options.delete(:user_data_file)
85
+ instance_options = "-t #{instance_size}"
86
+ instance_options += " -f #{user_data_file}" if user_data_file
87
+ instance_options += " -z #{zone}" if zone
88
+ instance = parse_aws_status_line_into_instance `ec2-run-instances #{image_id} -k #{EC2_SSH_KEY_NAME} #{instance_options}`.split("\n")[-1], name
89
+ write_instance_to_datastore(instance)
90
+ instance
91
+ end
92
+
93
+ def get_name_for_instance
94
+ Dictionaries.new[:company_names].random.downcase
95
+ end
96
+
97
+ def parse_aws_status_line_into_instance line, name=nil
98
+ columns = line.split("\t")
99
+ instance = Instance.new line, columns[1], columns[2], columns[5], columns[3], name
100
+ end
101
+
102
+ def get_instance(name)
103
+ instances = load_instances_from_datastore
104
+ instance_id = instances[name]
105
+ `ec2-describe-instances #{instance_id}`.split("\n").select{ |l| l =~ /^INSTANCE/ }.inject([]) do |result, line|
106
+ instance = parse_aws_status_line_into_instance(line, name)
107
+
108
+ if instance.status != 'terminated'
109
+ instance.name = name
110
+ result << instance
111
+ else
112
+ result
113
+ end
114
+ end.compact.first
115
+ end
116
+
117
+ def get_instances
118
+ instance_mappings = load_instances_from_datastore
119
+ `ec2-describe-instances`.split("\n").select{|l| l =~ /^INSTANCE/}.inject([]) do |result, line|
120
+ instance = parse_aws_status_line_into_instance(line)
121
+
122
+ if instance.status != "terminated"
123
+ instance.name = instance_mappings.find_name_by_instance_id(instance.instance_id)
124
+ result << instance
125
+ else
126
+ result
127
+ end
128
+ end
129
+ end
130
+
131
+ def terminate_instances *instances
132
+ `ec2-terminate-instances #{instances.map{|i| i.instance_id}.join(' ')}`
133
+ end
134
+
135
+ def ssh url
136
+ puts url
137
+ exec "ssh -i #{EC2_SSH_KEY_PATH} root@#{url}"
138
+ end
139
+
140
+ def scp_up instance, source, destination
141
+ exec "scp -i #{EC2_SSH_KEY_PATH} #{source} root@#{instance.url}:#{destination}"
142
+ end
143
+
144
+ def console_output instance
145
+ exec "ec2-get-console-output #{instance.instance_id}"
146
+ end
147
+
148
+ def spinup(options={})
149
+ puts "Spinning up image"
150
+ name = options[:name]
151
+ current_instance = instance = run_instance(options)
152
+ puts "Instance #{instance.instance_id} spinning up"
153
+
154
+ still_loading = true
155
+ while still_loading
156
+ puts "waiting...#{current_instance.line}"
157
+ sleep 2
158
+ current_instance = get_instance(name)
159
+ still_loading = current_instance.status == "pending"
160
+ end
161
+
162
+ puts "Instance running!"
163
+ puts "name: #{current_instance.name}, id: #{current_instance.instance_id}, url: #{current_instance.url}"
164
+ end
165
+
166
+ INSTANCE_MAPPINGS_FILENAME = File.expand_path("~/.ec2/instance_mappings.yml")
167
+ def write_instance_to_datastore(instance)
168
+ instances = load_instances_from_datastore || {}
169
+ instances.merge!({instance.name => instance.instance_id})
170
+ write_instances_to_datastore(instances)
171
+ end
172
+
173
+ def write_instances_to_datastore(instances)
174
+ File.open(INSTANCE_MAPPINGS_FILENAME, "w+") do |f|
175
+ f << instances.to_yaml
176
+ end
177
+ end
178
+
179
+ def load_instances_from_datastore
180
+ data = File.read(INSTANCE_MAPPINGS_FILENAME)
181
+ instances = YAML.load(data)
182
+
183
+ class << instances
184
+ def find_name_by_instance_id(instance_id)
185
+ select { |k,v| v == instance_id }[0]
186
+ end
187
+ end
188
+
189
+ instances
190
+ end
191
+
192
+ def delete_instance_from_datastore(name)
193
+ instances = load_instances_from_datastore
194
+ instances.delete(name)
195
+ write_instances_to_datastore(instances)
196
+ end
197
+
198
+ def spindown name
199
+ puts "Spinning down #{name}"
200
+ instance = get_instance(name)
201
+ raise "Unknown instance name #{name}" unless instance
202
+
203
+ terminate_instances instance
204
+
205
+ while instance
206
+ puts "waiting...#{instance.line}"
207
+ sleep 2
208
+ instance = get_instance(name)
209
+ end
210
+
211
+ delete_instance_from_datastore(name)
212
+
213
+ puts "Terminated #{name}"
214
+ end
215
+
216
+ main
@@ -0,0 +1,70 @@
1
+ #!/bin/bash
2
+
3
+ # Must be run with root permissions
4
+
5
+ set -e
6
+
7
+ export EC2_HOME=/usr/local/ec2
8
+ export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Home"
9
+
10
+ ec2_dir=".ec2"
11
+
12
+ if [ ! -e /usr/local/ec2 ]; then
13
+ sudo mkdir -p $EC2_HOME
14
+ sudo tar -xf ec2-api-tools.tar.gz -C $EC2_HOME
15
+ fi
16
+
17
+ while getopts "v:" flag
18
+ do
19
+ case $flag in
20
+ v)
21
+ conf_dir=$OPTARG ;;
22
+ esac
23
+ done
24
+
25
+ if [ -z $conf_dir ]; then
26
+ mkdir ~/.ec2
27
+ else
28
+
29
+ case $conf_dir in
30
+ */) ;;
31
+ *) conf_dir=$conf_dir/
32
+ esac
33
+
34
+ if [ ! -e $conf_dir$ec2_dir ]; then
35
+ mkdir $conf_dir$ec2_dir
36
+ fi
37
+
38
+ ln -s $conf_dir$ec2_dir ~/
39
+ fi
40
+
41
+ sudo gem install sevenwire-forgery
42
+
43
+ cp pk-* cert-* default-key-pair.pem ~/$ec2_dir
44
+
45
+ sudo cp goec2 /usr/local/bin
46
+
47
+ touch ~/$ec2_dir/instance_mappings.yml
48
+
49
+ export EC2_PRIVATE_KEY=$(ls ~/$ec2_dir/pk-*)
50
+ export EC2_CERT=$(ls ~/$ec2_dir/cert-*)
51
+
52
+ echo "Please enter the name you'd like to use for your EC2 key pair:"
53
+ read keypair_name
54
+
55
+ $EC2_HOME/bin/ec2-add-keypair $keypair_name | grep -v KEYPAIR > ~/$ec2_dir/$keypair_name
56
+ chmod 400 ~/$ec2_dir/$keypair_name
57
+ chmod 400 ~/$ec2_dir/default-key-pair.pem
58
+
59
+ echo "
60
+ EC2_HOME=$EC2_HOME
61
+ EC2_PRIVATE_KEY=$(ls ~/$ec2_dir/pk-*)
62
+ EC2_CERT=$(ls ~/$ec2_dir/cert-*)
63
+ PATH=\"$PATH:$EC2_HOME/bin\"
64
+ JAVA_HOME=$JAVA_HOME
65
+ EC2_KEYPAIR_PATH=~/$ec2_dir/$keypair_name
66
+ EC2_KEYPAIR_NAME=$keypair_name
67
+ export EC2_HOME EC2_PRIVATE_KEY EC2_CERT PATH JAVA_HOME EC2_KEYPAIR_NAME EC2_KEYPAIR_PATH
68
+ " >> ~/$ec2_dir/use-ec2
69
+
70
+ echo "source ~/$ec2_dir/use-ec2" >> ~/.bash_profile
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ ec2_dir=".ec2"
4
+
5
+ echo "Remove keypair? (yes/no)"
6
+ read should_remove_keypair
7
+
8
+ if [ $should_remove_keypair = "yes" ]; then
9
+ echo "What is the name of the keypair to remove?"
10
+ read keypair_name
11
+ source use-ec2
12
+ $EC2_HOME/bin/ec2-delete-keypair $keypair_name
13
+ fi
14
+
15
+ sudo rm /usr/local/bin/goec2
16
+ rm -rf ~/$ec2_dir
17
+
data/lib/options.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'optparse'
2
+
3
+ module Options
4
+
5
+ def opts
6
+ @opts ||= OptionParser.new
7
+ end
8
+
9
+ def parse_spinup_options(args, defaults={})
10
+ opts.on('-n', '--name NAME', "The name to use for the instance (note: this is local to this machine. It does not affect Amazon EC2 AT ALL") { |name| defaults[:name] = name }
11
+ opts.on('-s', '--size SIZE', "The size of the instance per EC2 documentation") { |size| defaults[:instance_size] = size }
12
+ opts.on('-f', '--user-data-file PATH', "Path to a user data file to pass into the instance") { |path| defaults[:user_data_file] = path }
13
+ opts.on('-a', '--ami-id AMI_ID', "The AMI ID of the image with which to boot this machine") { |ami_id| defaults[:ami_id] = ami_id }
14
+ opts.on('-z', '--zone ZONE', "The zone in which to boot this machine per EC2 documentation") { |zone| defaults[:zone] = zone }
15
+ opts.banner = "Usage: goec2 spinup [options]"
16
+ opts.parse!(args)
17
+ defaults
18
+ end
19
+
20
+ def parse_ssh_options(args, defaults={})
21
+ opts.on("-u", "--user [NAME]", "The user to pass to ssh") { |name| defaults[:user] = name }
22
+ opts.banner = "Usage: goec2 ssh INSTANCE_NAME [options]"
23
+ opts.parse!(args)
24
+ defaults
25
+ end
26
+
27
+ def parse_attach_volume_options(args, defaults={})
28
+ opts.on("-v", "--volume-id VOLUME_ID") { |volume_id| defaults[:volume_id] = volume_id }
29
+ opts.on("-d", "--device [DEVICE]") { |device| defaults[:device] = device }
30
+ opts.banner = "Usage: goec2 attach_volume INSTANCE_NAME [options]"
31
+ opts.parse!(args)
32
+ defaults
33
+ end
34
+ end
data/lib/runner.rb ADDED
@@ -0,0 +1,83 @@
1
+ require 'optparse'
2
+ require 'utils'
3
+ require 'options'
4
+
5
+ class Runner
6
+ include Utils
7
+ include Options
8
+
9
+ def run(args)
10
+ case args[0]
11
+ when /spinup/
12
+ options = parse_spinup_options(args,
13
+ :name => get_name_for_instance,
14
+ :ami_id => AMI_ID,
15
+ :instance_size => 'm1.large',
16
+ :zone => 'us-east-1c')
17
+ puts "Spining up image with options: #{options.inspect}"
18
+ spinup(options)
19
+ when /spindown/
20
+ raise "Need an instance name" unless args[1]
21
+ spindown args[1]
22
+ when /status/
23
+ puts "Getting the status"
24
+ instances = if args[1] then [get_instance(args[1])].compact else get_instances end
25
+ instances.each do |instance|
26
+ puts "%s\t%s\t%s\t%s" % [instance.name, instance.instance_id, instance.status, instance.url]
27
+ end
28
+ when /ssh/
29
+ instance_name = args.delete_at(1)
30
+ raise "Need an instance name" unless instance_name
31
+ instance = get_instance(instance_name)
32
+ raise "Unknown instance name #{instance_name}" unless instance
33
+ options = parse_ssh_options(args, :user => 'w3dev')
34
+ ssh instance.url, options
35
+ when /scp_up/
36
+ raise "Need an istance name" unless args[1]
37
+ raise "Need a source path" unless args[2]
38
+ raise "Need a destination path" unless args[3]
39
+ instance = get_instance(args[1])
40
+ scp_up instance, args[2], args[3]
41
+ when /webopen/
42
+ raise "Need an instance name" unless args[1]
43
+ instance = get_instance(args[1])
44
+ raise "Unknown instance name #{args[1]}" unless instance
45
+ `open http://#{instance.url}`
46
+ when /output/
47
+ raise "Need an instance name" unless args[1]
48
+ console_output get_instance(args[1])
49
+ when /address/
50
+ raise "Need an instance name" unless args[1]
51
+ instance = get_instance(args[1])
52
+ puts instance.url
53
+ when /attach_volume/
54
+ raise "Need an instance name" unless args[1]
55
+ instance_name = args.delete_at(1)
56
+ options = parse_attach_volume_options(args, :device => '/dev/sdf')
57
+ instance = get_instance(instance_name)
58
+ `ec2-attach-volume #{options[:volume_id]} -i #{instance.instance_id} -d #{options[:device]}`
59
+ else
60
+ puts banner
61
+ end
62
+ end
63
+
64
+ def banner
65
+ <<-EOS
66
+ Script enabling easier interaction with Amazon EC2 instances.
67
+
68
+ Usage: goec2 COMMAND [INSTANCE_NAME] [ARGS]
69
+
70
+ Commands:
71
+
72
+ spinup Tells EC2 service to launch a new instance. By default generates a random name to associate with that instance through goec2
73
+ spindown Terminates the specified instance
74
+ status Retrieves the status of all running EC2 instances
75
+ ssh SSH into an EC2 instance
76
+ scp_up Upload a file to an EC2 instance (goec2 scp_up INSTANCE_NAME SOURCE DEST)
77
+ webopen Open the EC2 instance in a web browser (Mac OSX only)
78
+ output Get console output for a given EC2 instance
79
+ address Get the public address for a given EC2 instance
80
+ attach_volume Attach an EBS volume to the given EC2 instance
81
+ EOS
82
+ end
83
+ end
data/lib/utils.rb ADDED
@@ -0,0 +1,152 @@
1
+ require 'forgery'
2
+ require 'dictionaries'
3
+ require 'yaml'
4
+ require 'file_reader'
5
+
6
+ EC2_SSH_KEY_NAME = ENV['EC2_KEYPAIR_NAME'] || 'default'
7
+ EC2_SSH_KEY_PATH = ENV['EC2_KEYPAIR_PATH'] || '~/.ec2/default-key-pair.pem'
8
+ AMI_ID = "ami-fceb0895" # Within3 App Base Image
9
+
10
+ Instance = Struct.new(:line, :instance_id, :image, :status, :url, :name)
11
+
12
+ module Utils
13
+ def run_instance(options={})
14
+ instance_size = options.delete(:instance_size)
15
+ image_id = options.delete(:ami_id)
16
+ name = options.delete(:name)
17
+ zone = options.delete(:zone)
18
+ user_data_file = options.delete(:user_data_file)
19
+ instance_options = "-t #{instance_size}"
20
+ instance_options += " -f #{user_data_file}" if user_data_file
21
+ instance_options += " -z #{zone}" if zone
22
+ instance = parse_aws_status_line_into_instance `ec2-run-instances #{image_id} -k #{EC2_SSH_KEY_NAME} #{instance_options}`.split("\n")[-1], name
23
+ write_instance_to_datastore(instance)
24
+ instance
25
+ end
26
+
27
+ def get_name_for_instance
28
+ Dictionaries.new[:company_names].random.downcase
29
+ end
30
+
31
+ def parse_aws_status_line_into_instance line, name=nil
32
+ columns = line.split("\t")
33
+ instance = Instance.new line, columns[1], columns[2], columns[5], columns[3], name
34
+ end
35
+
36
+ def get_instance(name)
37
+ instance_id = if name =~ /^i-\w{8}$/
38
+ name
39
+ else
40
+ load_instances_from_datastore[name]
41
+ end
42
+ `ec2-describe-instances #{instance_id}`.split("\n").select{ |l| l =~ /^INSTANCE/ }.inject([]) do |result, line|
43
+ instance = parse_aws_status_line_into_instance(line, name)
44
+
45
+ if instance.status != 'terminated'
46
+ instance.name = name
47
+ result << instance
48
+ else
49
+ result
50
+ end
51
+ end.compact.first
52
+ end
53
+
54
+ def get_instances
55
+ instance_mappings = load_instances_from_datastore
56
+ `ec2-describe-instances`.split("\n").select{|l| l =~ /^INSTANCE/}.inject([]) do |result, line|
57
+ instance = parse_aws_status_line_into_instance(line)
58
+
59
+ if instance.status != "terminated"
60
+ instance.name = instance_mappings.find_name_by_instance_id(instance.instance_id)
61
+ result << instance
62
+ else
63
+ result
64
+ end
65
+ end
66
+ end
67
+
68
+ def terminate_instances *instances
69
+ `ec2-terminate-instances #{instances.map{|i| i.instance_id}.join(' ')}`
70
+ end
71
+
72
+ def ssh(url, options={})
73
+ puts url
74
+ exec "ssh -i #{EC2_SSH_KEY_PATH} #{options[:user]}@#{url}"
75
+ end
76
+
77
+ def scp_up instance, source, destination
78
+ exec "scp -i #{EC2_SSH_KEY_PATH} #{source} root@#{instance.url}:#{destination}"
79
+ end
80
+
81
+ def console_output instance
82
+ exec "ec2-get-console-output #{instance.instance_id}"
83
+ end
84
+
85
+ def spinup(options={})
86
+ puts "Spinning up image"
87
+ name = options[:name]
88
+ current_instance = instance = run_instance(options)
89
+ puts "Instance #{instance.instance_id} spinning up"
90
+
91
+ still_loading = true
92
+ while still_loading
93
+ puts "waiting...#{current_instance.line}"
94
+ sleep 2
95
+ current_instance = get_instance(name)
96
+ still_loading = current_instance.status == "pending"
97
+ end
98
+
99
+ puts "Instance running!"
100
+ puts "name: #{current_instance.name}, id: #{current_instance.instance_id}, url: #{current_instance.url}"
101
+ end
102
+
103
+ INSTANCE_MAPPINGS_FILENAME = File.expand_path("~/.ec2/instance_mappings.yml")
104
+ def write_instance_to_datastore(instance)
105
+ instances = load_instances_from_datastore || {}
106
+ instances.merge!({instance.name => instance.instance_id})
107
+ write_instances_to_datastore(instances)
108
+ end
109
+
110
+ def write_instances_to_datastore(instances)
111
+ File.open(INSTANCE_MAPPINGS_FILENAME, "w+") do |f|
112
+ f << instances.to_yaml
113
+ end
114
+ end
115
+
116
+ def load_instances_from_datastore
117
+ data = File.read(INSTANCE_MAPPINGS_FILENAME)
118
+ instances = YAML.load(data)
119
+
120
+ class << instances
121
+ def find_name_by_instance_id(instance_id)
122
+ select { |k,v| v == instance_id }[0]
123
+ end
124
+ end
125
+
126
+ instances
127
+ end
128
+
129
+ def delete_instance_from_datastore(name)
130
+ instances = load_instances_from_datastore
131
+ instances.delete(name)
132
+ write_instances_to_datastore(instances)
133
+ end
134
+
135
+ def spindown name
136
+ puts "Spinning down #{name}"
137
+ instance = get_instance(name)
138
+ raise "Unknown instance name #{name}" unless instance
139
+
140
+ terminate_instances instance
141
+
142
+ while instance
143
+ puts "waiting...#{instance.line}"
144
+ sleep 2
145
+ instance = get_instance(name)
146
+ end
147
+
148
+ delete_instance_from_datastore(name)
149
+
150
+ puts "Terminated #{name}"
151
+ end
152
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: GoEC2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Within3
8
+ - Joe Fiorini
9
+ - Jonathan Penn
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-10-09 00:00:00 -04:00
15
+ default_executable: goec2
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: sevenwire-forgery
19
+ type: :runtime
20
+ version_requirement:
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 0.2.2
26
+ version:
27
+ - !ruby/object:Gem::Dependency
28
+ name: jeweler
29
+ type: :development
30
+ version_requirement:
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 1.2.1
36
+ version:
37
+ description: Simple and opinionated helper for creating and managing Rubygem projects on GitHub
38
+ email: jfiorini@within3.com
39
+ executables:
40
+ - goec2
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - .gitignore
47
+ - GoEC2.gemspec
48
+ - Rakefile
49
+ - VERSION
50
+ - bin/goec2
51
+ - lib/installer/goec2
52
+ - lib/installer/install-goec2
53
+ - lib/installer/uninstall_goec2
54
+ - lib/options.rb
55
+ - lib/runner.rb
56
+ - lib/utils.rb
57
+ has_rdoc: true
58
+ homepage: http://github.com/faithfulgeek/goec2
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --charset=UTF-8
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ version:
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.3.5
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Simple and opinionated helper for creating and managing Rubygem projects on GitHub
85
+ test_files: []
86
+