Skip to content

Commit e8b521f

Browse files
authored
Merge pull request #5023 from rubyforgood/move-to-s3
Move from Azure to AWS S3 for blob storage. Merge for staging testing
2 parents cf3e528 + b207112 commit e8b521f

File tree

7 files changed

+72
-34
lines changed

7 files changed

+72
-34
lines changed

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ gem "rails", "7.2.2"
2020

2121
# These two gems are used to hook into ActiveStorage to store blobs in Azure Storage Service.
2222
# gem 'azure-storage', '~> 0.15.0.preview', require: false
23+
# For ActiveStorage on AWS
24+
gem 'aws-sdk-s3', require: false
2325
gem 'azure-storage-blob'
2426
# Adds soft delete functionality for models.
2527
gem 'discard', '~> 1.3'

Gemfile.lock

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,23 @@ GEM
8383
autoprefixer-rails (10.4.13.0)
8484
execjs (~> 2)
8585
awesome_print (1.9.2)
86+
aws-eventstream (1.3.1)
87+
aws-partitions (1.1050.0)
88+
aws-sdk-core (3.218.1)
89+
aws-eventstream (~> 1, >= 1.3.0)
90+
aws-partitions (~> 1, >= 1.992.0)
91+
aws-sigv4 (~> 1.9)
92+
base64
93+
jmespath (~> 1, >= 1.6.1)
94+
aws-sdk-kms (1.98.0)
95+
aws-sdk-core (~> 3, >= 3.216.0)
96+
aws-sigv4 (~> 1.5)
97+
aws-sdk-s3 (1.181.0)
98+
aws-sdk-core (~> 3, >= 3.216.0)
99+
aws-sdk-kms (~> 1)
100+
aws-sigv4 (~> 1.5)
101+
aws-sigv4 (1.11.0)
102+
aws-eventstream (~> 1, >= 1.0.2)
86103
azure-storage-blob (2.0.3)
87104
azure-storage-common (~> 2.0)
88105
nokogiri (~> 1, >= 1.10.8)
@@ -312,6 +329,7 @@ GEM
312329
jbuilder (2.13.0)
313330
actionview (>= 5.0.0)
314331
activesupport (>= 5.0.0)
332+
jmespath (1.6.2)
315333
json (2.9.1)
316334
jwt (2.9.1)
317335
base64
@@ -721,6 +739,7 @@ PLATFORMS
721739
DEPENDENCIES
722740
annotate
723741
awesome_print
742+
aws-sdk-s3
724743
azure-storage-blob
725744
better_errors
726745
binding_of_caller

config/environments/staging.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@
9494
}
9595
end
9696

97-
# Store files locally.
98-
config.active_storage.service = :azure
97+
# Store files on Amazon S3.
98+
config.active_storage.service = :amazon
9999

100100
# Use a different logger for distributed setups.
101101
# require 'syslog/logger'

config/storage.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@ azure:
1212
storage_account_name: <%= ENV['AZURE_STORAGE_ACCOUNT_NAME'] %>
1313
storage_access_key: <%= ENV['AZURE_STORAGE_ACCESS_KEY'] %>
1414
container: <%= ENV['AZURE_STORAGE_CONTAINER'] %>
15+
16+
amazon:
17+
service: S3
18+
bucket: human-essentials-<%= Rails.env %>
19+
region: "us-east-2"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class MoveAzureBlobsToS3 < ActiveRecord::Migration[7.2]
2+
# https://stackoverflow.com/questions/71699789/activestorage-transfer-all-assets-from-one-bucket-to-another-bucket
3+
def up
4+
return unless Rails.env.staging?
5+
6+
source_service = ActiveStorage::Blob.services.fetch(:azure)
7+
destination_service = ActiveStorage::Blob.services.fetch(:amazon)
8+
9+
ActiveStorage::Blob.where(service_name: source_service.name).find_each do |blob|
10+
key = blob.key
11+
12+
raise "I can't find blob #{blob.id} (#{key})" unless source_service.exist?(key)
13+
14+
unless destination_service.exist?(key)
15+
source_service.open(blob.key, checksum: blob.checksum) do |file|
16+
destination_service.upload(blob.key, file, checksum: blob.checksum)
17+
end
18+
end
19+
blob.update_columns(service_name: destination_service.name)
20+
end
21+
22+
end
23+
24+
def down
25+
raise IrreversibleMigration
26+
end
27+
end

lib/tasks/backup_db_rds.rake

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'aws-sdk-s3'
2+
13
desc "Update the development db to what is being used in prod"
24
task :backup_db_rds => :environment do
35
logger = Logger.new(STDOUT)
@@ -6,18 +8,12 @@ task :backup_db_rds => :environment do
68
current_time = Time.current.strftime("%Y%m%d%H%M%S")
79

810
logger.info("Copying the database...")
9-
backup_filename = "#{current_time}.rds.dump"
11+
backup_filename = "#{Rails.env}-#{current_time}.rds.dump"
1012
system("PGPASSWORD='#{ENV["DIAPER_DB_PASSWORD"]}' pg_dump -Fc -v --host=#{ENV["DIAPER_DB_HOST"]} --username=#{ENV["DIAPER_DB_USERNAME"]} --dbname=#{ENV["DIAPER_DB_DATABASE"]} -f #{backup_filename}")
1113

12-
account_name = ENV["AZURE_STORAGE_ACCOUNT_NAME"]
13-
account_key = ENV["AZURE_STORAGE_ACCESS_KEY"]
14-
15-
blob_client = Azure::Storage::Blob::BlobService.create(
16-
storage_account_name: account_name,
17-
storage_access_key: account_key
18-
)
14+
client = Aws::S3::Client.new(region: 'us-east-2')
1915

2016
logger.info("Uploading #{backup_filename}")
21-
blob_client.create_block_blob("backups", backup_filename, File.read(backup_filename))
17+
client.put_object(bucket: "human-essentials-backups", key: "backups/#{backup_filename}", body: File.read(backup_filename))
2218
File.delete(backup_filename)
2319
end

lib/tasks/fetch_latest_db.rake

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
require 'aws-sdk-s3'
2+
13
desc "Update the development db to what is being used in prod"
2-
BACKUP_CONTAINER_NAME = 'backups'
4+
BUCKET_NAME = "human-essentials-backups"
35
PASSWORD_REPLACEMENT = 'password'
46

57
task :fetch_latest_db do
@@ -13,7 +15,7 @@ task :fetch_latest_db do
1315
system("bin/rails db:environment:set RAILS_ENV=development")
1416
system("bin/rails db:drop db:create")
1517

16-
puts "Restoring the database with #{backup.name}"
18+
puts "Restoring the database with #{backup.key}"
1719
backup_filepath = fetch_file_path(backup)
1820
db_username = ENV["PG_USERNAME"].presence || ENV["USER"].presence || "postgres"
1921
db_host = ENV["PG_HOST"].presence || "localhost"
@@ -51,48 +53,35 @@ end
5153
private
5254

5355
def fetch_latest_backups
54-
backups = blob_client.list_blobs(BACKUP_CONTAINER_NAME)
56+
backups = blob_client.list_objects_v2(bucket: BUCKET_NAME)
5557

5658
#
5759
# Retrieve the most up to date version of the DB dump
5860
#
59-
backup = backups.select { |b| b.name.match?(".rds.dump") }.sort do |a,b|
60-
Time.parse(a.properties[:last_modified]) <=> Time.parse(b.properties[:last_modified])
61+
backup = backups.contents.select { |b| b.key.match?(".rds.dump") }.sort do |a,b|
62+
Time.parse(a.last_modified) <=> Time.parse(b.last_modified)
6163
end.reverse.first
6264

6365
#
6466
# Download each of the backups onto the local disk in tmp
6567
#
6668
filepath = fetch_file_path(backup)
67-
puts "\nDownloading blob #{backup.name} to #{filepath}"
68-
blob, content = blob_client.get_blob(BACKUP_CONTAINER_NAME, backup.name)
69-
File.open(filepath, "wb") { |f| f.write(content) }
69+
puts "\nDownloading blob #{backup.key} to #{filepath}"
70+
blob_client.get_object(bucket: BUCKET_NAME, key: backup.key, response_target: filepath)
7071

7172
#
7273
# At this point, the dumps should be stored on the local
7374
# machine of the user under tmp.
7475
#
75-
return backup
76+
backup
7677
end
7778

7879
def blob_client
79-
return @blob_client if @blob_client
80-
81-
account_name = ENV["AZURE_STORAGE_ACCOUNT_NAME"]
82-
account_key = ENV["AZURE_STORAGE_ACCESS_KEY"]
83-
84-
if account_name.blank? || account_key.blank?
85-
raise "You must have the correct azure credentials in your ENV"
86-
end
87-
88-
@blob_client = Azure::Storage::Blob::BlobService.create(
89-
storage_account_name: account_name,
90-
storage_access_key: account_key
91-
)
80+
Aws::S3::Client.new(region: 'us-east-2')
9281
end
9382

9483
def fetch_file_path(backup)
95-
File.join(Rails.root, 'tmp', backup.name)
84+
File.join(Rails.root, 'tmp', File.basename(backup.key))
9685
end
9786

9887
def replace_user_passwords

0 commit comments

Comments
 (0)