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 +42 -0
- data/aws_helper.gemspec +34 -0
- data/bin/aws_helper +5 -0
- data/lib/awshelper.rb +2 -0
- data/lib/awshelper/cli.rb +302 -0
- data/lib/awshelper/ec2.rb +141 -0
- data/lib/awshelper/elb.rb +12 -0
- data/lib/awshelper/version.rb +3 -0
- metadata +87 -0
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
|
+
|
data/aws_helper.gemspec
ADDED
@@ -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
data/lib/awshelper.rb
ADDED
@@ -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
|
+
|
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: []
|