1
0
Fork 0
mirror of https://codeberg.org/icewind/haze.git synced 2026-06-04 01:24:09 +02:00

sharding option

This commit is contained in:
Robin Appelman 2024-07-03 16:20:07 +02:00
commit ce0d3ff3e4
19 changed files with 248 additions and 121 deletions

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::exec::exec;
use crate::image::pull_image;
@ -34,6 +35,7 @@ impl ServiceTrait for ClamIcap {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "ghcr.io/icewind1991/icap-clamav-service-tls";
pull_image(docker, image).await?;
@ -122,6 +124,7 @@ impl ServiceTrait for ClamIcapTls {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "ghcr.io/icewind1991/icap-clamav-service-tls";
pull_image(docker, image).await?;

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -23,6 +24,7 @@ impl ServiceTrait for Dav {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "ugeek/webdav:amd64";
pull_image(docker, image).await?;
@ -71,11 +73,6 @@ impl ServiceTrait for Dav {
&["files_external"]
}
// no need to wait for dav, as it won't be used until the user logs in
async fn is_healthy(&self, _docker: &Docker, _cloud_id: &str) -> Result<bool> {
Ok(true)
}
async fn post_setup(
&self,
_docker: &Docker,

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -23,6 +24,7 @@ impl ServiceTrait for Imaginary {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "nextcloud/aio-imaginary:latest";
pull_image(docker, image).await?;
@ -66,11 +68,6 @@ impl ServiceTrait for Imaginary {
Some(format!("{}-imaginary", cloud_id))
}
// no need to wait for imaginary, as it won't be used until the user logs in
async fn is_healthy(&self, _docker: &Docker, _cloud_id: &str) -> Result<bool> {
Ok(true)
}
async fn post_setup(
&self,
_docker: &Docker,

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::exec::exec;
use crate::image::{image_exists, pull_image};
@ -29,6 +30,7 @@ impl ServiceTrait for Kaspersky {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "kaspersky";
if !image_exists(docker, image).await {
@ -71,7 +73,12 @@ impl ServiceTrait for Kaspersky {
Ok(vec![id])
}
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
async fn is_healthy(
&self,
docker: &Docker,
cloud_id: &str,
_options: &CloudOptions,
) -> Result<bool> {
let exit = exec(
docker,
self.container_name(cloud_id).unwrap(),
@ -130,6 +137,7 @@ impl ServiceTrait for KasperskyIcap {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "kaspersky-icap";
if !image_exists(docker, image).await {
@ -172,19 +180,6 @@ impl ServiceTrait for KasperskyIcap {
Ok(vec![id])
}
// async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
// let exit = exec(
// docker,
// self.container_name(cloud_id),
// "root",
// vec!["curl", "localhost/licenseinfo"],
// vec![],
// Option::<Stdout>::None,
// )
// .await?;
// Ok(exit.to_result().is_ok())
// }
fn container_name(&self, cloud_id: &str) -> Option<String> {
Some(format!("{}-kaspersky-icap", cloud_id))
}

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -27,6 +28,7 @@ impl ServiceTrait for Ldap {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "icewind1991/haze-ldap";
pull_image(docker, image).await?;
@ -75,6 +77,15 @@ impl ServiceTrait for Ldap {
fn apps(&self) -> &'static [&'static str] {
&["user_ldap"]
}
async fn is_healthy(
&self,
docker: &Docker,
cloud_id: &str,
_options: &CloudOptions,
) -> Result<bool> {
self.is_running(docker, cloud_id).await
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
@ -96,6 +107,7 @@ impl ServiceTrait for LdapAdmin {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "osixia/phpldapadmin";
pull_image(docker, image).await?;

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -23,6 +24,7 @@ impl ServiceTrait for Mail {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "rnwood/smtp4dev";
pull_image(docker, image).await?;
@ -66,11 +68,6 @@ impl ServiceTrait for Mail {
Some(format!("{}-mail", cloud_id))
}
// no need to wait for mail, as it won't be used until the user logs in
async fn is_healthy(&self, _docker: &Docker, _cloud_id: &str) -> Result<bool> {
Ok(true)
}
async fn post_setup(
&self,
_docker: &Docker,

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::exec::exec;
use crate::image::pull_image;
@ -77,6 +78,7 @@ impl ServiceTrait for ObjectStore {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
pull_image(docker, self.image()).await?;
let options = Some(CreateContainerOptions {
@ -117,7 +119,15 @@ impl ServiceTrait for ObjectStore {
Ok(vec![id])
}
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
async fn is_healthy(
&self,
docker: &Docker,
cloud_id: &str,
_options: &CloudOptions,
) -> Result<bool> {
if !self.is_running(docker, cloud_id).await? {
return Ok(false);
}
match self {
ObjectStore::S3 | ObjectStore::S3mb => {
let mut output = Vec::new();

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::exec::exec;
use crate::image::pull_image;
@ -27,6 +28,7 @@ impl ServiceTrait for Oc {
cloud_id: &str,
network: &str,
config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "owncloud/server:10.12.2";
pull_image(docker, image).await?;
@ -78,11 +80,6 @@ impl ServiceTrait for Oc {
Some(format!("{}-oc", cloud_id))
}
// no need to wait for oc
async fn is_healthy(&self, _docker: &Docker, _cloud_id: &str) -> Result<bool> {
Ok(true)
}
async fn post_setup(
&self,
docker: &Docker,

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -27,6 +28,7 @@ impl ServiceTrait for Office {
cloud_id: &str,
network: &str,
config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "collabora/code";
pull_image(docker, image).await?;

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -27,6 +28,7 @@ impl ServiceTrait for OnlyOffice {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "onlyoffice/documentserver";
pull_image(docker, image).await?;

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -26,6 +27,7 @@ impl ServiceTrait for NotifyPush {
cloud_id: &str,
network: &str,
config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "icewind1991/notify_push";
pull_image(docker, image).await?;
@ -79,10 +81,6 @@ impl ServiceTrait for NotifyPush {
&["notify_push"]
}
async fn is_healthy(&self, _docker: &Docker, _cloud_id: &str) -> Result<bool> {
Ok(true)
}
async fn post_setup(
&self,
docker: &Docker,

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -23,6 +24,7 @@ impl ServiceTrait for Sftp {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "atmoz/sftp:alpine";
pull_image(docker, image).await?;
@ -71,11 +73,6 @@ impl ServiceTrait for Sftp {
&["files_external"]
}
// no need to wait for dav, as it won't be used until the user logs in
async fn is_healthy(&self, _docker: &Docker, _cloud_id: &str) -> Result<bool> {
Ok(true)
}
async fn post_setup(
&self,
_docker: &Docker,

97
src/service/sharded.rs Normal file
View file

@ -0,0 +1,97 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::database::DatabaseFamily;
use crate::service::ServiceTrait;
use crate::Result;
use bollard::Docker;
use futures_util::future::try_join_all;
use maplit::hashmap;
use miette::Report;
use serde_json::json;
use serde_json::Value;
use std::collections::HashMap;
use std::convert::identity;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Sharding;
const SHARDS: &[&str] = &["-1", "-2"];
#[async_trait::async_trait]
impl ServiceTrait for Sharding {
fn name(&self) -> &str {
"sharding"
}
async fn spawn(
&self,
docker: &Docker,
cloud_id: &str,
network: &str,
_config: &HazeConfig,
options: &CloudOptions,
) -> Result<Vec<String>> {
if options.db.family() == DatabaseFamily::Sqlite {
return Err(Report::msg("Sharding is not supported with sqlite"));
}
let containers = try_join_all(
SHARDS
.iter()
.copied()
.map(|postfix| options.db.spawn(docker, cloud_id, network, postfix)),
)
.await?;
Ok(containers.into_iter().flatten().collect())
}
async fn is_healthy(
&self,
docker: &Docker,
cloud_id: &str,
options: &CloudOptions,
) -> Result<bool> {
let running = try_join_all(
SHARDS
.iter()
.copied()
.map(|postfix| options.db.is_healthy(docker, cloud_id, postfix)),
)
.await?;
Ok(running.iter().copied().all(identity))
}
fn config(
&self,
_docker: &Docker,
_cloud_id: &str,
_config: &HazeConfig,
) -> Result<HashMap<String, Value>> {
let shard_config = json!({
"filecache": {
"table": "filecache",
"primary_key": "fileid",
"shard_key": "storage",
"companion_tables": ["filecache_extended"],
"shards": [
{
"name": "haze",
"host": "db-1",
"tableprefix": "oc_",
"user": "haze",
"password": "haze",
},
{
"name": "haze",
"host": "db-2",
"tableprefix": "oc_",
"user": "haze",
"password": "haze",
}
],
}
});
Ok(hashmap! {String::from("db.sharding") => shard_config})
}
}

View file

@ -1,3 +1,4 @@
use crate::cloud::CloudOptions;
use crate::config::HazeConfig;
use crate::image::pull_image;
use crate::service::ServiceTrait;
@ -23,6 +24,7 @@ impl ServiceTrait for Smb {
cloud_id: &str,
network: &str,
_config: &HazeConfig,
_options: &CloudOptions,
) -> Result<Vec<String>> {
let image = "ghcr.io/servercontainers/samba:smbd-only-a3.18.0-s4.18.2-r0";
pull_image(docker, image).await?;
@ -75,11 +77,6 @@ impl ServiceTrait for Smb {
&["files_external"]
}
// no need to wait for smb, as it won't be used until the user logs in
async fn is_healthy(&self, _docker: &Docker, _cloud_id: &str) -> Result<bool> {
Ok(true)
}
async fn post_setup(
&self,
_docker: &Docker,