From c3eedc072831fbe859f32baffe61f68fee12b5b3 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Thu, 16 Nov 2023 17:06:05 +0000 Subject: [PATCH] ci: [#384] add container healthcheck for index service --- Containerfile | 9 +++- .../container/e2e/mysql/run-e2e-tests.sh | 8 ++-- .../container/e2e/sqlite/run-e2e-tests.sh | 8 ++-- src/app.rs | 44 +++++++++++++++++-- src/bin/health_check.rs | 34 ++++++++++++++ 5 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 src/bin/health_check.rs diff --git a/Containerfile b/Containerfile index 4048d27d..89e65706 100644 --- a/Containerfile +++ b/Containerfile @@ -85,7 +85,9 @@ COPY --from=build \ RUN cargo nextest run --workspace-remap /test/src/ --extract-to /test/src/ --no-run --archive-file /test/torrust-index.tar.zst RUN cargo nextest run --workspace-remap /test/src/ --target-dir-remap /test/src/target/ --cargo-metadata /test/src/target/nextest/cargo-metadata.json --binaries-metadata /test/src/target/nextest/binaries-metadata.json -RUN mkdir -p /app/bin/; cp -l /test/src/target/release/torrust-index /app/bin/torrust-index +RUN mkdir -p /app/bin/; \ + cp -l /test/src/target/release/torrust-index /app/bin/torrust-index; \ + cp -l /test/src/target/release/health_check /app/bin/health_check; # RUN mkdir -p /app/lib/; cp -l $(realpath $(ldd /app/bin/torrust-index | grep "libz\.so\.1" | awk '{print $3}')) /app/lib/libz.so.1 RUN chown -R root:root /app; chmod -R u=rw,go=r,a+X /app; chmod -R a+x /app/bin @@ -99,11 +101,13 @@ ARG TORRUST_INDEX_PATH_CONFIG="/etc/torrust/index/index.toml" ARG TORRUST_INDEX_DATABASE_DRIVER="sqlite3" ARG USER_ID=1000 ARG API_PORT=3001 +ARG HEALTH_CHECK_PORT=3002 ENV TORRUST_INDEX_PATH_CONFIG=${TORRUST_INDEX_PATH_CONFIG} ENV TORRUST_INDEX_DATABASE_DRIVER=${TORRUST_INDEX_DATABASE_DRIVER} ENV USER_ID=${USER_ID} ENV API_PORT=${API_PORT} +ENV HEALTH_CHECK_PORT=${HEALTH_CHECK_PORT} ENV TZ=Etc/UTC EXPOSE ${API_PORT}/tcp @@ -130,5 +134,6 @@ CMD ["sh"] FROM runtime as release ENV RUNTIME="release" COPY --from=test /app/ /usr/ -# HEALTHCHECK CMD ["/usr/bin/wget", "--no-verbose", "--tries=1", "--spider", "localhost:${API_PORT}/version"] +HEALTHCHECK --interval=5s --timeout=5s --start-period=3s --retries=3 \ + CMD /usr/bin/health_check http://localhost:${HEALTH_CHECK_PORT}/health_check || exit 1 CMD ["/usr/bin/torrust-index"] diff --git a/contrib/dev-tools/container/e2e/mysql/run-e2e-tests.sh b/contrib/dev-tools/container/e2e/mysql/run-e2e-tests.sh index 4e9ab8c7..03f23079 100755 --- a/contrib/dev-tools/container/e2e/mysql/run-e2e-tests.sh +++ b/contrib/dev-tools/container/e2e/mysql/run-e2e-tests.sh @@ -25,10 +25,10 @@ echo "Running E2E tests using MySQL ..." ./contrib/dev-tools/container/e2e/mysql/e2e-env-up.sh || exit 1 # Wait for conatiners to be healthy -./contrib/dev-tools/container/functions/wait_for_container_to_be_healthy.sh torrust-mysql-1 10 3 -# todo: implement healthchecks for tracker and index and wait until they are healthy -#wait_for_container torrust-tracker-1 10 3 -#wait_for_container torrust-idx-back-1 10 3 +./contrib/dev-tools/container/functions/wait_for_container_to_be_healthy.sh torrust-mysql-1 10 3 || exit 1 +# todo: implement healthchecks for the tracker and wait until it's healthy +#./contrib/dev-tools/container/functions/wait_for_container_to_be_healthy.sh torrust-tracker-1 10 3 +./contrib/dev-tools/container/functions/wait_for_container_to_be_healthy.sh torrust-index-1 10 3 || exit 1 sleep 20s # Just to make sure that everything is up and running diff --git a/contrib/dev-tools/container/e2e/sqlite/run-e2e-tests.sh b/contrib/dev-tools/container/e2e/sqlite/run-e2e-tests.sh index 60a21c22..afedc5f6 100755 --- a/contrib/dev-tools/container/e2e/sqlite/run-e2e-tests.sh +++ b/contrib/dev-tools/container/e2e/sqlite/run-e2e-tests.sh @@ -26,10 +26,10 @@ echo "Running E2E tests using SQLite ..." ./contrib/dev-tools/container/e2e/sqlite/e2e-env-up.sh || exit 1 # Wait for conatiners to be healthy -./contrib/dev-tools/container/functions/wait_for_container_to_be_healthy.sh torrust-mysql-1 10 3 -# todo: implement healthchecks for tracker and index and wait until they are healthy -#wait_for_container torrust-tracker-1 10 3 -#wait_for_container torrust-idx-back-1 10 3 +./contrib/dev-tools/container/functions/wait_for_container_to_be_healthy.sh torrust-mysql-1 10 3 || exit 1 +# todo: implement healthchecks for the tracker and wait until it's healthy +#./contrib/dev-tools/container/functions/wait_for_container_to_be_healthy.sh torrust-tracker-1 10 3 +./contrib/dev-tools/container/functions/wait_for_container_to_be_healthy.sh torrust-index-1 10 3 || exit 1 sleep 20s # Just to make sure that everything is up and running diff --git a/src/app.rs b/src/app.rs index 353ce274..ec91ad10 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,10 @@ use std::net::SocketAddr; use std::sync::Arc; +use axum::routing::get; +use axum::{Json, Router}; +use log::info; +use serde_json::{json, Value}; use tokio::task::JoinHandle; use crate::bootstrap::logging; @@ -22,6 +26,8 @@ use crate::web::api::v1::auth::Authentication; use crate::web::api::{start, Version}; use crate::{mailer, tracker}; +const HEALTH_CHECK_PORT: u16 = 3002; + pub struct Running { pub api_socket_addr: SocketAddr, pub api_server: Option>>, @@ -159,6 +165,8 @@ pub async fn run(configuration: Configuration, api_version: &Version) -> Running let weak_tracker_statistics_importer = Arc::downgrade(&tracker_statistics_importer); let tracker_statistics_importer_handle = tokio::spawn(async move { + info!("Tracker statistics importer started"); + let interval = std::time::Duration::from_secs(torrent_info_update_interval); let mut interval = tokio::time::interval(interval); interval.tick().await; // first tick is immediate... @@ -173,12 +181,42 @@ pub async fn run(configuration: Configuration, api_version: &Version) -> Running }); // Start API server - let running_api = start(app_data, &net_ip, net_port, api_version).await; - Running { + // Full running application + let app = Running { api_socket_addr: running_api.socket_addr, api_server: running_api.api_server, tracker_data_importer_handle: tracker_statistics_importer_handle, - } + }; + + // Start Health Checker + // This must be done after launching the other services because it does not + // re-check the health of all services. + let _health_check_handle = tokio::spawn(async move { + let app = Router::new().route("/health_check", get(get(health_check))); + + let addr = format!("127.0.0.1:{HEALTH_CHECK_PORT}"); + + info!("Health checker listening on http://{}/health_check", addr); + + axum::Server::bind(&addr.parse().unwrap()) + .serve(app.into_make_service()) + .await + .unwrap(); + }); + + app +} + +/// It runs a health check on the application. +/// +/// For the time being, we only return ok if the application services were +/// launched. This services has to be launched after launching all the other +/// application services. +/// +/// It's used for container health check when the application is containerized. +async fn health_check() -> Json { + // todo: check that services are healthy + Json(json!({ "status": "Ok" })) } diff --git a/src/bin/health_check.rs b/src/bin/health_check.rs new file mode 100644 index 00000000..20691ba7 --- /dev/null +++ b/src/bin/health_check.rs @@ -0,0 +1,34 @@ +//! Command line tool to parse a torrent file and print the decoded torrent. +//! +//! It's only used for debugging purposes. +use std::{env, process}; + +#[tokio::main] +async fn main() { + let args: Vec = env::args().collect(); + if args.len() != 2 { + eprintln!("Usage: cargo run --bin health_check "); + eprintln!("Example: cargo run --bin health_check http://localhost:3002/health_check"); + std::process::exit(1); + } + + println!("Health check ..."); + + let url = &args[1].clone(); + + match reqwest::get(url).await { + Ok(response) => { + if response.status().is_success() { + println!("STATUS: {}", response.status()); + process::exit(0); + } else { + println!("Non-success status received."); + process::exit(1); + } + } + Err(err) => { + println!("ERROR: {err}"); + process::exit(1); + } + } +}