Skip to content

Commit

Permalink
Merge torrust#623: Extract Config from Tracker and Heath Check
Browse files Browse the repository at this point in the history
3f0dcea dev: add tests to health check (Cameron Garnham)
b310c75 dev: extract config from health check (Cameron Garnham)
3b49257 dev: extract config from core::tracker (Cameron Garnham)

Pull request description:

  This is the first three commits from torrust#557

  It includes an significant improvement of the Heath Check logic, as it now takes the active port from the binding, instead of the configuration.

ACKs for top commit:
  josecelano:
    ACK 3f0dcea

Tree-SHA512: 5076583618bf68dd7fe016b55da5a14490be2ec4e3416efe7d3bcd27c73fedbe5a219cd9f5bcc62c526007d1ae17fab7323b2199aa14fd9542bbe52eba2b6b38
  • Loading branch information
josecelano committed Jan 17, 2024
2 parents dde3d8d + 3f0dcea commit 203ce96
Show file tree
Hide file tree
Showing 55 changed files with 1,720 additions and 1,274 deletions.
2 changes: 2 additions & 0 deletions cSpell.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"Cyberneering",
"datagram",
"datetime",
"Deque",
"Dijke",
"distroless",
"dockerhub",
Expand Down Expand Up @@ -91,6 +92,7 @@
"Rasterbar",
"realpath",
"reannounce",
"Registar",
"repr",
"reqwest",
"rerequests",
Expand Down
18 changes: 6 additions & 12 deletions packages/configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@
//! [health_check_api]
//! bind_address = "127.0.0.1:1313"
//!```
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use std::net::IpAddr;
use std::str::FromStr;
use std::sync::Arc;
Expand Down Expand Up @@ -337,6 +337,8 @@ pub struct HttpTracker {
pub ssl_key_path: Option<String>,
}

pub type AccessTokens = HashMap<String, String>;

/// Configuration for the HTTP API.
#[serde_as]
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
Expand All @@ -360,21 +362,13 @@ pub struct HttpApi {
/// token and the value is the token itself. The token is used to
/// authenticate the user. All tokens are valid for all endpoints and have
/// the all permissions.
pub access_tokens: HashMap<String, String>,
pub access_tokens: AccessTokens,
}

impl HttpApi {
fn override_admin_token(&mut self, api_admin_token: &str) {
self.access_tokens.insert("admin".to_string(), api_admin_token.to_string());
}

/// Checks if the given token is one of the token in the configuration.
#[must_use]
pub fn contains_token(&self, token: &str) -> bool {
let tokens: HashMap<String, String> = self.access_tokens.clone();
let tokens: HashSet<String> = tokens.into_values().collect();
tokens.contains(token)
}
}

/// Configuration for the Health Check API.
Expand Down Expand Up @@ -804,7 +798,7 @@ mod tests {
fn http_api_configuration_should_check_if_it_contains_a_token() {
let configuration = Configuration::default();

assert!(configuration.http_api.contains_token("MyAccessToken"));
assert!(!configuration.http_api.contains_token("NonExistingToken"));
assert!(configuration.http_api.access_tokens.values().any(|t| t == "MyAccessToken"));
assert!(!configuration.http_api.access_tokens.values().any(|t| t == "NonExistingToken"));
}
}
29 changes: 23 additions & 6 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use tokio::task::JoinHandle;
use torrust_tracker_configuration::Configuration;

use crate::bootstrap::jobs::{health_check_api, http_tracker, torrent_cleanup, tracker_apis, udp_tracker};
use crate::servers::registar::Registar;
use crate::{core, servers};

/// # Panics
Expand All @@ -36,9 +37,11 @@ use crate::{core, servers};
///
/// - Can't retrieve tracker keys from database.
/// - Can't load whitelist from database.
pub async fn start(config: Arc<Configuration>, tracker: Arc<core::Tracker>) -> Vec<JoinHandle<()>> {
pub async fn start(config: &Configuration, tracker: Arc<core::Tracker>) -> Vec<JoinHandle<()>> {
let mut jobs: Vec<JoinHandle<()>> = Vec::new();

let registar = Registar::default();

// Load peer keys
if tracker.is_private() {
tracker
Expand Down Expand Up @@ -67,31 +70,45 @@ pub async fn start(config: Arc<Configuration>, tracker: Arc<core::Tracker>) -> V
udp_tracker_config.bind_address, config.mode
);
} else {
jobs.push(udp_tracker::start_job(udp_tracker_config, tracker.clone()).await);
jobs.push(udp_tracker::start_job(udp_tracker_config, tracker.clone(), registar.give_form()).await);
}
}

// Start the HTTP blocks
for http_tracker_config in &config.http_trackers {
if let Some(job) = http_tracker::start_job(http_tracker_config, tracker.clone(), servers::http::Version::V1).await {
if let Some(job) = http_tracker::start_job(
http_tracker_config,
tracker.clone(),
registar.give_form(),
servers::http::Version::V1,
)
.await
{
jobs.push(job);
};
}

// Start HTTP API
if config.http_api.enabled {
if let Some(job) = tracker_apis::start_job(&config.http_api, tracker.clone(), servers::apis::Version::V1).await {
if let Some(job) = tracker_apis::start_job(
&config.http_api,
tracker.clone(),
registar.give_form(),
servers::apis::Version::V1,
)
.await
{
jobs.push(job);
};
}

// Start runners to remove torrents without peers, every interval
if config.inactive_peer_cleanup_interval > 0 {
jobs.push(torrent_cleanup::start_job(&config, &tracker));
jobs.push(torrent_cleanup::start_job(config, &tracker));
}

// Start Health Check API
jobs.push(health_check_api::start_job(config).await);
jobs.push(health_check_api::start_job(&config.health_check_api, registar.entries()).await);

jobs
}
12 changes: 6 additions & 6 deletions src/bootstrap/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use crate::shared::crypto::ephemeral_instance_keys;

/// It loads the configuration from the environment and builds the main domain [`Tracker`] struct.
#[must_use]
pub fn setup() -> (Arc<Configuration>, Arc<Tracker>) {
let configuration = Arc::new(initialize_configuration());
pub fn setup() -> (Configuration, Arc<Tracker>) {
let configuration = initialize_configuration();
let tracker = initialize_with_configuration(&configuration);

(configuration, tracker)
Expand All @@ -35,7 +35,7 @@ pub fn setup() -> (Arc<Configuration>, Arc<Tracker>) {
///
/// The configuration may be obtained from the environment (via config file or env vars).
#[must_use]
pub fn initialize_with_configuration(configuration: &Arc<Configuration>) -> Arc<Tracker> {
pub fn initialize_with_configuration(configuration: &Configuration) -> Arc<Tracker> {
initialize_static();
initialize_logging(configuration);
Arc::new(initialize_tracker(configuration))
Expand All @@ -60,13 +60,13 @@ pub fn initialize_static() {
/// The tracker is the domain layer service. It's the entrypoint to make requests to the domain layer.
/// It's used by other higher-level components like the UDP and HTTP trackers or the tracker API.
#[must_use]
pub fn initialize_tracker(config: &Arc<Configuration>) -> Tracker {
tracker_factory(config.clone())
pub fn initialize_tracker(config: &Configuration) -> Tracker {
tracker_factory(config)
}

/// It initializes the log level, format and channel.
///
/// See [the logging setup](crate::bootstrap::logging::setup) for more info about logging.
pub fn initialize_logging(config: &Arc<Configuration>) {
pub fn initialize_logging(config: &Configuration) {
bootstrap::logging::setup(config);
}
12 changes: 7 additions & 5 deletions src/bootstrap/jobs/health_check_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@
//!
//! Refer to the [configuration documentation](https://docs.rs/torrust-tracker-configuration)
//! for the API configuration options.
use std::sync::Arc;
use log::info;
use tokio::sync::oneshot;
use tokio::task::JoinHandle;
use torrust_tracker_configuration::Configuration;
use torrust_tracker_configuration::HealthCheckApi;

use super::Started;
use crate::servers::health_check_api::server;
use crate::servers::registar::ServiceRegistry;
use crate::servers::signals::Halted;

/// This function starts a new Health Check API server with the provided
/// configuration.
Expand All @@ -33,20 +34,21 @@ use crate::servers::health_check_api::server;
/// # Panics
///
/// It would panic if unable to send the `ApiServerJobStarted` notice.
pub async fn start_job(config: Arc<Configuration>) -> JoinHandle<()> {
pub async fn start_job(config: &HealthCheckApi, register: ServiceRegistry) -> JoinHandle<()> {
let bind_addr = config
.health_check_api
.bind_address
.parse::<std::net::SocketAddr>()
.expect("it should have a valid health check bind address");

let (tx_start, rx_start) = oneshot::channel::<Started>();
let (tx_halt, rx_halt) = tokio::sync::oneshot::channel::<Halted>();
drop(tx_halt);

// Run the API server
let join_handle = tokio::spawn(async move {
info!(target: "Health Check API", "Starting on: http://{}", bind_addr);

let handle = server::start(bind_addr, tx_start, config.clone());
let handle = server::start(bind_addr, tx_start, rx_halt, register);

if let Ok(()) = handle.await {
info!(target: "Health Check API", "Stopped server running on: http://{}", bind_addr);
Expand Down
22 changes: 17 additions & 5 deletions src/bootstrap/jobs/http_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use super::make_rust_tls;
use crate::core;
use crate::servers::http::server::{HttpServer, Launcher};
use crate::servers::http::Version;
use crate::servers::registar::ServiceRegistrationForm;

/// It starts a new HTTP server with the provided configuration and version.
///
Expand All @@ -32,7 +33,12 @@ use crate::servers::http::Version;
///
/// It would panic if the `config::HttpTracker` struct would contain inappropriate values.
///
pub async fn start_job(config: &HttpTracker, tracker: Arc<core::Tracker>, version: Version) -> Option<JoinHandle<()>> {
pub async fn start_job(
config: &HttpTracker,
tracker: Arc<core::Tracker>,
form: ServiceRegistrationForm,
version: Version,
) -> Option<JoinHandle<()>> {
if config.enabled {
let socket = config
.bind_address
Expand All @@ -44,17 +50,22 @@ pub async fn start_job(config: &HttpTracker, tracker: Arc<core::Tracker>, versio
.map(|tls| tls.expect("it should have a valid http tracker tls configuration"));

match version {
Version::V1 => Some(start_v1(socket, tls, tracker.clone()).await),
Version::V1 => Some(start_v1(socket, tls, tracker.clone(), form).await),
}
} else {
info!("Note: Not loading Http Tracker Service, Not Enabled in Configuration.");
None
}
}

async fn start_v1(socket: SocketAddr, tls: Option<RustlsConfig>, tracker: Arc<core::Tracker>) -> JoinHandle<()> {
async fn start_v1(
socket: SocketAddr,
tls: Option<RustlsConfig>,
tracker: Arc<core::Tracker>,
form: ServiceRegistrationForm,
) -> JoinHandle<()> {
let server = HttpServer::new(Launcher::new(socket, tls))
.start(tracker)
.start(tracker, form)
.await
.expect("it should be able to start to the http tracker");

Expand All @@ -80,6 +91,7 @@ mod tests {
use crate::bootstrap::app::initialize_with_configuration;
use crate::bootstrap::jobs::http_tracker::start_job;
use crate::servers::http::Version;
use crate::servers::registar::Registar;

#[tokio::test]
async fn it_should_start_http_tracker() {
Expand All @@ -88,7 +100,7 @@ mod tests {
let tracker = initialize_with_configuration(&cfg);
let version = Version::V1;

start_job(config, tracker, version)
start_job(config, tracker, Registar::default().give_form(), version)
.await
.expect("it should be able to join to the http tracker start-job");
}
Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/jobs/torrent_cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::core;
///
/// Refer to [`torrust-tracker-configuration documentation`](https://docs.rs/torrust-tracker-configuration) for more info about that option.
#[must_use]
pub fn start_job(config: &Arc<Configuration>, tracker: &Arc<core::Tracker>) -> JoinHandle<()> {
pub fn start_job(config: &Configuration, tracker: &Arc<core::Tracker>) -> JoinHandle<()> {
let weak_tracker = std::sync::Arc::downgrade(tracker);
let interval = config.inactive_peer_cleanup_interval;

Expand Down
27 changes: 21 additions & 6 deletions src/bootstrap/jobs/tracker_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ use std::sync::Arc;
use axum_server::tls_rustls::RustlsConfig;
use log::info;
use tokio::task::JoinHandle;
use torrust_tracker_configuration::HttpApi;
use torrust_tracker_configuration::{AccessTokens, HttpApi};

use super::make_rust_tls;
use crate::core;
use crate::servers::apis::server::{ApiServer, Launcher};
use crate::servers::apis::Version;
use crate::servers::registar::ServiceRegistrationForm;

/// This is the message that the "launcher" spawned task sends to the main
/// application process to notify the API server was successfully started.
Expand All @@ -53,7 +54,12 @@ pub struct ApiServerJobStarted();
/// It would panic if unable to send the `ApiServerJobStarted` notice.
///
///
pub async fn start_job(config: &HttpApi, tracker: Arc<core::Tracker>, version: Version) -> Option<JoinHandle<()>> {
pub async fn start_job(
config: &HttpApi,
tracker: Arc<core::Tracker>,
form: ServiceRegistrationForm,
version: Version,
) -> Option<JoinHandle<()>> {
if config.enabled {
let bind_to = config
.bind_address
Expand All @@ -64,18 +70,26 @@ pub async fn start_job(config: &HttpApi, tracker: Arc<core::Tracker>, version: V
.await
.map(|tls| tls.expect("it should have a valid tracker api tls configuration"));

let access_tokens = Arc::new(config.access_tokens.clone());

match version {
Version::V1 => Some(start_v1(bind_to, tls, tracker.clone()).await),
Version::V1 => Some(start_v1(bind_to, tls, tracker.clone(), form, access_tokens).await),
}
} else {
info!("Note: Not loading Http Tracker Service, Not Enabled in Configuration.");
None
}
}

async fn start_v1(socket: SocketAddr, tls: Option<RustlsConfig>, tracker: Arc<core::Tracker>) -> JoinHandle<()> {
async fn start_v1(
socket: SocketAddr,
tls: Option<RustlsConfig>,
tracker: Arc<core::Tracker>,
form: ServiceRegistrationForm,
access_tokens: Arc<AccessTokens>,
) -> JoinHandle<()> {
let server = ApiServer::new(Launcher::new(socket, tls))
.start(tracker)
.start(tracker, form, access_tokens)
.await
.expect("it should be able to start to the tracker api");

Expand All @@ -94,6 +108,7 @@ mod tests {
use crate::bootstrap::app::initialize_with_configuration;
use crate::bootstrap::jobs::tracker_apis::start_job;
use crate::servers::apis::Version;
use crate::servers::registar::Registar;

#[tokio::test]
async fn it_should_start_http_tracker() {
Expand All @@ -102,7 +117,7 @@ mod tests {
let tracker = initialize_with_configuration(&cfg);
let version = Version::V1;

start_job(config, tracker, version)
start_job(config, tracker, Registar::default().give_form(), version)
.await
.expect("it should be able to join to the tracker api start-job");
}
Expand Down
5 changes: 3 additions & 2 deletions src/bootstrap/jobs/udp_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use tokio::task::JoinHandle;
use torrust_tracker_configuration::UdpTracker;

use crate::core;
use crate::servers::registar::ServiceRegistrationForm;
use crate::servers::udp::server::{Launcher, UdpServer};

/// It starts a new UDP server with the provided configuration.
Expand All @@ -25,14 +26,14 @@ use crate::servers::udp::server::{Launcher, UdpServer};
/// It will panic if it is unable to start the UDP service.
/// It will panic if the task did not finish successfully.
#[must_use]
pub async fn start_job(config: &UdpTracker, tracker: Arc<core::Tracker>) -> JoinHandle<()> {
pub async fn start_job(config: &UdpTracker, tracker: Arc<core::Tracker>, form: ServiceRegistrationForm) -> JoinHandle<()> {
let bind_to = config
.bind_address
.parse::<std::net::SocketAddr>()
.expect("it should have a valid udp tracker bind address");

let server = UdpServer::new(Launcher::new(bind_to))
.start(tracker)
.start(tracker, form)
.await
.expect("it should be able to start the udp tracker");

Expand Down
Loading

0 comments on commit 203ce96

Please sign in to comment.