module SnapEbs::Snapshotter
Constants
- AWS_INSTANCE_ID_URL
Attributes
compute[W]
Public Instance Methods
compute()
click to toggle source
Get the Fog compute object. When `–mock` is given, `Fog.mock!` is called and information normally auto-detected from AWS is injected with dummy values to circumvent the lazy loaders.
# File lib/snap_ebs/snapshotter.rb, line 35 def compute require 'fog/aws' logger.debug "Mock: #{options[:mock]}" if options[:mock] Fog.mock! @region = 'us-east-1' @instance_name = 'totally-not-the-cia' end logger.debug "AWS region auto-detected as #{region}" @compute ||= Fog::Compute.new({ :aws_access_key_id => access_key, :aws_secret_access_key => secret_key, :region => region, :provider => "AWS" }) end
take_snapshots()
click to toggle source
Takes snapshots of attached volumes (optionally filtering by volumes mounted to the given directories)
# File lib/snap_ebs/snapshotter.rb, line 10 def take_snapshots snapped_volumes = [] logger.debug "Issuing sync command" system 'sync' logger.debug "Walking attached volumes" attached_volumes.each do |vol| dir = device_to_directory device_name vol logger.debug "Found #{vol.id} mounted on #{dir}" unless should_snap vol logger.debug "Skipping #{vol.id}" next end fs_freeze dir if options[:fs_freeze] take_snapshot vol snapped_volumes.push vol fs_unfreeze dir if options[:fs_freeze] end snapped_volumes end
Private Instance Methods
access_key()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 73 def access_key @access_key ||= if options[:credentials_file] then credentials.first["Access Key Id"] else options[:access_key] end end
attached_volumes()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 68 def attached_volumes logger.debug "Querying for volumes attached to this instance #{instance_id}" @attached_volumes ||= (retry_on_transient_error { compute.volumes.select { |vol| vol.server_id == instance_id } } || []) end
credentials()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 81 def credentials @credentials ||= CSV.parse(File.read(options[:credentials_file]), :headers => true) end
device_name(vol)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 121 def device_name vol vol.device.gsub('/dev/s', '/dev/xv') rescue vol.device end
device_to_directory(device)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 111 def device_to_directory device parts = `cat /etc/mtab | grep #{device}`.split(/\s+/) logger.warn "Could not find directory for #{device}" unless parts.length > 1 parts[1] end
devices_to_snap()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 129 def devices_to_snap @devices_to_snap ||= options.directory.split(',').map { |dir| directory_to_device dir } end
directory_to_device(dir)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 107 def directory_to_device dir `df -T #{dir} | grep dev`.split(/\s/).first.strip end
fs_freeze(dir)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 137 def fs_freeze dir logger.debug "Preparing to freeze #{dir}" return logger.warn "Refusing to freeze #{dir}, which is the root device (#{directory_to_device dir})" if is_root_device? dir system("#{fs_freeze_command} -f #{dir}") end
fs_freeze_command()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 133 def fs_freeze_command @fs_freeze_command ||= system('which fsfreeze > /dev/null') ? 'fsfreeze' : 'xfs_freeze' end
fs_unfreeze(dir)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 143 def fs_unfreeze dir logger.debug "Preparing to unfreeze #{dir}" return logger.warn "Refusing to unfreeze #{dir}, which is the root device (#{directory_to_device dir})" if is_root_device? dir system("#{fs_freeze_command} -u #{dir}") end
instance_id()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 85 def instance_id if options[:mock] @instance_id = 'i-deadbeef' else @instance_id ||= JSON.parse(HTTParty.get(AWS_INSTANCE_ID_URL))["instanceId"] end end
instance_name()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 93 def instance_name @instance_name ||= compute.servers.get(instance_id).tags['Name'] end
is_root_device?(dir)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 117 def is_root_device? dir directory_to_device('/') == directory_to_device(dir) end
region()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 97 def region @region ||= JSON.parse(HTTParty.get(AWS_INSTANCE_ID_URL))["region"] end
retry_on_transient_error() { || ... }
click to toggle source
Retries the given block options.retry_count times while it raises transient AWS API errors. Returns nil if the number of attempts has been exceeded
# File lib/snap_ebs/snapshotter.rb, line 151 def retry_on_transient_error (options.retry_count.to_i + 1).times do |n| logger.debug "Attempt ##{n}" begin result = yield rescue Fog::Compute::AWS::Error => e sleep_seconds = options.retry_interval * (n+1) logger.warn "Received AWS error: #{e}" logger.warn "Sleeping #{sleep_seconds} seconds before retrying" sleep sleep_seconds else return result end end nil end
secret_key()
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 77 def secret_key @secret_key ||= if options[:credentials_file] then credentials.first["Secret Access Key"] else options[:secret_key] end end
should_snap(vol)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 125 def should_snap vol options.directory.nil? or devices_to_snap.include?(device_name vol) end
snapshot_name(vol)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 101 def snapshot_name vol id = instance_name id = instance_id if id.nil? or id.empty? "#{Time.now.strftime "%Y%m%d%H%M%S"}-#{id}-#{vol.device}" end
take_snapshot(vol)
click to toggle source
# File lib/snap_ebs/snapshotter.rb, line 55 def take_snapshot vol logger.debug "Snapping #{vol.id}" snapshot = compute.snapshots.new snapshot.volume_id = vol.id snapshot.description = snapshot_name(vol) if retry_on_transient_error { snapshot.save } logger.debug "Done saving snapshot for #{vol.id}" else logger.warn "Problems saving snapshot, see above" end end