Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

Commit 424b691

Browse files
authored
bottomless: prefix AWS env vars in use with LIBSQL_BOTTOMLESS_ (#649)
* bottomless: prefix AWS env vars in use with LIBSQL_BOTTOMLESS_ * changed env vars in workflow defs * post rebase fixes
1 parent df92c46 commit 424b691

File tree

5 files changed

+69
-23
lines changed

5 files changed

+69
-23
lines changed

.github/workflows/rust.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ jobs:
9191
command: test
9292
args: --verbose
9393
env:
94-
AWS_ACCESS_KEY_ID: minioadmin
95-
AWS_SECRET_ACCESS_KEY: minioadmin
96-
AWS_DEFAULT_REGION: eu-central-2
94+
LIBSQL_BOTTOMLESS_AWS_ACCESS_KEY_ID: minioadmin
95+
LIBSQL_BOTTOMLESS_AWS_SECRET_ACCESS_KEY: minioadmin
96+
LIBSQL_BOTTOMLESS_AWS_DEFAULT_REGION: eu-central-2
9797
LIBSQL_BOTTOMLESS_BUCKET: bottomless
9898
LIBSQL_BOTTOMLESS_ENDPOINT: http://localhost:9000
9999

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ environment variables can be used to configure the replication:
8383
```bash
8484
LIBSQL_BOTTOMLESS_BUCKET=my-bucket # Default bucket name: bottomless
8585
LIBSQL_BOTTOMLESS_ENDPOINT='http://localhost:9000' # address can be overridden for local testing, e.g. with Minio
86-
AWS_SECRET_ACCESS_KEY= # regular AWS variables are used
87-
AWS_ACCESS_KEY_ID= # ... to set up auth, regions, etc.
88-
AWS_REGION= # .
86+
LIBSQL_BOTTOMLESS_AWS_SECRET_ACCESS_KEY= # regular AWS variables are used
87+
LIBSQL_BOTTOMLESS_AWS_ACCESS_KEY_ID= # ... to set up auth, regions, etc.
88+
LIBSQL_BOTTOMLESS_AWS_REGION= # .
8989
```
9090

9191
### bottomless-cli

bottomless/src/replicator.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::wal::WalFileReader;
66
use anyhow::anyhow;
77
use arc_swap::ArcSwap;
88
use async_compression::tokio::write::GzipEncoder;
9+
use aws_sdk_s3::config::{Credentials, Region};
910
use aws_sdk_s3::error::SdkError;
1011
use aws_sdk_s3::operation::get_object::builders::GetObjectFluentBuilder;
1112
use aws_sdk_s3::operation::get_object::GetObjectError;
@@ -85,6 +86,9 @@ pub struct Options {
8586
/// Kind of compression algorithm used on the WAL frames to be sent to S3.
8687
pub use_compression: CompressionKind,
8788
pub aws_endpoint: Option<String>,
89+
pub access_key_id: Option<String>,
90+
pub secret_access_key: Option<String>,
91+
pub region: Option<String>,
8892
pub db_id: Option<String>,
8993
/// Bucket directory name where all S3 objects are backed up. General schema is:
9094
/// - `{db-name}-{uuid-v7}` subdirectories:
@@ -109,14 +113,34 @@ pub struct Options {
109113
}
110114

111115
impl Options {
112-
pub async fn client_config(&self) -> Config {
116+
pub async fn client_config(&self) -> Result<Config> {
113117
let mut loader = aws_config::from_env();
114118
if let Some(endpoint) = self.aws_endpoint.as_deref() {
115119
loader = loader.endpoint_url(endpoint);
116120
}
117-
aws_sdk_s3::config::Builder::from(&loader.load().await)
121+
let region = self
122+
.region
123+
.clone()
124+
.ok_or(anyhow!("LIBSQL_BOTTOMLESS_AWS_DEFAULT_REGION was not set"))?;
125+
let access_key_id = self
126+
.access_key_id
127+
.clone()
128+
.ok_or(anyhow!("LIBSQL_BOTTOMLESS_AWS_ACCESS_KEY_ID was not set"))?;
129+
let secret_access_key = self.secret_access_key.clone().ok_or(anyhow!(
130+
"LIBSQL_BOTTOMLESS_AWS_SECRET_ACCESS_KEY was not set"
131+
))?;
132+
let conf = aws_sdk_s3::config::Builder::from(&loader.load().await)
118133
.force_path_style(true)
119-
.build()
134+
.region(Region::new(region))
135+
.credentials_provider(Credentials::new(
136+
access_key_id,
137+
secret_access_key,
138+
None,
139+
None,
140+
"Static",
141+
))
142+
.build();
143+
Ok(conf)
120144
}
121145

122146
pub fn from_env() -> Result<Self> {
@@ -132,6 +156,15 @@ impl Options {
132156
options.max_batch_interval = Duration::from_secs(seconds);
133157
}
134158
}
159+
if let Ok(access_key_id) = std::env::var("LIBSQL_BOTTOMLESS_AWS_ACCESS_KEY_ID") {
160+
options.access_key_id = Some(access_key_id);
161+
}
162+
if let Ok(secret_access_key) = std::env::var("LIBSQL_BOTTOMLESS_AWS_SECRET_ACCESS_KEY") {
163+
options.secret_access_key = Some(secret_access_key);
164+
}
165+
if let Ok(region) = std::env::var("LIBSQL_BOTTOMLESS_AWS_DEFAULT_REGION") {
166+
options.region = Some(region);
167+
}
135168
if let Ok(count) = std::env::var("LIBSQL_BOTTOMLESS_BATCH_MAX_FRAMES") {
136169
match count.parse::<usize>() {
137170
Ok(count) => options.max_frames_per_batch = count,
@@ -208,6 +241,9 @@ impl Default for Options {
208241
restore_transaction_page_swap_after: 1000,
209242
db_id,
210243
aws_endpoint: None,
244+
access_key_id: None,
245+
secret_access_key: None,
246+
region: None,
211247
restore_transaction_cache_fpath: ".bottomless.restore".to_string(),
212248
bucket_name: "bottomless".to_string(),
213249
}
@@ -222,7 +258,7 @@ impl Replicator {
222258
}
223259

224260
pub async fn with_options<S: Into<String>>(db_path: S, options: Options) -> Result<Self> {
225-
let config = options.client_config().await;
261+
let config = options.client_config().await?;
226262
let client = Client::from_conf(config);
227263
let bucket = options.bucket_name.clone();
228264
let generation = Arc::new(ArcSwap::new(Arc::new(Self::generate_generation())));

docker-compose/docker-compose-with-bottomless.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ services:
66
- SQLD_NODE=primary
77
- SQLD_ENABLE_BOTTOMLESS_REPLICATION=true
88
- LIBSQL_BOTTOMLESS_ENDPOINT=http://s3:9000
9-
- AWS_ACCESS_KEY_ID=minioadmin
10-
- AWS_SECRET_ACCESS_KEY=minioadmin
11-
- AWS_DEFAULT_REGION=eu-central-2
9+
- LIBSQL_BOTTOMLESS_AWS_ACCESS_KEY_ID=minioadmin
10+
- LIBSQL_BOTTOMLESS_AWS_SECRET_ACCESS_KEY=minioadmin
11+
- LIBSQL_BOTTOMLESS_AWS_DEFAULT_REGION=eu-central-2
1212
- RUST_LOG=info,bottomless=trace
1313
ports:
1414
- "6000:5000"

sqld/src/test/bottomless.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{run_server, Config};
22
use anyhow::Result;
3+
use aws_sdk_s3::config::{Credentials, Region};
34
use libsql_client::{Connection, QueryResult, Statement, Value};
45
use std::net::ToSocketAddrs;
56
use std::path::PathBuf;
@@ -322,16 +323,29 @@ where
322323
db.batch(stmts).await
323324
}
324325

326+
async fn s3_config() -> aws_sdk_s3::config::Config {
327+
let loader = aws_config::from_env().endpoint_url(S3_URL);
328+
aws_sdk_s3::config::Builder::from(&loader.load().await)
329+
.force_path_style(true)
330+
.region(Region::new(
331+
std::env::var("LIBSQL_BOTTOMLESS_AWS_DEFAULT_REGION").unwrap(),
332+
))
333+
.credentials_provider(Credentials::new(
334+
std::env::var("LIBSQL_BOTTOMLESS_AWS_ACCESS_KEY_ID").unwrap(),
335+
std::env::var("LIBSQL_BOTTOMLESS_AWS_SECRET_ACCESS_KEY").unwrap(),
336+
None,
337+
None,
338+
"Static",
339+
))
340+
.build()
341+
}
342+
325343
/// Checks if the corresponding bucket is empty (has any elements) or not.
326344
/// If bucket was not found, it's equivalent of an empty one.
327345
async fn assert_bucket_occupancy(bucket: &str, expect_empty: bool) {
328346
use aws_sdk_s3::Client;
329347

330-
let loader = aws_config::from_env().endpoint_url(S3_URL);
331-
let conf = aws_sdk_s3::config::Builder::from(&loader.load().await)
332-
.force_path_style(true)
333-
.build();
334-
let client = Client::from_conf(conf);
348+
let client = Client::from_conf(s3_config().await);
335349
if let Ok(out) = client.list_objects().bucket(bucket).send().await {
336350
let contents = out.contents().unwrap_or_default();
337351
if expect_empty {
@@ -388,11 +402,7 @@ impl S3BucketCleaner {
388402
use aws_sdk_s3::types::{Delete, ObjectIdentifier};
389403
use aws_sdk_s3::Client;
390404

391-
let loader = aws_config::from_env().endpoint_url(S3_URL);
392-
let conf = aws_sdk_s3::config::Builder::from(&loader.load().await)
393-
.force_path_style(true)
394-
.build();
395-
let client = Client::from_conf(conf);
405+
let client = Client::from_conf(s3_config().await);
396406
let objects = client.list_objects().bucket(bucket).send().await?;
397407
let mut delete_keys = Vec::new();
398408
for o in objects.contents().unwrap_or_default() {

0 commit comments

Comments
 (0)