Skip to content

Commit 86ac00f

Browse files
committed
Add support for s3-compatible storage
1 parent 28e8d84 commit 86ac00f

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

src/server/cloud/aws.rs

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use aws_sdk_s3::{
1313
use std::future::Future;
1414
use tokio::runtime::Runtime;
1515

16-
/// A [`Service`] implementation based on the Google Cloud Storage service.
16+
/// A [`Service`] implementation based on the AWS Simple Storage Service.
1717
pub(in crate::server) struct AwsService {
1818
client: s3::Client,
1919
rt: Runtime,
@@ -63,9 +63,11 @@ pub enum AwsCredentials {
6363

6464
impl AwsService {
6565
pub(in crate::server) fn new(
66-
region: String,
66+
region: Option<String>,
6767
bucket: String,
6868
creds: AwsCredentials,
69+
endpoint_url: Option<String>,
70+
force_path_style: bool,
6971
) -> Result<Self> {
7072
let rt = Runtime::new()?;
7173

@@ -92,13 +94,37 @@ impl AwsService {
9294
// Just use the default.
9395
}
9496
}
95-
config_provider
96-
.region(RegionProviderChain::first_try(Region::new(region)))
97-
.load()
98-
.await
97+
// This will:
98+
// 1. If a region is set, use it
99+
// 2. if No region is set, follow the AWS default provider chain
100+
// (https://docs.aws.amazon.com/sdk-for-rust/latest/dg/region.html)
101+
// 3. If no region is discovered, hardcode to "us-east-1"
102+
//
103+
// If there's a region specified we will always prefer that
104+
// next, the default provider chain will look at things like AWS_REGION environment
105+
// variables, the profile file, etc.
106+
//
107+
// we provide the hardcoded fallback because a region MUST be set
108+
// but, a region being set does _not_ make sense if endpoint_url is set, because
109+
// the endpoint URL would include a region.
110+
// realistically, endpoint_url is more useful for S3-compatible services
111+
// and would not use a separate region in addition to endpoint_url.
112+
config_provider = config_provider.region(
113+
RegionProviderChain::first_try(region.map(Region::new))
114+
.or_default_provider()
115+
.or_else(Region::new("us-east-1")),
116+
);
117+
match endpoint_url {
118+
Some(url) => config_provider = config_provider.endpoint_url(url),
119+
None => {}
120+
}
121+
config_provider.load().await
99122
});
100123

101-
let client = s3::client::Client::new(&config);
124+
let s3_config = aws_sdk_s3::config::Builder::from(&config)
125+
.force_path_style(force_path_style)
126+
.build();
127+
let client = aws_sdk_s3::Client::from_conf(s3_config);
102128
Ok(Self { client, rt, bucket })
103129
}
104130

@@ -405,12 +431,14 @@ mod tests {
405431

406432
Some(
407433
AwsService::new(
408-
region,
434+
Some(region),
409435
bucket,
410436
AwsCredentials::AccessKey {
411437
access_key_id,
412438
secret_access_key,
413439
},
440+
None,
441+
false,
414442
)
415443
.unwrap(),
416444
)

src/server/config.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub enum ServerConfig {
7979
#[cfg(feature = "server-aws")]
8080
Aws {
8181
/// Region in which the bucket is located.
82-
region: String,
82+
region: Option<String>,
8383
/// Bucket in which to store the task data.
8484
///
8585
/// This bucket must not be used for any other purpose. No special bucket configuration is
@@ -90,6 +90,12 @@ pub enum ServerConfig {
9090
/// Private encryption secret used to encrypt all data sent to the server. This can
9191
/// be any suitably un-guessable string of bytes.
9292
encryption_secret: Vec<u8>,
93+
// endpoint_url is an optional URL to specify the hostname of an s3-compatible service.
94+
// When endpoint_url is used, region is ignored by the underlying S3 client.
95+
endpoint_url: Option<String>,
96+
// force_path_style is used to force the S3 client to use path-style URLs instead of
97+
// virtual-hosted-style (subdomain) URLs for the bucket.
98+
force_path_style: bool,
9399
},
94100
}
95101

@@ -120,8 +126,10 @@ impl ServerConfig {
120126
bucket,
121127
credentials,
122128
encryption_secret,
129+
endpoint_url,
130+
force_path_style,
123131
} => Box::new(CloudServer::new(
124-
AwsService::new(region, bucket, credentials)?,
132+
AwsService::new(region, bucket, credentials, endpoint_url, force_path_style)?,
125133
encryption_secret,
126134
)?),
127135
})

0 commit comments

Comments
 (0)