Skip to content

Commit

Permalink
Use ECS credentials when bucket name in env var
Browse files Browse the repository at this point in the history
Attempt to use the ECS credentials configured on the running instances
when the env var with the bucket name exists.

We need to support both ways of obtaining s3 credentials for a while,
until we are confident the new way is properly configured.
  • Loading branch information
CristinaRO committed Oct 12, 2023
1 parent 4a46579 commit 42c8d8e
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 27 deletions.
22 changes: 15 additions & 7 deletions app/services/export/s3_uploader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@ class S3UploadError < StandardError; end
class S3Uploader
def initialize(file:, filename:, use_public_bucket:)
@use_public_bucket = use_public_bucket
@bucket_name_from_env_var = ENV.fetch("EXPORT_DOWNLOAD_S3_BUCKET", false)
@config = S3UploaderConfig.new(use_public_bucket: use_public_bucket)
@client = Aws::S3::Client.new(
region: config.region,
credentials: Aws::Credentials.new(
config.key_id,
config.secret_key
@client = if @bucket_name_from_env_var
Aws::S3::Client.new(
region: "eu-west-2",
credentials: Aws::ECSCredentials.new(retries: 3)
)
)
else
Aws::S3::Client.new(
region: config.region,
credentials: Aws::Credentials.new(
config.key_id,
config.secret_key
)
)
end
@file = file
@filename = timestamped_filename(filename)
end
Expand All @@ -20,7 +28,7 @@ def initialize(file:, filename:, use_public_bucket:)

def upload
response = client.put_object(
bucket: config.bucket,
bucket: @bucket_name_from_env_var || config.bucket,
key: filename,
body: file
)
Expand Down
101 changes: 81 additions & 20 deletions spec/services/export/s3_uploader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
let(:response) { double("response", etag: double) }
let(:file) { Tempfile.open("tempfile") { |f| f << "my export here" } }
let(:aws_credentials) { double("aws credentials") }
let(:ecs_credentials) { double("ecs credentials") }
let(:aws_client) { instance_double(Aws::S3::Client, put_object: response) }
let(:timestamp) { Time.current }
let(:timestamped_filename) { "spending_breakdown-#{timestamp.to_formatted_s(:number)}.csv" }
Expand All @@ -22,6 +23,7 @@
}

let(:use_public_bucket) { false }
let(:bucket_name) { "dsit_exports_bucket" }

subject do
travel_to(timestamp) do
Expand All @@ -31,31 +33,63 @@

before do
allow(Aws::Credentials).to receive(:new).and_return(aws_credentials)
allow(Aws::ECSCredentials).to receive(:new).and_return(ecs_credentials)
allow(Aws::S3::Client).to receive(:new).and_return(aws_client)
allow(Aws::S3::Resource).to receive(:new).and_return(s3_bucket_finder)
allow(Export::S3UploaderConfig).to receive(:new).and_return(s3_uploader_config)
end

describe "#initialize" do
context "when instantiating the Aws::S3::Client" do
it "sets credentials: using an Aws::Credentials object" do
subject
context "when the EXPORT_DOWNLOAD_S3_BUCKET env var is present" do
around(:each) do |example|
ClimateControl.modify(EXPORT_DOWNLOAD_S3_BUCKET: bucket_name) { example.run }
end

expect(Aws::Credentials).to have_received(:new).with(
s3_uploader_config.key_id,
s3_uploader_config.secret_key
)
expect(Aws::S3::Client).to have_received(:new).with(hash_including(
credentials: aws_credentials
))
context "when instantiating the Aws::S3::Client" do
it "sets credentials: using an Aws::ECSCredentials object" do
subject

expect(Aws::ECSCredentials).to have_received(:new).with({retries: 3})
expect(Aws::S3::Client).to have_received(:new).with(hash_including(
credentials: ecs_credentials
))
end

it "sets region: using the hardcoded eu-west-2 region" do
subject

expect(Aws::S3::Client).to have_received(:new).with(hash_including(
region: "eu-west-2"
))
end
end
end

it "sets region: using the region from the S3UploaderConfig" do
subject
context "when the EXPORT_DOWNLOAD_S3_BUCKET env var is not present" do
around(:each) do |example|
ClimateControl.modify(EXPORT_DOWNLOAD_S3_BUCKET: nil) { example.run }
end

context "when instantiating the Aws::S3::Client" do
it "sets credentials: using an Aws::Credentials object" do
subject

expect(Aws::S3::Client).to have_received(:new).with(hash_including(
region: s3_uploader_config.region
))
expect(Aws::Credentials).to have_received(:new).with(
s3_uploader_config.key_id,
s3_uploader_config.secret_key
)
expect(Aws::S3::Client).to have_received(:new).with(hash_including(
credentials: aws_credentials
))
end

it "sets region: using the region from the S3UploaderConfig" do
subject

expect(Aws::S3::Client).to have_received(:new).with(hash_including(
region: s3_uploader_config.region
))
end
end
end
end
Expand All @@ -67,12 +101,39 @@
expect(aws_client).to have_received(:put_object).with(hash_including(body: file))
end

it "uploads to the bucket defined by the S3UploaderConfig" do
subject.upload
context "when the EXPORT_DOWNLOAD_S3_BUCKET env var is present" do
around(:each) do |example|
ClimateControl.modify(EXPORT_DOWNLOAD_S3_BUCKET: bucket_name) { example.run }
end

it "uploads to the bucket defined by the env var" do
subject.upload

expect(aws_client).to have_received(:put_object).with(
hash_including(bucket: bucket_name)
)
end

expect(aws_client).to have_received(:put_object).with(
hash_including(bucket: s3_uploader_config.bucket)
)
it "does not use the S3UploaderConfig" do
subject.upload

expect(s3_uploader_config).to_not have_received(:region)
expect(s3_uploader_config).to_not have_received(:bucket)
expect(s3_uploader_config).to_not have_received(:key_id)
expect(s3_uploader_config).to_not have_received(:secret_key)
end
end

context "when the EXPORT_DOWNLOAD_S3_BUCKET env var is not present" do
it "uploads to the bucket defined by the S3UploaderConfig" do
ClimateControl.modify(EXPORT_DOWNLOAD_S3_BUCKET: nil) do
subject.upload

expect(aws_client).to have_received(:put_object).with(
hash_including(bucket: s3_uploader_config.bucket)
)
end
end
end

it "sets the filename using a timestamp" do
Expand Down

0 comments on commit 42c8d8e

Please sign in to comment.