class AwsXRegionSync::RdsAutomatedSnapshotSync
Public Instance Methods
sync()
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 11 def sync setup = pre_sync_setup sync_snapshot_to_region setup[:source_region], setup[:destination_region], setup[:snapshot] end
sync_required?()
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 16 def sync_required? setup = pre_sync_setup sync = needs_sync? setup[:destination_region], setup[:source_region], setup[:snapshot], discover_aws_account_id sync[:sync_required] end
sync_snapshot_to_region(source_region, destination_region, source_snapshot)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 22 def sync_snapshot_to_region source_region, destination_region, source_snapshot # The way automated snapshot copying seems to work is as long as you're copying snapshot from the same db instance between regions # every snapshot you copy from the source region after the first one is simply just an incremental copy. Because of this we # should copy the latest snapshot # This first thing we should do is look for a sync tag in the destination snapshot (if present) and see we've already synced this # snapshot-id (or if the id is outdated) aws_account_id = discover_aws_account_id sync = needs_sync?(destination_region, source_region, source_snapshot, aws_account_id) if sync[:sync_required] sr = region(source_region) result = destination_region.client.copy_db_snapshot source_db_snapshot_identifier: arn(sr, aws_account_id, source_snapshot.id), target_db_snapshot_identifier: sanitize_snapshot_id(source_snapshot.id) if result[:db_snapshot_identifier] destination_snapshot_id = result[:db_snapshot_identifier] # Move the source snapshot's created timestamp and id to the destination snapshot's sync tag so that we know the last time # the snapshot was synced and what region it was synced from. Also, log the sync against the source too so we have tangible evidence # that it was synced just by looking at it as well. dr = region(destination_region) dest_sync_tag = create_sync_tag sr, source_snapshot.id, timestamp: source_snapshot.created_at, sync_subtype: "From" source_sync_tag = create_sync_tag dr, destination_snapshot_id, timestamp: source_snapshot.created_at destination_region.client.add_tags_to_resource resource_name: arn(dr, aws_account_id, result[:db_snapshot_identifier]), tags: [dest_sync_tag] source_region.client.add_tags_to_resource resource_name: arn(sr, aws_account_id, source_snapshot.id), tags: [source_sync_tag] # We'll now clean up older snapshots if necessary cleanup_old_snapshots sync[:snapshots], max_snapshots, destination_region end end destination_snapshot_id end
validate_config()
click to toggle source
Calls superclass method
AwsXRegionSync::AwsSync#validate_config
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 4 def validate_config raise AwsXRegionSyncConfigError, "The #{self.sync_name} configuration must provide a 'db_instance' option to use to locate automated snapshots." unless config['db_instance'] && config['db_instance'].length > 0 # This call will raise if there's an invalid value..so just call it right now max_snapshots super end
Private Instance Methods
arn(region, account_number, snapshot_id)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 111 def arn region, account_number, snapshot_id # Strip all non-decimal characters from account numbers account_number = account_number.gsub(/\D/, "") "arn:aws:rds:#{region}:#{account_number}:snapshot:#{snapshot_id}" end
cleanup_old_snapshots(destination_snapshots, max_snapshots_to_retain, destination_region)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 178 def cleanup_old_snapshots destination_snapshots, max_snapshots_to_retain, destination_region if destination_snapshots.size > max_snapshots_to_retain # Grab the first max_snapshots # of destination_snapshots (since they're sorted already in ascending order) and just delete them snapshots_to_delete = destination_snapshots.take(destination_snapshots.size - max_snapshots_to_retain) snapshots_to_delete.each do |snapshot| destination_region.client.delete_db_snapshot db_snapshot_identifier: snapshot[:snapshot].id end end end
extract_newest_snapshot(snapshots)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 104 def extract_newest_snapshot snapshots # Grab the snapshot created at time for snapshot as the hash key, then we can sort on the keys and extract the last one from that sorted array snapshot_values = {} snapshots.each {|s| snapshot_values[s.created_at] = s} snapshot_values[snapshot_values.keys.sort[-1]] end
find_sync_tag(tags, source_region_name, db_instance)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 159 def find_sync_tag tags, source_region_name, db_instance sync_key = make_to_snapshot_sync_tag_key source_region_name tags.each do |t| return t if t[:key] == sync_key end nil end
make_rds(config)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 99 def make_rds config # purely for mocking AWS::RDS.new config end
make_to_snapshot_sync_tag_key(source_region)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 155 def make_to_snapshot_sync_tag_key source_region create_sync_tag(source_region, nil, sync_subtype: "From")[:key] end
max_snapshots()
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 189 def max_snapshots retain = nil if config['max_snapshots_to_retain'] retain = Integer(config['max_snapshots_to_retain']) else retain = 2 end retain rescue raise AwsXRegionSyncConfigError, "The #{self.sync_name} configuration must provide a valid 'max_snapshots_to_retain' option. '#{config['max_snapshots_to_retain']}' is not valid." end
needs_sync?(destination_region, source_region, source_snapshot, aws_account_id)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 80 def needs_sync? destination_region, source_region, source_snapshot, aws_account_id destination_snapshots = retrieve_destination_snapshots_for_instance destination_region, region(source_region), source_snapshot.db_instance.id, aws_account_id sync_needed = destination_snapshots.size == 0 || snapshot_needs_copying(destination_snapshots, source_snapshot) {sync_required: sync_needed, snapshots: destination_snapshots} end
pre_sync_setup()
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 60 def pre_sync_setup # There doesn't appear to be a direct way of actually obtaining # a region reference after initializing the rds client - like there is for the s3 client # so we'll just create multiple clients. source_rds = rds_client config['source_region'], config['db_instance'] destination_rds = rds_client config['destination_region'], config['db_instance'] instance = source_rds.db_instances[config['db_instance']] raise AwsXRegionSyncConfigError, "No DB Instance with identifier '#{config['db_instance']}' is available for these credentials in region #{config['db_instance']}." unless instance # Find all the snapshots snapshots = instance.snapshots.with_type('automated').to_a raise AwsXRegionSyncConfigError, "No automated snapshots for db '#{config['db_instance']}' are available for these credentials in region #{config['source_region']}." unless snapshots.size > 0 # Use the created_at attribute of the snapshot to find the newest one newest_snapshot = extract_newest_snapshot snapshots {source_region: source_rds, destination_region: destination_rds, snapshot: newest_snapshot} end
rds_client(region, db_instance)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 87 def rds_client region, db_instance # There doesn't appear to be a direct way of actually obtaining # a region reference after initializing an rds client object (unlike w/ the EC2 API) rds = make_rds aws_config.merge({region: region}) # Just force an API call to validate the region setting. Use the db instance call which we'll use later and, I believe, is cached # so there should be no penalty for calling it here (since we use it pretty much directly after this call anyway) rds.db_instances[db_instance] rds rescue raise AwsXRegionSyncConfigError, "Region '#{region}' is invalid. It either does not exist or the given credentials cannot access it." end
region(client)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 117 def region client client.config.region end
retrieve_destination_snapshots_for_instance(destination_region, source_region_name, db_instance, account_number)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 136 def retrieve_destination_snapshots_for_instance destination_region, source_region_name, db_instance, account_number snapshots = destination_region.db_instances[db_instance].snapshots.with_type('manual').to_a # order them newest to oldest based on their sync tags snapshot_list = [] snapshots.each do |s| tags = tags_for_snapshot(destination_region, account_number, s.id) sync_tag = find_sync_tag tags, source_region_name, db_instance # Ignore any snapshot that doesn't have a sync tag, these are likely actual user initiated manual copies and we don't want to mess with them next unless sync_tag split_sync_value = parse_sync_tag_value(sync_tag[:value]) if sync_tag snapshot_list << {snapshot: s, tags: tags, :sync_timestamp => split_sync_value[:timestamp], :sync_tag=>sync_tag} end snapshot_list.sort_by {|snapshot| snapshot[:sync_timestamp]} end
sanitize_snapshot_id(id)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 169 def sanitize_snapshot_id id # The official "rules" for identifiers are: # Identifiers must begin with a letter; must contain only ASCII letters, digits, and hyphens;" # and must not end with a hyphen or contain two consecutive hyphens # Ids for automated snapshots appear to look like "rds:db_instance-YYYY-mm-dd-HH-MM"..that hyphen is invalid # For now, just translate any : to - id.gsub(":", "-") end
snapshot_needs_copying(destination_snapshots, source_snapshot)
click to toggle source
# File lib/aws_xregion_sync/rds_automated_snapshot_sync.rb, line 121 def snapshot_needs_copying destination_snapshots, source_snapshot # The snapshot array is already sorted, so the last value from the array is the newest one newest_snapshot_hash = destination_snapshots.last source_snapshot.created_at.to_i > newest_snapshot_hash[:sync_timestamp].to_i end