Compare commits

...

13 Commits

Author SHA1 Message Date
charlesgauthereau 4de2b81b33 chore(release): 1.1.2-rc.2 2026-02-16 09:00:26 +01:00
charlesgauthereau b06f9d8186 fix: failed backup 2026-02-16 09:00:18 +01:00
charlesgauthereau f5a2182723 fix: blocking for mysql database 2026-02-16 08:43:27 +01:00
charlesgauthereau e8a96980f1 chore(release): 1.1.2-rc.1 2026-02-16 08:43:13 +01:00
charlesgauthereau a64792bcc6 fix: blocking for mysql database 2026-02-16 08:41:44 +01:00
charlesgauthereau 2d4542be5f chore: Cargo.lock 2026-02-16 08:21:32 +01:00
charlesgauthereau 4a00ed574d chore(release): 1.1.1 2026-02-16 08:21:10 +01:00
Charles GTE fd220598fc Merge pull request #12 from Portabase/fix/s3-region
fix/s3-region
2026-02-16 08:19:11 +01:00
charlesgauthereau d8b239a123 fix: s3 region to us-east-1 2026-02-16 08:18:14 +01:00
Charles GTE ebf0526366 Update README.md 2026-02-15 11:52:35 +01:00
Charles GTE 6461c1523b Merge pull request #11 from Portabase/dev
dev
2026-02-15 11:51:51 +01:00
charlesgauthereau 2809373de1 feat: README.md and docker-compose.yml 2026-02-15 11:50:16 +01:00
charlesgauthereau 2bcb393d60 feat: Adding AES GCM encryption. 2026-02-13 14:36:54 +01:00
8 changed files with 72 additions and 66 deletions
+2 -2
View File
@@ -22,5 +22,5 @@ keywords:
- self-hosted
- portabase
license: Apache-2.0
version: 1.1.0
date-released: "2026-02-13"
version: 1.1.2-rc.2
date-released: "2026-02-16"
Generated
+1 -1
View File
@@ -2851,7 +2851,7 @@ dependencies = [
[[package]]
name = "portabase-agent"
version = "1.1.0-rc.2"
version = "1.1.2-rc.1"
dependencies = [
"aes",
"aes-gcm",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "portabase-agent"
version = "1.1.0"
version = "1.1.2-rc.2"
edition = "2024"
[dependencies]
+3 -4
View File
@@ -11,13 +11,12 @@ services:
# - ./databases.toml:/config/config.toml
- cargo-registry:/usr/local/cargo/registry
- cargo-git:/usr/local/cargo/git
- cargo-target:/app/target
# - cargo-target:/app/target
environment:
APP_ENV: development
LOG: debug
TZ: "Europe/Paris"
EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiMzI3YTU4ODktYzE0MC00ODMzLTk1ZWMtNTBmMmU2NTFlZmJhIiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ=="
# EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiZWE2NTg1MDctZTA5My00NDUxLWIxZDAtMDgwZWZjMGNmNWYzIiwicHVibGljS2V5IjoiLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tXG5NSUlCQ2dLQ0FRRUE5TWV4M2pmdnVLdFB5YU1ERnh2Ulp2dmd3YkRJQ2JzQi81Wll5NDNSVVRBaXZRYjJiSDdYXG5qRHBQd1lJeCs4UFBrbHlRbDVMQzV1UWZEaCs4SVd4OG1LZ3FvMXpWMkdiZXdGbEdEWFYxVEdyU1ZEU25aSWR4XG52bWdYc29EeXhVMlJvWUFUMS9YMWxuc2YxenZKdkFMTkhXdEhRdk42SjVDZTFSMmFsendVRGFEVXlJNzRmSldQXG5tNTh0SDMrYklXL0VVTXdjaWNxM0oySWw3Vm9KNkZNUHJQL1ZSOWEvdFF1SU1qa200MXpFY2NscExPa2luRkxuXG54NmVUWkFSZUpya2UrbnRvZ2t4TGEyRWV5a1lUNzB4V3hKNWp5ZExBVnRvNkkyQlVLVVJoTkowTUFaU29NYUtvXG5iMGJRcnY1UzExZWllMnMrT2I3aTYzSFpkVUx0UmV1MVJ3SURBUUFCXG4tLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tXG4ifQ"
EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiOWZjYjhmNjUtNTcyMC00N2M3LThkNWItYWFlMmVjOTc2OWU1IiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ=="
#POOLING: 1
#DATABASES_CONFIG_FILE: "config.toml"
extra_hosts:
@@ -95,7 +94,7 @@ services:
volumes:
cargo-registry:
cargo-git:
cargo-target:
# cargo-target:
postgres-data:
BIN
View File
Binary file not shown.
+15 -8
View File
@@ -1,19 +1,26 @@
use crate::services::config::DatabaseConfig;
use anyhow::Context;
use std::collections::HashMap;
use std::process::Command;
use tokio::process::Command;
use tokio::time::{Duration, timeout};
pub async fn run(cfg: DatabaseConfig, env: HashMap<String, String>) -> anyhow::Result<bool> {
let output = Command::new("mysqladmin")
.arg("--host")
let mut cmd = Command::new("mysqladmin");
cmd.arg("--host")
.arg(cfg.host)
.arg("--port")
.arg(cfg.port.to_string())
.arg("--user")
.arg(cfg.username)
.arg("ping")
.envs(env)
.output()
.with_context(|| format!("Failed to ping MySQL server {}", cfg.name))?;
Ok(output.status.success())
.envs(env);
let result = timeout(Duration::from_secs(10), cmd.output()).await;
match result {
Ok(output) => {
let output = output?;
Ok(output.status.success())
}
Err(_) => Ok(false),
}
}
+48 -20
View File
@@ -69,7 +69,6 @@ impl BackupService {
return;
}
Ok(false) => {
match ctx
.api
.backup_create(
@@ -85,13 +84,27 @@ impl BackupService {
info!("Created temp directory {}", tmp_path.display());
match BackupService::run(db_cfg, &tmp_path).await {
Ok(mut result) => {
let backup_id = backup_created_result.unwrap().backup.id;
if result.status == "failed" {
error!("Backup failed early for {}", result.generated_id);
let service = BackupService { ctx: ctx.clone() };
let _ = service
.send_result(result, vec![], &backup_id)
.await;
return;
}
if let Some(backup_file) = result.backup_file.take() {
match compress_to_tar_gz_large(&backup_file).await {
Ok(compression_result) => {
result.backup_file =
Some(compression_result.compressed_path);
let service = BackupService { ctx: ctx.clone() };
let backup_id = backup_created_result.unwrap().backup.id;
match service
.upload(
result.clone(),
@@ -107,7 +120,7 @@ impl BackupService {
.send_result(
result,
upload_result,
&backup_id
&backup_id,
)
.await
{
@@ -147,7 +160,7 @@ impl BackupService {
}
Err(e) => error!("Backup creation failed: {}", e),
}
},
}
Err(e) => error!("An error occurred while checking lock : {}", e),
}
}
@@ -162,7 +175,16 @@ impl BackupService {
let generated_id = cfg.generated_id.clone();
let db_type = cfg.db_type.clone();
let reachable = db_instance.ping().await.unwrap_or(false);
let reachable = match db_instance.ping().await {
Ok(v) => v,
Err(e) => {
error!("Ping failed: {}", e);
return Err(e.into());
}
};
info!("Reachable: {}", reachable);
if !reachable {
return Ok(BackupResult {
@@ -276,7 +298,7 @@ impl BackupService {
}
}
};
match self.ctx.api.backup_upload_status(
self.ctx.edge_key.agent_id.clone(),
generated_id.clone(),
@@ -284,12 +306,12 @@ impl BackupService {
status,
remote_path,
total_size,
backup_id
backup_id,
).await {
Ok(_) => {
upload_result
},
Err(err)=> {
}
Err(err) => {
error!(
"backup_upload_status failed (generated_id={}, storage_id={}): {}",
generated_id, storage_id, err
@@ -355,17 +377,23 @@ impl BackupService {
"failed"
};
let file_size = upload_results
.iter()
.map(|r| r.total_size)
.try_fold((0u64, 0u64), |(sum, count), v| {
match v {
Some(size) => Ok((sum + size, count + 1)),
None => Err(()), // stop and return None
}
})
.ok()
.map(|(sum, count)| sum / count);
let file_size = if status == "failed" {
None
} else {
let mut sum = 0u64;
let mut count = 0u64;
for size in upload_results.iter().filter_map(|r| r.total_size) {
sum += size;
count += 1;
}
if count == 0 {
None
} else {
Some(sum / count)
}
};
match self
.ctx
+2 -30
View File
@@ -61,8 +61,7 @@ impl StorageProvider for S3Provider {
let upload = match build_stream(
&file_path,
encrypt,
&ctx.edge_key.master_key_b64
// encrypt.then(|| ctx.edge_key.public_key.as_bytes().to_vec()),
&ctx.edge_key.master_key_b64,
)
.await
{
@@ -100,7 +99,7 @@ impl StorageProvider for S3Provider {
"static-creds",
);
let region = Region::new(config.region.clone().unwrap_or("eu-central-3".to_string()));
let region = Region::new(config.region.clone().unwrap_or("us-east-1".to_string()));
let sdk_config = s3::config::Builder::new()
.credentials_provider(credentials)
@@ -284,33 +283,6 @@ impl StorageProvider for S3Provider {
remote_file_path
);
// if let Some(enc) = upload.encryption {
// let meta = EncryptionMetadataFile {
// version: 1,
// cipher: "AES-256-CBC+RSA-OAEP-SHA256".to_string(),
// encrypted_aes_key_b64: general_purpose::STANDARD
// .encode(enc.encrypted_aes_key),
// iv_b64: general_purpose::STANDARD.encode(enc.iv),
// };
//
// let meta_toml = toml::to_string(&meta).expect("Serialization error");
//
// let meta_key = format!("{}.meta", remote_file_path);
//
// client
// .put_object()
// .bucket(bucket)
// .key(&meta_key)
// .body(ByteStream::from(meta_toml.into_bytes()))
// .content_type("application/toml")
// .send()
// .await
// .map_err(|e| {
// error!("Metadata upload failed: {}", e);
// e
// })
// .unwrap();
// }
UploadResult {
storage_id: storage.id.clone(),