Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract Config from Tracker and Heath Check #623

Merged
merged 3 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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