diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
index 6cfc387..318244b 100644
--- a/.idea/dataSources.xml
+++ b/.idea/dataSources.xml
@@ -1,12 +1,19 @@
-
+
postgresql
true
org.postgresql.Driver
jdbc:postgresql:///acrate
$ProjectFileDir$
+
+ postgresql
+ true
+ org.postgresql.Driver
+ jdbc:postgresql://localhost:5432/postgres
+ $ProjectFileDir$
+
\ No newline at end of file
diff --git a/.idea/jsonSchemas.xml b/.idea/jsonSchemas.xml
new file mode 100644
index 0000000..da97271
--- /dev/null
+++ b/.idea/jsonSchemas.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Check.xml b/.idea/runConfigurations/Check.xml
new file mode 100644
index 0000000..048d405
--- /dev/null
+++ b/.idea/runConfigurations/Check.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/acrate_database/Cargo.toml b/acrate_database/Cargo.toml
index ba63f83..d2afc81 100644
--- a/acrate_database/Cargo.toml
+++ b/acrate_database/Cargo.toml
@@ -13,7 +13,7 @@ categories = ["database"]
diesel = { version = "2.2.4", features = ["postgres", "uuid"] }
diesel-async = { version = "0.5.1", features = ["postgres"] }
diesel_migrations = { version = "2.2.0", optional = true }
-log = "0.4.22"
+log = { version = "0.4.22", features = ["std", "max_level_trace", "release_max_level_debug"] }
mediatype = "0.19.18"
micronfig = { version = "0.3.0", optional = true }
mime = "0.3.17"
diff --git a/acrate_docker/Dockerfile b/acrate_docker/Dockerfile
new file mode 100644
index 0000000..7af2e9e
--- /dev/null
+++ b/acrate_docker/Dockerfile
@@ -0,0 +1,32 @@
+FROM rust AS base_builder
+WORKDIR /usr/src/acrate
+COPY --from=source ./acrate_database ./acrate_database
+COPY --from=source ./acrate_nodeinfo ./acrate_nodeinfo
+COPY --from=source ./acrate_rd ./acrate_rd
+COPY --from=source ./acrate_rdserver ./acrate_rdserver
+COPY --from=source ./Cargo.toml ./Cargo.toml
+COPY --from=source ./Cargo.lock ./Cargo.lock
+
+FROM rust:slim AS base_runner
+RUN apt-get update
+RUN apt-get upgrade --assume-yes
+RUN apt-get install --assume-yes libpq5
+WORKDIR /usr/local/bin
+ENV RUST_LOG="warn"
+
+FROM base_builder AS migrate_build
+RUN cargo build --release --package=acrate_database --features=bin --bin=acrate_database_migrate
+
+FROM base_runner AS migrate
+COPY --from=migrate_build /usr/src/acrate/target/release/acrate_database_migrate /usr/local/bin/acrate_database_migrate
+ENTRYPOINT ["acrate_database_migrate"]
+ENV RUST_LOG="warn,acrate_database_migrate=info"
+
+FROM base_builder AS rdserver_build
+RUN cargo build --release --package=acrate_rdserver --bin=acrate_rdserver
+
+FROM base_runner AS rdserver
+COPY --from=rdserver_build /usr/src/acrate/target/release/acrate_rdserver /usr/local/bin/acrate_rdserver
+ENTRYPOINT ["acrate_rdserver"]
+HEALTHCHECK CMD ["curl", "http://127.0.0.1/.healthcheck"]
+ENV RUST_LOG="warn,acrate_rdserver=info"
diff --git a/acrate_docker/compose.yml b/acrate_docker/compose.yml
new file mode 100644
index 0000000..03e4a32
--- /dev/null
+++ b/acrate_docker/compose.yml
@@ -0,0 +1,95 @@
+# Full acrate stack, running on a single machine for experimental purposes
+
+x-config:
+ ingress_config_dir: &ingress_config_dir "./config/caddy"
+
+name: "acrate"
+
+volumes:
+ ingress_data:
+ ingress_config:
+ postgres_data:
+
+services:
+ # Public ingress node
+ ingress:
+ image: "caddy"
+ restart: "unless-stopped"
+ cap_add:
+ - "NET_ADMIN"
+ ports:
+ - protocol: "tcp"
+ target: 80
+ published: 80
+ - protocol: "tcp"
+ target: 443
+ published: 443
+ - protocol: "udp"
+ target: 443
+ published: 443
+ volumes:
+ - type: "volume"
+ source: "ingress_data"
+ target: "/data"
+ - type: "volume"
+ source: "ingress_config"
+ target: "/config"
+ - type: "bind"
+ source: *ingress_config_dir
+ target: "/etc/caddy"
+
+ # Main database
+ database:
+ image: "postgres"
+ restart: "unless-stopped"
+ environment:
+ # Make sure the password is the same for both client and server tools
+ POSTGRES_PASSWORD: &postgres_password "acrate"
+ PGUSER: "postgres"
+ PGPASS: *postgres_password
+ volumes:
+ - type: "volume"
+ source: "postgres_data"
+ target: "/var/lib/postgresql/data"
+ ports:
+ # FIXME: for development purposes only
+ - protocol: "tcp"
+ host_ip: "127.0.0.1"
+ target: 5432
+ published: 5432
+ expose:
+ - 5432
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready"]
+
+ # Migrations
+ migrate:
+ build:
+ dockerfile: "./Dockerfile"
+ additional_contexts:
+ - "source=.."
+ target: "migrate"
+ environment:
+ ACRATE_DATABASE_DATABASE_URL: &database_url "postgres:///postgres?host=database&user=postgres&password=acrate" # TODO: Split parameters off to their own envvars
+ depends_on:
+ database:
+ condition: "service_healthy"
+
+ # Resource descriptor server
+ rdserver:
+ build:
+ dockerfile: "./Dockerfile"
+ additional_contexts:
+ - "source=.."
+ target: "rdserver"
+ restart: "unless-stopped"
+ environment:
+ ACRATE_WEBFINGER_BIND_ADDRESS: "0.0.0.0:80"
+ ACRATE_WEBFINGER_DATABASE_URL: *database_url
+ expose:
+ - 80
+ depends_on:
+ database:
+ condition: "service_healthy"
+ migrate:
+ condition: "service_completed_successfully"
diff --git a/acrate_docker/config/caddy/Caddyfile b/acrate_docker/config/caddy/Caddyfile
new file mode 100644
index 0000000..6514746
--- /dev/null
+++ b/acrate_docker/config/caddy/Caddyfile
@@ -0,0 +1,16 @@
+# replace with your HTTPS domain
+:80 {
+ @rdserver {
+ path "/.well-known/webfinger"
+ path "/.well-known/host-meta"
+ path "/.well-known/host-meta.xml"
+ path "/.well-known/host-meta.json"
+ }
+
+ reverse_proxy @rdserver {
+ to "http://rdserver"
+
+ health_uri "/.healthcheck"
+ health_status "204"
+ }
+}
diff --git a/acrate_nodeinfo/Cargo.toml b/acrate_nodeinfo/Cargo.toml
index 5e7693e..b137bc0 100644
--- a/acrate_nodeinfo/Cargo.toml
+++ b/acrate_nodeinfo/Cargo.toml
@@ -11,7 +11,7 @@ categories = ["web-programming"]
[dependencies]
acrate_rd = { path = "../acrate_rd" }
-log = "0.4.22"
+log = { version = "0.4.22", features = ["std", "max_level_trace", "release_max_level_debug"] }
mediatype = { version = "0.19.18", features = ["serde"] }
reqwest = { version = "0.12.9", features = ["json", "stream"] }
serde = { version = "1.0.214", features = ["derive"] }
diff --git a/acrate_rdserver/Cargo.toml b/acrate_rdserver/Cargo.toml
index 4752f69..43b0148 100644
--- a/acrate_rdserver/Cargo.toml
+++ b/acrate_rdserver/Cargo.toml
@@ -15,7 +15,7 @@ acrate_rd = { path = "../acrate_rd" }
anyhow = "1.0.93"
axum = { version = "0.7.7", features = ["macros"] }
axum-extra = { version = "0.9.4", features = ["query"] }
-log = "0.4.22"
+log = { version = "0.4.22", features = ["std", "max_level_trace", "release_max_level_debug"] }
micronfig = "0.3.0"
minijinja = "2.5.0"
pretty_env_logger = "0.5.0"
diff --git a/acrate_rdserver/src/main.rs b/acrate_rdserver/src/main.rs
index 3752cbf..60dffed 100644
--- a/acrate_rdserver/src/main.rs
+++ b/acrate_rdserver/src/main.rs
@@ -21,6 +21,7 @@ async fn main() -> anyhow::Result {
log::trace!("Creating Axum router...");
let app = axum::Router::new()
.route("/*path", axum::routing::get(route::webfinger_handler))
+ .route("/.healthcheck", axum::routing::get(route::healthcheck_handler))
.layer(Extension(Arc::new(mj)));
log::trace!("Axum router created successfully!");
@@ -31,7 +32,7 @@ async fn main() -> anyhow::Result {
.context("failed to bind listener to address")?;
log::trace!("Tokio listener bound to: {bind_address}");
- log::debug!("Starting server...");
+ log::info!("Starting server...");
axum::serve(listener, app)
.await
.context("server exited with error")?;
diff --git a/acrate_rdserver/src/route.rs b/acrate_rdserver/src/route.rs
index 61ba271..9821182 100644
--- a/acrate_rdserver/src/route.rs
+++ b/acrate_rdserver/src/route.rs
@@ -13,6 +13,18 @@ use acrate_rd::jrd::ResourceDescriptorLinkJRD;
use acrate_rd::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD, ResourceDescriptorTitleXRD};
use crate::config;
+pub async fn healthcheck_handler() -> Result {
+ log::debug!("Handling an healthcheck request!");
+
+ log::trace!("Making sure the database is up...");
+ let _conn = AsyncPgConnection::establish(config::ACRATE_WEBFINGER_DATABASE_URL())
+ .await
+ .map_err(|_| StatusCode::BAD_GATEWAY)?;
+
+ log::trace!("Healthcheck successful! Everything's fine!");
+ Ok(StatusCode::NO_CONTENT)
+}
+
#[derive(Debug, Clone, Deserialize)]
pub struct WebfingerQuery {
pub resource: Option,
@@ -27,7 +39,7 @@ pub async fn webfinger_handler(
headers: HeaderMap,
Extension(mj): Extension>>,
) -> Result, StatusCode> {
- log::info!("Handling a WebFinger request!");
+ log::debug!("Handling a WebFinger request!");
let resource = resource.unwrap_or_else(|| "".to_string());
log::debug!("Resource is: {resource:#?}");