aws_helper 0.0.1

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/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # aws_helper
2
+
3
+ Aws Helper for an instance
4
+
5
+ Allows functions on EBS volumes, snapshots, IP addresses and more
6
+ * initially snapshots are supported
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'aws_helper'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install aws_helper
21
+
22
+ ## Usage
23
+
24
+ Snapshot EBS attached to device /dev/sdf
25
+
26
+ export AWS_ACCESS_KEY_ID ='xxxxxxxxxxxx'
27
+ export AWS_SECRET_ACCESS_KEY ='yyyyyyyy'
28
+ export HTTP_PROXY=http://myproxy:port
29
+ aws_helper snap /dev/sdf --description zzzzzzzzz
30
+
31
+ Prune so only keep 7 snapshots:
32
+
33
+ export AWS_ACCESS_KEY_ID ='xxxxxxxxxxxx'
34
+ export AWS_SECRET_ACCESS_KEY ='yyyyyyyy'
35
+ aws_helper snap_prune /dev/sdf --snapshots_to_keep=7
36
+
37
+ NOTE: Best Practice is for your server to have an IAM role then you don't
38
+ need to specify AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
39
+
40
+ Other functions to follow
41
+
42
+
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'awshelper/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'aws_helper'
9
+ s.version = Awshelper::VERSION
10
+ s.authors = ['Neill Turner']
11
+ s.email = ['neillwturner@gmail.com']
12
+ s.homepage = 'https://github.com/neillturner/aws_helper'
13
+ s.summary = 'Aws Helper for an instance'
14
+ candidates = Dir.glob('{lib}/**/*') + ['README.md', 'aws_helper.gemspec']
15
+ candidates = candidates + Dir.glob("bin/*")
16
+ s.files = candidates.sort
17
+ s.platform = Gem::Platform::RUBY
18
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+ s.add_dependency('right_aws')
21
+ s.add_dependency('thor')
22
+ s.rubyforge_project = '[none]'
23
+ s.description = <<-EOF
24
+ == DESCRIPTION:
25
+
26
+ Aws Helper for an instance
27
+
28
+ == FEATURES:
29
+
30
+ Allows functions on EBS volumes, snapshots, IP addresses and more
31
+
32
+ EOF
33
+
34
+ end
data/bin/aws_helper ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "awshelper/cli"
4
+
5
+ Awshelper::CLI.start(ARGV)
data/lib/awshelper.rb ADDED
@@ -0,0 +1,2 @@
1
+ module Awshelper
2
+ end
@@ -0,0 +1,302 @@
1
+ require 'thor'
2
+ require 'awshelper'
3
+ require 'awshelper/ec2'
4
+ require 'syslog'
5
+
6
+ module Awshelper
7
+ class CLI < Thor
8
+ include Thor::Actions
9
+
10
+ include Awshelper::Ec2
11
+
12
+ #def ebs_create(volume_id, snapshot_id, most_recent_snapshot)
13
+ # #TO DO
14
+ # raise "Cannot create a volume with a specific id (EC2 chooses volume ids)" if volume_id
15
+ # if snapshot_id =~ /vol/
16
+ # new_resource.snapshot_id(find_snapshot_id(new_resource.snapshot_id, new_resource.most_recent_snapshot))
17
+ # end
18
+ #
19
+ # #nvid = volume_id_in_node_data
20
+ # #if nvid
21
+ # # # volume id is registered in the node data, so check that the volume in fact exists in EC2
22
+ # # vol = volume_by_id(nvid)
23
+ # # exists = vol && vol[:aws_status] != "deleting"
24
+ # # # TODO: determine whether this should be an error or just cause a new volume to be created. Currently erring on the side of failing loudly
25
+ # # raise "Volume with id #{nvid} is registered with the node but does not exist in EC2. To clear this error, remove the ['aws']['ebs_volume']['#{new_resource.name}']['volume_id'] entry from this node's data." unless exists
26
+ # #else
27
+ # # Determine if there is a volume that meets the resource's specifications and is attached to the current
28
+ # # instance in case a previous [:create, :attach] run created and attached a volume but for some reason was
29
+ # # not registered in the node data (e.g. an exception is thrown after the attach_volume request was accepted
30
+ # # by EC2, causing the node data to not be stored on the server)
31
+ # if new_resource.device && (attached_volume = currently_attached_volume(instance_id, new_resource.device))
32
+ # Chef::Log.debug("There is already a volume attached at device #{new_resource.device}")
33
+ # compatible = volume_compatible_with_resource_definition?(attached_volume)
34
+ # raise "Volume #{attached_volume[:aws_id]} attached at #{attached_volume[:aws_device]} but does not conform to this resource's specifications" unless compatible
35
+ # Chef::Log.debug("The volume matches the resource's definition, so the volume is assumed to be already created")
36
+ # converge_by("update the node data with volume id: #{attached_volume[:aws_id]}") do
37
+ # node.set['aws']['ebs_volume'][new_resource.name]['volume_id'] = attached_volume[:aws_id]
38
+ # node.save unless Chef::Config[:solo]
39
+ # end
40
+ # else
41
+ # # If not, create volume and register its id in the node data
42
+ # converge_by("create a volume with id=#{new_resource.snapshot_id} size=#{new_resource.size} availability_zone=#{new_resource.availability_zone} and update the node data with created volume's id") do
43
+ # nvid = create_volume(new_resource.snapshot_id,
44
+ # new_resource.size,
45
+ # new_resource.availability_zone,
46
+ # new_resource.timeout,
47
+ # new_resource.volume_type,
48
+ # new_resource.piops)
49
+ # node.set['aws']['ebs_volume'][new_resource.name]['volume_id'] = nvid
50
+ # node.save unless Chef::Config[:solo]
51
+ # end
52
+ # end
53
+ # #end
54
+ #end
55
+
56
+ #def ebs_attach(device, volume_id, timeout)
57
+ # # determine_volume returns a Hash, not a Mash, and the keys are
58
+ # # symbols, not strings.
59
+ # vol = determine_volume(device, volume_id)
60
+ # if vol[:aws_status] == "in-use"
61
+ # if vol[:aws_instance_id] != instance_id
62
+ # raise "Volume with id #{vol[:aws_id]} exists but is attached to instance #{vol[:aws_instance_id]}"
63
+ # else
64
+ # Chef::Log.debug("Volume is already attached")
65
+ # end
66
+ # else
67
+ # # attach the volume
68
+ # attach_volume(vol[:aws_id], instance_id, device, timeout)
69
+ # end
70
+ #end
71
+
72
+ #def ebs_detach(device, volume_id, timeout)
73
+ # vol = determine_volume(device, volume_id)
74
+ # detach_volume(vol[:aws_id], timeout)
75
+ #end
76
+
77
+ desc "snap DEVICE [VOLUME_ID]", "Take a snapshot of a EBS Disk."
78
+ option :description
79
+
80
+ long_desc <<-LONGDESC
81
+ 'snap DEVICE [VOLUME_ID] --description xxxxxx'
82
+ \x5 Take a snapshot of a EBS Disk by specifying device and/or volume_id.
83
+ \x5 All commands rely on environment variables
84
+ \x5 export AWS_ACCESS_KEY_ID ='xxxxxxxxxx'
85
+ \x5 export AWS_SECRET_ACCESS_KEY ='yyyyyy'
86
+ \x5 For example
87
+ \x5 aws_helper snap /dev/sdf
88
+ \x5 will snap shot the EBS disk attach to device /dev/xvdj
89
+ LONGDESC
90
+
91
+ def snap(device, volume_id=nil)
92
+ vol = determine_volume(device, volume_id)
93
+ snap_description = options[:description] if options[:description]
94
+ snap_description = "Created by aws_helper(#{instance_id}/#{local_ipv4}) for #{ami_id} from #{vol[:aws_id]}" if !options[:description]
95
+ snapshot = ec2.create_snapshot(vol[:aws_id],snap_description)
96
+ log("Created snapshot of #{vol[:aws_id]} as #{snapshot[:aws_id]}")
97
+ end
98
+
99
+ desc "snap_prune DEVICE [VOLUME_ID]", "Prune the number of snapshots."
100
+ option :snapshots_to_keep, :type => :numeric, :required => true
101
+
102
+ long_desc <<-LONGDESC
103
+ 'snap_prune DEVICE [VOLUME_ID] --snapshots_to_keep=<numeric>'
104
+ \x5 Prune the number of snapshots of a EBS Disk by specifying device and/or volume_id and the no to keep.
105
+ \x5 All commands rely on environment variables
106
+ \x5 export AWS_ACCESS_KEY_ID ='xxxxxxxxxxxx'
107
+ \x5 export AWS_SECRET_ACCESS_KEY ='yyyyyyyy'
108
+ \x5 For example
109
+ \x5 aws_helper snap_prune /dev/sdf --snapshots_to_keep=7
110
+ \x5 will keep the last 7 snapshots of the EBS disk attach to device /dev/xvdj
111
+ LONGDESC
112
+
113
+ def snap_prune(device, volume_id=nil)
114
+ snapshots_to_keep = options[:snapshots_to_keep]
115
+ vol = determine_volume(device, volume_id)
116
+ old_snapshots = Array.new
117
+ log("Checking for old snapshots")
118
+ ec2.describe_snapshots.sort { |a,b| b[:aws_started_at] <=> a[:aws_started_at] }.each do |snapshot|
119
+ if snapshot[:aws_volume_id] == vol[:aws_id]
120
+ log("Found old snapshot #{snapshot[:aws_id]} (#{snapshot[:aws_volume_id]}) #{snapshot[:aws_started_at]}")
121
+ old_snapshots << snapshot
122
+ end
123
+ end
124
+ if old_snapshots.length > snapshots_to_keep
125
+ old_snapshots[snapshots_to_keep, old_snapshots.length].each do |die|
126
+ log("Deleting old snapshot #{die[:aws_id]}")
127
+ ec2.delete_snapshot(die[:aws_id])
128
+ end
129
+ end
130
+ end
131
+
132
+ private
133
+
134
+ def log(message,type="info")
135
+ # $0 is the current script name
136
+ puts message
137
+ Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.info message } if type == "info"
138
+ Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.info message } if type == "err"
139
+ end
140
+
141
+ # Pulls the volume id from the volume_id attribute or the node data and verifies that the volume actually exists
142
+ def determine_volume(device, volume_id)
143
+ vol = currently_attached_volume(instance_id, device)
144
+ vol_id = volume_id || ( vol ? vol[:aws_id] : nil )
145
+ log("volume_id attribute not set and no volume is attached at the device #{device}",'err') unless vol_id
146
+ raise "volume_id attribute not set and no volume is attached at the device #{device}" unless vol_id
147
+
148
+ # check that volume exists
149
+ vol = volume_by_id(vol_id)
150
+ log("No volume with id #{vol_id} exists",'err') unless vol
151
+ raise "No volume with id #{vol_id} exists" unless vol
152
+
153
+ vol
154
+ end
155
+
156
+ # Retrieves information for a volume
157
+ def volume_by_id(volume_id)
158
+ ec2.describe_volumes.find{|v| v[:aws_id] == volume_id}
159
+ end
160
+
161
+ # Returns the volume that's attached to the instance at the given device or nil if none matches
162
+ def currently_attached_volume(instance_id, device)
163
+ ec2.describe_volumes.find{|v| v[:aws_instance_id] == instance_id && v[:aws_device] == device}
164
+ end
165
+
166
+ # Returns true if the given volume meets the resource's attributes
167
+ #def volume_compatible_with_resource_definition?(volume)
168
+ # if new_resource.snapshot_id =~ /vol/
169
+ # new_resource.snapshot_id(find_snapshot_id(new_resource.snapshot_id, new_resource.most_recent_snapshot))
170
+ # end
171
+ # (new_resource.size.nil? || new_resource.size == volume[:aws_size]) &&
172
+ # (new_resource.availability_zone.nil? || new_resource.availability_zone == volume[:zone]) &&
173
+ # (new_resource.snapshot_id.nil? || new_resource.snapshot_id == volume[:snapshot_id])
174
+ #end
175
+
176
+ # TODO: support tags in deswcription
177
+ #def tag_value(instance,tag_key)
178
+ # options = ec2.describe_tags({:filters => {:resource_id => instance }} )
179
+ # end
180
+
181
+ # Creates a volume according to specifications and blocks until done (or times out)
182
+ def create_volume(snapshot_id, size, availability_zone, timeout, volume_type, piops)
183
+ availability_zone ||= instance_availability_zone
184
+
185
+ # Sanity checks so we don't shoot ourselves.
186
+ raise "Invalid volume type: #{volume_type}" unless ['standard', 'io1', 'gp2'].include?(volume_type)
187
+
188
+ # PIOPs requested. Must specify an iops param and probably won't be "low".
189
+ if volume_type == 'io1'
190
+ raise 'IOPS value not specified.' unless piops >= 100
191
+ end
192
+
193
+ # Shouldn't see non-zero piops param without appropriate type.
194
+ if piops > 0
195
+ raise 'IOPS param without piops volume type.' unless volume_type == 'io1'
196
+ end
197
+
198
+ create_volume_opts = { :volume_type => volume_type }
199
+ # TODO: this may have to be casted to a string. rightaws vs aws doc discrepancy.
200
+ create_volume_opts[:iops] = piops if volume_type == 'io1'
201
+
202
+ nv = ec2.create_volume(snapshot_id, size, availability_zone, create_volume_opts)
203
+ Chef::Log.debug("Created new volume #{nv[:aws_id]}#{snapshot_id ? " based on #{snapshot_id}" : ""}")
204
+
205
+ # block until created
206
+ begin
207
+ Timeout::timeout(timeout) do
208
+ while true
209
+ vol = volume_by_id(nv[:aws_id])
210
+ if vol && vol[:aws_status] != "deleting"
211
+ if ["in-use", "available"].include?(vol[:aws_status])
212
+ Chef::Log.info("Volume #{nv[:aws_id]} is available")
213
+ break
214
+ else
215
+ Chef::Log.debug("Volume is #{vol[:aws_status]}")
216
+ end
217
+ sleep 3
218
+ else
219
+ raise "Volume #{nv[:aws_id]} no longer exists"
220
+ end
221
+ end
222
+ end
223
+ rescue Timeout::Error
224
+ raise "Timed out waiting for volume creation after #{timeout} seconds"
225
+ end
226
+
227
+ nv[:aws_id]
228
+ end
229
+
230
+ # Attaches the volume and blocks until done (or times out)
231
+ def attach_volume(volume_id, instance_id, device, timeout)
232
+ Chef::Log.debug("Attaching #{volume_id} as #{device}")
233
+ ec2.attach_volume(volume_id, instance_id, device)
234
+
235
+ # block until attached
236
+ begin
237
+ Timeout::timeout(timeout) do
238
+ while true
239
+ vol = volume_by_id(volume_id)
240
+ if vol && vol[:aws_status] != "deleting"
241
+ if vol[:aws_attachment_status] == "attached"
242
+ if vol[:aws_instance_id] == instance_id
243
+ Chef::Log.info("Volume #{volume_id} is attached to #{instance_id}")
244
+ break
245
+ else
246
+ raise "Volume is attached to instance #{vol[:aws_instance_id]} instead of #{instance_id}"
247
+ end
248
+ else
249
+ Chef::Log.debug("Volume is #{vol[:aws_status]}")
250
+ end
251
+ sleep 3
252
+ else
253
+ raise "Volume #{volume_id} no longer exists"
254
+ end
255
+ end
256
+ end
257
+ rescue Timeout::Error
258
+ raise "Timed out waiting for volume attachment after #{timeout} seconds"
259
+ end
260
+ end
261
+
262
+ # Detaches the volume and blocks until done (or times out)
263
+ def detach_volume(volume_id, timeout)
264
+ vol = volume_by_id(volume_id)
265
+ if vol[:aws_instance_id] != instance_id
266
+ Chef::Log.debug("EBS Volume #{volume_id} is not attached to this instance (attached to #{vol[:aws_instance_id]}). Skipping...")
267
+ return
268
+ end
269
+ Chef::Log.debug("Detaching #{volume_id}")
270
+ orig_instance_id = vol[:aws_instance_id]
271
+ ec2.detach_volume(volume_id)
272
+
273
+ # block until detached
274
+ begin
275
+ Timeout::timeout(timeout) do
276
+ while true
277
+ vol = volume_by_id(volume_id)
278
+ if vol && vol[:aws_status] != "deleting"
279
+ if vol[:aws_instance_id] != orig_instance_id
280
+ Chef::Log.info("Volume detached from #{orig_instance_id}")
281
+ break
282
+ else
283
+ Chef::Log.debug("Volume: #{vol.inspect}")
284
+ end
285
+ else
286
+ Chef::Log.debug("Volume #{volume_id} no longer exists")
287
+ break
288
+ end
289
+ sleep 3
290
+ end
291
+ end
292
+ rescue Timeout::Error
293
+ raise "Timed out waiting for volume detachment after #{timeout} seconds"
294
+ end
295
+ end
296
+
297
+
298
+ end
299
+
300
+ end
301
+
302
+
@@ -0,0 +1,141 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2009 Opscode, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'open-uri'
19
+ require 'syslog'
20
+ require 'right_aws'
21
+
22
+
23
+ module Awshelper
24
+ module Ec2
25
+ def find_snapshot_id(volume_id="", find_most_recent=false)
26
+ snapshot_id = nil
27
+ snapshots = if find_most_recent
28
+ ec2.describe_snapshots.sort { |a,b| a[:aws_started_at] <=> b[:aws_started_at] }
29
+ else
30
+ ec2.describe_snapshots.sort { |a,b| b[:aws_started_at] <=> a[:aws_started_at] }
31
+ end
32
+ snapshots.each do |snapshot|
33
+ if snapshot[:aws_volume_id] == volume_id
34
+ snapshot_id = snapshot[:aws_id]
35
+ end
36
+ end
37
+ log("Cannot find snapshot id!",'err') unless snapshot_id
38
+ raise "Cannot find snapshot id!" unless snapshot_id
39
+ log("Snapshot ID is #{snapshot_id}")
40
+ snapshot_id
41
+ end
42
+
43
+ def ec2
44
+ @@ec2 ||= create_aws_interface
45
+ #(RightAws::Ec2)
46
+ end
47
+
48
+ def instance_id
49
+ @@instance_id ||= query_instance_id
50
+ end
51
+
52
+ def ami_id
53
+ @@ami_id ||= query_ami_id
54
+ end
55
+
56
+ def local_ipv4
57
+ @@local_ipv4 ||= query_local_ipv4
58
+ end
59
+
60
+ def instance_availability_zone
61
+ @@instance_availability_zone ||= query_instance_availability_zone
62
+ end
63
+
64
+ private
65
+
66
+ def create_aws_interface
67
+
68
+ region = instance_availability_zone
69
+ region = region[0, region.length-1]
70
+
71
+ aws_access_key = ENV['AWS_ACCESS_KEY_ID']
72
+ aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
73
+
74
+ if aws_access_key and aws_secret_access_key
75
+ RightAws::Ec2.new(aws_access_key,aws_secret_access_key, {:region => region}) # :logger => Chef::Log,
76
+ else
77
+ log("No env var AWS_ACCESS_KEY_ID and 'AWS_SECRET_ACCESS_KEY so trying role credentials")
78
+ creds = query_role_credentials
79
+ RightAws::Ec2.new(creds['AccessKeyId'], creds['SecretAccessKey'], { :region => region, :token => creds['Token']})
80
+ end
81
+ end
82
+
83
+ def query_role
84
+ r = open("http://169.254.169.254/latest/meta-data/iam/security-credentials/",options = {:proxy => proxy}).readlines.first
85
+ r
86
+ end
87
+
88
+ def query_role_credentials(role = query_role)
89
+ log("Instance has no IAM role.",'err') if role.to_s.empty?
90
+ fail "Instance has no IAM role." if role.to_s.empty?
91
+ creds = open("http://169.254.169.254/latest/meta-data/iam/security-credentials/#{role}",options = {:proxy => proxy}){|f| JSON.parse(f.string)}
92
+ log("Retrieved instance credentials for IAM role #{role}")
93
+ creds
94
+ end
95
+
96
+ def query_instance_id
97
+ instance_id = open('http://169.254.169.254/latest/meta-data/instance-id',options = {:proxy => proxy}){|f| f.gets}
98
+ log("Cannot find instance id!",'err') unless instance_id
99
+ raise "Cannot find instance id!" unless instance_id
100
+ log("Instance ID is #{instance_id}")
101
+ instance_id
102
+ end
103
+
104
+ def query_ami_id
105
+ ami_id = open('http://169.254.169.254/latest/meta-data/ami-id',options = {:proxy => proxy}){|f| f.gets}
106
+ log("Cannot find ami id!",'err') unless ami_id
107
+ raise "Cannot find instance id!" unless ami_id
108
+ log("Aim ID is #{ami_id}")
109
+ ami_id
110
+ end
111
+
112
+ def query_local_ipv4
113
+ local_ipv4 = open('http://169.254.169.254/latest/meta-data/local-ipv4',options = {:proxy => proxy}){|f| f.gets}
114
+ log("Cannot find local_ipv4!",'err') unless local_ipv4
115
+ raise "Cannot find local_ipv4!" unless local_ipv4
116
+ log("local_ipv4 is #{local_ipv4}")
117
+ local_ipv4
118
+ end
119
+
120
+ def query_instance_availability_zone
121
+ availability_zone = open('http://169.254.169.254/latest/meta-data/placement/availability-zone/', options = {:proxy => proxy}){|f| f.gets}
122
+ log("Cannot find availability zone!",'err') unless availability_zone
123
+ raise "Cannot find availability zone!" unless availability_zone
124
+ log("Instance's availability zone is #{availability_zone}")
125
+ availability_zone
126
+ end
127
+
128
+ def log(message,type="info")
129
+ # $0 is the current script name
130
+ puts message
131
+ Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.info message } if type == "info"
132
+ Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.info message } if type == "err"
133
+ end
134
+
135
+ def proxy
136
+ p = ENV['HTTP_PROXY'] if ENV['HTTP_PROXY']
137
+ p
138
+ end
139
+ end
140
+ end
141
+
@@ -0,0 +1,12 @@
1
+ require File.join(File.dirname(__FILE__), 'ec2')
2
+
3
+ module AwsHelper
4
+ module Elb
5
+ include AwsHelper::Ec2
6
+
7
+ def elb
8
+ @@elb ||= create_aws_interface(RightAws::ElbInterface)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Awshelper
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aws_helper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Neill Turner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-11-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: right_aws
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: thor
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: ! "== DESCRIPTION:\n\nAws Helper for an instance \n\n== FEATURES:\n\nAllows
47
+ functions on EBS volumes, snapshots, IP addresses and more \n\n"
48
+ email:
49
+ - neillwturner@gmail.com
50
+ executables:
51
+ - aws_helper
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - README.md
56
+ - aws_helper.gemspec
57
+ - bin/aws_helper
58
+ - lib/awshelper.rb
59
+ - lib/awshelper/cli.rb
60
+ - lib/awshelper/ec2.rb
61
+ - lib/awshelper/elb.rb
62
+ - lib/awshelper/version.rb
63
+ homepage: https://github.com/neillturner/aws_helper
64
+ licenses: []
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project: ! '[none]'
83
+ rubygems_version: 1.8.24
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Aws Helper for an instance
87
+ test_files: []