sproutr 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Peter van Hardenberg
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ #Sprout
2
+ ##EC2 made stupid simple.
3
+
4
+ ##Introduction
5
+
6
+ sproutr is a thor based EC2 instance management library which abstracts the Amazon EC2 API and provides an interactive interface for designing, launching, and managing running instances.
7
+
8
+ sproutr is based around the idea of helping you define an instance, launch it, then create as many copies of that as you need. Currently sproutr supports the following tasks:
9
+ sproutr clone --instance=one two three # Clone N number of running instance
10
+ sproutr create_ami --ami=AMI --desc=DESC --name=NAME # Create an EBS Ami from a running or stopped instance
11
+ sproutr define # define a new instance
12
+ sproutr delete_snapshot --snapshot=one two three # Deletes the given snapshot(s) use --snapshot=
13
+ sproutr describe --ami=one two three # Describe a specific instance
14
+ sproutr destroy --ami=one two three # Alias to terminate
15
+ sproutr help [TASK] # Describe available tasks or one specific task
16
+ sproutr launch --config-file=CONFIG_FILE # launch an instance from the specified config directory
17
+ sproutr list # list all the instances and ami's in your ec2 account
18
+ sproutr list_amis # list all the ami's in your ec2 account
19
+ sproutr list_instances # list all the instances in your ec2 account
20
+ sproutr list_snapshots # Alias to list_snapshots
21
+ sproutr list_snapshots # Lists all the snapshots available and their status
22
+ sproutr restart --ami=one two three # Restart the specified instance(s), requires --ami=
23
+ sproutr snapshot --ami=one two three # Create snapshot
24
+ sproutr start --ami=one two three # Start the specified instance(s), requires --ami=
25
+ sproutr stop --ami=one two three # Stop the specified instance(s), requires --ami=
26
+ sproutr terminate --ami=one two three # Terminate the specified instance, requires --ami=
27
+
28
+ ##Configuration
29
+
30
+ sproutr relies on the Swirl library, which needs to be passed your AWS credentials to do its magic. sproutr therefore requires that you provide a .swirlrc file in your home directory (~/) that contains:
31
+ ~/.swirl:
32
+ ---
33
+ :default:
34
+ :aws_access_key_id: my_access_key
35
+ :aws_secret_access_key: my_secret_key
36
+
37
+ ##Usage
38
+
39
+ You can use sproutr to manage your instances from the commandline. You should create an instance which will serve as your "sproutr" and be converted into an AMI.
40
+ Once you have tested this instance, create a snapshot of the instance, then use it by AMI-Id to launch new instances with their own individual configuration.
41
+
42
+ Here's a simple example from the command line. Begin by invoking the define task.
43
+
44
+ $ bin/sproutr define
45
+
46
+ sproutr's define task will walk you through the process of determining the name, instance size, starting AMI etc.
47
+ Key to the sproutr experience is the way handles two key features: Chef and Volumes:
48
+ sproutr builds the instance with knowledge of, and the ability to execute arbitrary chef cookbooks/recipes.
49
+ While defining an instance you're given the opportunity to specify additional packages, cookbooks and recipes to have installed
50
+ Currently only Debian (ubuntu, mint, etc.) based distributions are supported.
51
+ Additionally, be aware that any volumes you specify will be aggregated together using mdadm and lvm into one logical volume.
52
+
53
+ Once defined, you can launch the instance via
54
+
55
+ $ sproutr launch --definition=filename.json
56
+
57
+ You can monitor the instance's fabrication process via
58
+
59
+ $ sproutr list
60
+
61
+ The instance you created will boot, install your selected packages on top of the stock AMI you selected, then download and cook all the cookbooks and recipes you selected.
62
+
63
+ ##Inspiration and Thanks
64
+
65
+ sproutr is a rewrite and extension of the stem gem, a product (so far as I can tell) a gift of the Heroku development / operations team.
data/bin/sproutr ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.dirname(__FILE__) + "/../lib"
3
+ require 'sproutr'
4
+
5
+
6
+
data/lib/sproutr.rb ADDED
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.dirname(__FILE__)
3
+ require 'rubygems'
4
+ require 'swirl/aws'
5
+ require 'json'
6
+ require 'thor'
7
+ require 'ap'
8
+ require 'terminal-table/import'
9
+ require 'sproutr/utilities'
10
+ require 'sproutr/instance'
11
+ require 'sproutr/cloud'
12
+ require 'sproutr/ami'
13
+ require 'sproutr/definition'
14
+
15
+ class Sproutr < Thor
16
+ include Thor::Actions
17
+ map "-l" => :list
18
+
19
+ def initialize(*args)
20
+ super
21
+ @ec2 ||= Swirl::AWS.new :ec2, load_config
22
+ end
23
+
24
+ desc "clone", "Clone N number of running instance"
25
+ method_option :instance, :type => :array, :required => true
26
+ method_option :ami, :type => :string
27
+ method_option :start, :type => :boolean
28
+ method_option :tags, :type => :hash
29
+
30
+ def clone
31
+ options[:instance].each do |ami_to_clone|
32
+ if options[:ami] then
33
+ ami_id = options[:ami]
34
+ else
35
+ ami_id = @ec2.call("CreateImage", "InstanceId" => ami_to_clone, "Name" => "AMI-#{ami_to_clone}-#{Time.now.to_i}",
36
+ "Description" => "AMI created from #{ami_to_clone} at #{Time.now}", "NoReboot" => "true")["imageId"]
37
+ end
38
+ new_config = clone_ami_config(@ec2.call("DescribeInstances", "InstanceId" => ami_to_clone)["reservationSet"][0]["instancesSet"][0], ami_id)
39
+ until ami_done?(ami_id) do
40
+ say "Ami has not completed so this clone can not yet be started. Sleeping 30 seconds", :red
41
+ sleep 30
42
+ end
43
+ new_instance = invoke_launch(new_config)
44
+ say "Created and started #{new_instance}", :green
45
+ tag_instance(new_instance, options[:tags]) if options[:tags]
46
+ end
47
+ end
48
+
49
+ desc "create_ami", "Create an EBS Ami from a running or stopped instance"
50
+ method_option :ami, :type => :string, :required => true
51
+ method_option :name, :type => :string, :required => true
52
+ method_option :desc, :type => :string, :required => true
53
+
54
+ def create_ami
55
+ @ec2.call "CreateImage", "InstanceId" => options[:ami], "Name" => options[:name], "Description" => options[:desc], "NoReboot" => "true"
56
+ end
57
+
58
+ desc "define", "define a new instance"
59
+
60
+ def define
61
+ definition = Definition.new do |d|
62
+ d.name = demand "What do you want to call this definition (Required): "
63
+ d.size = demand "What size instance do you want (Required): "
64
+ d.ami = demand "What base AMI image would you like to use (Required): "
65
+ ami_info = Cloud.new.describe_image(d.ami)
66
+ break unless yes? "Is this the Image -- #{ami_info["imagesSet"][0]["name"]} -- you wish to build from?", :red
67
+ d.packages = ask "What additional packages do you want installed (Optional): ", :green
68
+ d.gems = ask "What gems do you want to install on this machine by default (Optional): ", :green
69
+ d.chef_cookbooks = ask "Please name the chef cookbooks you wish to automatically download (Optional): ", :green
70
+ d.chef_recipes = ask "Enter the recipes you wish chef to run after cookbooks are installed (Optional): ", :green
71
+ d.user_data = demand "Please copy/paste your Userdata.sh here now. Note, sproutr will automatically add in the
72
+ requisite code to download and install Cheff cookbooks, and aggregate additional volumes
73
+ into a singluar raid array (Required): "
74
+ d.tags = ask "Please enter the tags you'd like in name:value format (Optional, Note that the Name will automatically be specified): ", :green
75
+ d.volumes = ask "Please enter the number of additional volumes (Optional, Note that these additional volumes will be RAID/LVM enabled as 1 *logical* volume): ", :green
76
+ d.volume_size = ask "Please enter the size of each component volume in Gigabytes (Optional, Currently all volumes are identical in size): ", :green
77
+ d.availability_zone = demand "Please enter the availability zone you wish to instantiate this machine in: "
78
+ d.key_name = demand "Which key-pair would you like to use? use the key name: "
79
+ end
80
+ definition.save_to_file(definition.name+"_definition.json")
81
+ end
82
+
83
+ desc "delete_snapshot", "Deletes the given snapshot(s) use --snapshot="
84
+ method_option :snapshot, :type => :array, :required => true
85
+
86
+ def delete_snapshot
87
+ options[:snapshot].each do |snapshot_id|
88
+ result = @ec2.call "DeleteSnapshot", "SnapshotId" => snapshot_id
89
+ say result["return"], :green
90
+ end
91
+ end
92
+
93
+ desc "describe", "Describe a specific instance"
94
+ method_option :ami, :type => :array, :required => true
95
+
96
+ def describe
97
+ options[:ami].each do |ami|
98
+ ap @ec2.call("DescribeInstances", "InstanceId" => ami)["reservationSet"][0]["instancesSet"][0]
99
+ end
100
+ end
101
+
102
+ desc "launch", "launch an instance from the specified config directory"
103
+ method_option :config_file, :type => :string, :required => true
104
+
105
+ def launch
106
+ config = JSON.parse(File.new(options[:config_file]).read) if File.exists? options[:config_file]
107
+ throw "Failed to read config file, or config file does not specify an ImageId" unless config["ami"]
108
+ say invoke_launch(validate_launch_config(config)), :blue
109
+ end
110
+
111
+ desc "list", "list all the instances and ami's in your ec2 account"
112
+
113
+ def list
114
+ invoke :list_instances
115
+ invoke :list_amis
116
+ end
117
+
118
+ desc "list_amis", "list all the ami's in your ec2 account"
119
+
120
+ def list_amis
121
+ @ami_images = Cloud.new.get_images
122
+ ami_table = table do |a|
123
+ a.headings = 'Name', 'AMI Id', 'Type', 'State', 'Size', 'Architecture', 'Public?', 'Description'
124
+ @ami_images.each do |ami|
125
+ a << [ami.name, ami.imageId, ami.rootDeviceType, ami.imageState, ami.blockDeviceMapping[0]["ebs"]["volumeSize"],
126
+ ami.architecture, ami.isPublic, ami.description]
127
+ end
128
+ end
129
+ puts ami_table
130
+ end
131
+
132
+ desc "list_instances", "list all the instances in your ec2 account"
133
+
134
+ def list_instances
135
+ instances = Cloud.new.get_instances
136
+ instance_table = table do |i|
137
+ i.headings = 'Name', 'Instance Id', 'Status', 'ip Address', 'Instance Type', 'AMI Image', 'Availablity Zone', 'DNS Cname'
138
+ instances.each do |instance|
139
+ i << [((instance.tagSet.nil?) ? "Name Not Set" : instance.tagSet[0]["value"]),
140
+ instance.instanceId, instance.instanceState["name"], instance.ipAddress,
141
+ instance.instanceType, instance.imageId, instance.placement["availabilityZone"], instance.dnsName]
142
+ end
143
+ end
144
+ puts instance_table
145
+ end
146
+
147
+ desc "list_snapshots", "Lists all the snapshots available and their status"
148
+
149
+ def list_snapshots
150
+ snapshots = @ec2.call("DescribeSnapshots", "Owner" => "self")["snapshotSet"]
151
+ snapshots_table = table do |s|
152
+ s.headings = snapshots.first.keys
153
+ snapshots.each do |snap|
154
+ s << snap.values
155
+ end
156
+ end
157
+ puts snapshots_table
158
+ end
159
+
160
+ desc "restart", "Restart the specified instance(s), requires --ami="
161
+ method_option :ami, :type => :array, :required => true
162
+
163
+ def restart
164
+ options[:ami].each { |ami| Instance::call_on("RebootInstances", ami) }
165
+ end
166
+
167
+ desc "snapshot", "Create snapshot"
168
+ method_option :ami, :type => :array, :required => true
169
+ method_options :desc => "Snapshot created by sproutr"
170
+
171
+ def snapshot
172
+ options[:ami].each do |ami|
173
+ instance_volumes = @ec2.call("DescribeInstances", "InstanceId" => ami)["reservationSet"][0]["instancesSet"][0]["blockDeviceMapping"]
174
+ instance_volumes.each { |volume| ap @ec2.call("CreateSnapshot", "VolumeId" => volume["ebs"]["volumeId"], "Description" => options[:desc]) }
175
+ end
176
+ end
177
+
178
+
179
+ desc "start", "Start the specified instance(s), requires --ami="
180
+ method_option :ami, :type => :array, :required => true
181
+
182
+ def start
183
+ options[:ami].each { |ami| Instance::call_on("StartInstances", ami) }
184
+ end
185
+
186
+ desc "stop", "Stop the specified instance(s), requires --ami="
187
+ method_option :ami, :type => :array, :required => true
188
+
189
+ def stop
190
+ options[:ami].each { |ami| Instance::call_on("StopInstances", ami) if yes? "Do you really want to stop the #{instance} instance? ", :red }
191
+ end
192
+
193
+
194
+ desc "terminate", "Terminate the specified instance, requires --ami="
195
+ method_option :ami, :type => :array, :required => true
196
+
197
+ def terminate
198
+ options[:ami].each do |ami|
199
+ verify = ask "Do you really want to terminate the #{ami} instance? ", :red
200
+ Instance::call_on("TerminateInstances", ami) if verify.downcase == "y" || verify.downcase == "yes"
201
+ end
202
+ end
203
+
204
+ desc "destroy", "Alias to terminate"
205
+ method_option :ami, :type => :array, :required => true
206
+ alias :destroy :terminate
207
+
208
+
209
+ desc "list_snapshots", "Alias to list_snapshots"
210
+ alias :list_snapshot :list_snapshots
211
+
212
+ end
213
+ Sproutr.start
@@ -0,0 +1,12 @@
1
+ class Ami
2
+ def initialize(ami)
3
+ ami.keys.each do |key|
4
+ var = "@#{key}"
5
+ self.instance_variable_set(var.to_sym, ami[key])
6
+ end
7
+ end
8
+
9
+ def method_missing(sym, *args, &block)
10
+ self.instance_variable_get "@#{sym}".to_sym
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ require 'swirl/aws'
2
+ require 'sproutr/utilities'
3
+
4
+ class Cloud
5
+
6
+ class << self
7
+ attr_accessor :instances, :images
8
+ end
9
+
10
+ def initialize
11
+ @ec2 ||= Swirl::AWS.new :ec2, load_config
12
+ end
13
+
14
+ def get_instances
15
+ aws_instances = @ec2.call "DescribeInstances"
16
+ @instances = Array.new
17
+ aws_instances["reservationSet"].each { |reservation| @instances << Instance.new(reservation["instancesSet"][0]) }
18
+ @instances
19
+ end
20
+
21
+ def get_images
22
+ aws_images = @ec2.call "DescribeImages", "Owner" => "self"
23
+ images = aws_images["imagesSet"].select { |img| img["name"] } rescue nil
24
+ @images = Array.new
25
+ images.each { |image| @images << Ami.new(image) }
26
+ @images
27
+ end
28
+
29
+ def describe_image(ami)
30
+ @ec2.call "DescribeImages", "ImageId" => ami
31
+ end
32
+
33
+ end
@@ -0,0 +1,26 @@
1
+ require 'json'
2
+
3
+ class Definition
4
+ FILE_PREFIX = "~/Sprout_configs/machine_definitions/"
5
+ %x{mkdir -p #{FILE_PREFIX} } unless File.directory? FILE_PREFIX
6
+ attr_accessor :name, :gems, :user_data, :packages, :size, :chef_cookbooks, :chef_recipes, :ami, :tags, :volumes, :volume_size, :availability_zone, :key_name, :chef_install
7
+
8
+ def initialize
9
+ yield self if block_given?
10
+ end
11
+
12
+ def load_from_file(filename)
13
+ definition_file = File.open(FILE_PREFIX + filename, 'r')
14
+ JSON.parse(definition_file.read).each do |element, value|
15
+ instance_variable_set(element, value)
16
+ end
17
+ end
18
+
19
+ def save_to_file(filename)
20
+ hash_of_definition = Hash.new
21
+ instance_variables.each do |var|
22
+ hash_of_definition[var.to_s.gsub("@","")] = instance_variable_get(var)
23
+ end
24
+ File.open(FILE_PREFIX + filename, 'w') {|f| f.write(hash_of_definition.to_json) }
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ class Instance
2
+
3
+ def initialize(instance)
4
+ instance.keys.each do |key|
5
+ var = "@#{key}"
6
+
7
+ self.instance_variable_set(var.to_sym, instance[key])
8
+ end
9
+ end
10
+
11
+ def self.call_on(action, ami)
12
+ @ec2.call action, "InstanceId" => ami
13
+ end
14
+
15
+ def method_missing(sym, *args, &block)
16
+ self.instance_variable_get "@#{sym}".to_sym
17
+ end
18
+ end
@@ -0,0 +1,108 @@
1
+ def load_config
2
+ account = "default"
3
+ swirl_config = "#{ENV["HOME"]}/.swirl"
4
+ account = account.to_sym
5
+
6
+ if File.exists?(swirl_config)
7
+ data = YAML.load_file(swirl_config)
8
+ else
9
+ abort("You are required to write a proper YAML config file called .swirl file in your home directory")
10
+ end
11
+
12
+ if data.key?(account)
13
+ data[account]
14
+ else
15
+ abort("I don't see the account you're looking for")
16
+ end
17
+ end
18
+
19
+ def invoke_launch(config)
20
+ response = @ec2.call "RunInstances", config
21
+ response["instancesSet"].first["instanceId"]
22
+ end
23
+
24
+ def validate_launch_config(config)
25
+ instance_options = {
26
+ "SecurityGroup.#" => config["groups"] || [],
27
+ "MinCount" => "1",
28
+ "MaxCount" => "1",
29
+ "KeyName" => config["key_name"] || "Production",
30
+ "InstanceType" => config["instance_type"] || "m1.small",
31
+ "ImageId" => config["ami"]
32
+ }
33
+
34
+ if config["volumes"]
35
+ devices = []
36
+ sizes = []
37
+ config["volumes"].each do |v|
38
+ puts "Adding a volume of #{v["size"]} to be mounted at #{v["device"]}."
39
+ devices << v["device"]
40
+ sizes << v["size"].to_s
41
+ end
42
+
43
+ instance_options.merge! "BlockDeviceMapping.#.Ebs.VolumeSize" => sizes, "BlockDeviceMapping.#.DeviceName" => devices
44
+ end
45
+
46
+ end
47
+
48
+ def clone_ami_config(config, new_ami)
49
+ throw "No config provided" unless config
50
+
51
+ instance_options = {
52
+ "SecurityGroup.#" => config["groups"] || [],
53
+ "MinCount" => "1",
54
+ "MaxCount" => "1",
55
+ "KeyName" => config["key_name"] || "Production",
56
+ "InstanceType" => config["instance_type"] || "m1.small",
57
+ "ImageId" => new_ami
58
+ }
59
+
60
+ devices = []
61
+ sizes = []
62
+ config["blockDeviceMapping"].each do |block_device|
63
+ volume = @ec2.call "DescribeVolumes", "VolumeId" => block_device["ebs"]["volumeId"]
64
+ next if volume["volumeSet"][0]["attachmentSet"][0]["device"] == "/dev/sda1"
65
+ say "Adding volume #{volume["volumeSet"][0]["attachmentSet"][0]["device"]} with a size of #{volume["volumeSet"][0]["size"]}", :green
66
+ devices << volume["volumeSet"][0]["attachmentSet"][0]["device"]
67
+ sizes << volume["volumeSet"][0]["size"]
68
+ end
69
+
70
+ instance_options.merge! "BlockDeviceMapping.#.Ebs.VolumeSize" => sizes, "BlockDeviceMapping.#.DeviceName" => devices
71
+
72
+ end
73
+
74
+ def ami_done?(ami)
75
+ ami_list = @ec2.call "DescribeImages", "Owner" => "self"
76
+ images = ami_list["imagesSet"].select { |img| img["name"] } rescue nil
77
+ images = images.map { |image| image["imageId"] if image["imageState"] == "available" }
78
+ (images.include? ami) ? true : false
79
+ end
80
+
81
+ def parse_tags(tags)
82
+ if tags && !tags.empty?
83
+ if tags.is_a? Hash
84
+ {"Tag.#.Key" => tags.keys.map(&:to_s),
85
+ "Tag.#.Value" => tags.values.map(&:to_s)}
86
+ elsif tags.is_a? Array
87
+ {
88
+ "Tag.#.Key" => tags.map(&:to_s),
89
+ "Tag.#.Value" => (1..tags.size).map { '' }
90
+ }
91
+ else
92
+ {"Tag.1.Key" => tags.to_s, "Tag.1.Value" => ''}
93
+ end
94
+ end
95
+ end
96
+
97
+ def tag_instance(instance_id, tags)
98
+ instance_id = [instance_id] unless instance_id.is_a? Array
99
+ @ec2.call("CreateTags", parse_tags(tags).merge("ResourceId" => instance_id))
100
+ end
101
+
102
+ def demand(question)
103
+ answer = nil
104
+ while answer.nil? or answer.strip == ""
105
+ answer = ask question, :green
106
+ end
107
+ answer
108
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sproutr
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.2.2
6
+ platform: ruby
7
+ authors:
8
+ - Kevin Poorman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-24 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: swirl
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 1.7.5
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 0.14.6
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: terminal-table
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.4.2
47
+ type: :runtime
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: awesome_print
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: 0.3.2
58
+ type: :runtime
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: json
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ type: :runtime
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ version: 2.5.0
80
+ type: :development
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: rspec-core
84
+ prerelease: false
85
+ requirement: &id007 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: 2.5.0
91
+ type: :development
92
+ version_requirements: *id007
93
+ - !ruby/object:Gem::Dependency
94
+ name: rspec-expectations
95
+ prerelease: false
96
+ requirement: &id008 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 2.5.0
102
+ type: :development
103
+ version_requirements: *id008
104
+ - !ruby/object:Gem::Dependency
105
+ name: rspec-mocks
106
+ prerelease: false
107
+ requirement: &id009 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ~>
111
+ - !ruby/object:Gem::Version
112
+ version: 2.5.0
113
+ type: :development
114
+ version_requirements: *id009
115
+ - !ruby/object:Gem::Dependency
116
+ name: vcr
117
+ prerelease: false
118
+ requirement: &id010 !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ~>
122
+ - !ruby/object:Gem::Version
123
+ version: 1.6.0
124
+ type: :development
125
+ version_requirements: *id010
126
+ - !ruby/object:Gem::Dependency
127
+ name: webmock
128
+ prerelease: false
129
+ requirement: &id011 !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ~>
133
+ - !ruby/object:Gem::Version
134
+ version: 1.6.2
135
+ type: :development
136
+ version_requirements: *id011
137
+ description: Elegant, interactive EC2 Management
138
+ email:
139
+ - kjp@brightleafsoftware.com
140
+ executables:
141
+ - sproutr
142
+ extensions: []
143
+
144
+ extra_rdoc_files: []
145
+
146
+ files:
147
+ - LICENSE
148
+ - README.md
149
+ - lib/sproutr/ami.rb
150
+ - lib/sproutr/cloud.rb
151
+ - lib/sproutr/definition.rb
152
+ - lib/sproutr/instance.rb
153
+ - lib/sproutr/utilities.rb
154
+ - lib/sproutr.rb
155
+ - bin/sproutr
156
+ has_rdoc: true
157
+ homepage: https://github.com/noeticpenguin/sproutr
158
+ licenses: []
159
+
160
+ post_install_message:
161
+ rdoc_options: []
162
+
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: "0"
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ none: false
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: "0"
177
+ requirements: []
178
+
179
+ rubyforge_project:
180
+ rubygems_version: 1.6.2
181
+ signing_key:
182
+ specification_version: 2
183
+ summary: An Ec2 management system designed to help you quickly define a new instance, create N clones of said instance and start/stop them
184
+ test_files: []
185
+