forked from github-starred/komodo
start working on core
This commit is contained in:
58
Cargo.lock
generated
58
Cargo.lock
generated
@@ -980,6 +980,12 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range-header"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.8.0"
|
||||
@@ -1292,6 +1298,16 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
@@ -1376,6 +1392,10 @@ version = "1.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
"axum",
|
||||
"dotenv",
|
||||
"envy",
|
||||
"log",
|
||||
"merge_config_files",
|
||||
"monitor_helpers",
|
||||
"monitor_types",
|
||||
@@ -1383,8 +1403,12 @@ dependencies = [
|
||||
"periphery_client",
|
||||
"resolver_api",
|
||||
"serde",
|
||||
"simple_logger",
|
||||
"termination_signal",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2601,6 +2625,31 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-range-header",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.2"
|
||||
@@ -2743,6 +2792,15 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
|
||||
@@ -14,8 +14,16 @@ monitor_helpers.workspace = true
|
||||
periphery_client.workspace = true
|
||||
# external
|
||||
tokio.workspace = true
|
||||
anyhow.workspace = true
|
||||
axum.workspace = true
|
||||
tower.workspace = true
|
||||
tower-http.workspace = true
|
||||
serde.workspace = true
|
||||
uuid.workspace = true
|
||||
anyhow.workspace = true
|
||||
log.workspace = true
|
||||
simple_logger.workspace = true
|
||||
dotenv.workspace = true
|
||||
envy.workspace = true
|
||||
# mogh
|
||||
async_timing_util.workspace = true
|
||||
merge_config_files.workspace = true
|
||||
|
||||
@@ -1 +1,172 @@
|
||||
use anyhow::Context;
|
||||
use merge_config_files::parse_config_file;
|
||||
use monitor_types::entities::Timelength;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Env {
|
||||
#[serde(default = "default_config_path")]
|
||||
pub config_path: String,
|
||||
#[serde(default = "default_frontend_path")]
|
||||
pub frontend_path: String,
|
||||
pub port: Option<u16>,
|
||||
}
|
||||
|
||||
fn default_config_path() -> String {
|
||||
"/config/config.toml".to_string()
|
||||
}
|
||||
|
||||
fn default_frontend_path() -> String {
|
||||
"/frontend".to_string()
|
||||
}
|
||||
|
||||
impl Env {
|
||||
pub fn load() -> anyhow::Result<Env> {
|
||||
dotenv::dotenv().ok();
|
||||
envy::from_env().context("failed to parse environment")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct CoreConfig {
|
||||
#[serde(default = "default_title")]
|
||||
pub title: String,
|
||||
|
||||
// the host to use with oauth redirect url, whatever host the user hits to access monitor. eg 'https://monitor.mogh.tech'
|
||||
pub host: String,
|
||||
|
||||
// port the core web server runs on
|
||||
#[serde(default = "default_core_port")]
|
||||
pub port: u16,
|
||||
|
||||
pub jwt_secret: String,
|
||||
|
||||
#[serde(default = "default_jwt_valid_for")]
|
||||
pub jwt_valid_for: Timelength,
|
||||
|
||||
// interval at which to collect server stats and alert for out of bounds
|
||||
pub monitoring_interval: Timelength,
|
||||
|
||||
// daily utc offset in hours to run daily update. eg 8:00 eastern time is 13:00 UTC, so offset should be 13. default of 0 runs at UTC midnight.
|
||||
#[serde(default)]
|
||||
pub daily_offset_hours: u8,
|
||||
|
||||
// number of days to keep stats, or 0 to disable pruning. stats older than this number of days are deleted on a daily cycle
|
||||
#[serde(default)]
|
||||
pub keep_stats_for_days: u64,
|
||||
|
||||
// used to verify validity from github webhooks
|
||||
pub github_webhook_secret: String,
|
||||
|
||||
// used to form the frontend listener url, if None will use 'host'.
|
||||
pub github_webhook_base_url: Option<String>,
|
||||
|
||||
// sent in auth header with req to periphery
|
||||
pub passkey: String,
|
||||
|
||||
// integration with slack app
|
||||
pub slack_url: Option<String>,
|
||||
|
||||
// enable login with local auth
|
||||
pub local_auth: bool,
|
||||
|
||||
#[serde(default = "default_log_level")]
|
||||
pub log_level: LogLevel,
|
||||
|
||||
// allowed docker orgs used with monitor. first in this list will be default for build
|
||||
#[serde(default)]
|
||||
pub docker_organizations: Vec<String>,
|
||||
|
||||
pub mongo: MongoConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub github_oauth: OauthCredentials,
|
||||
|
||||
#[serde(default)]
|
||||
pub google_oauth: OauthCredentials,
|
||||
|
||||
#[serde(default)]
|
||||
pub aws: AwsCredentials,
|
||||
}
|
||||
|
||||
fn default_title() -> String {
|
||||
String::from("monitor")
|
||||
}
|
||||
|
||||
fn default_core_port() -> u16 {
|
||||
9000
|
||||
}
|
||||
|
||||
fn default_jwt_valid_for() -> Timelength {
|
||||
Timelength::OneWeek
|
||||
}
|
||||
|
||||
fn default_log_level() -> LogLevel {
|
||||
LogLevel::Info
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct OauthCredentials {
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
pub id: String,
|
||||
#[serde(default)]
|
||||
pub secret: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct MongoConfig {
|
||||
pub uri: String,
|
||||
#[serde(default = "default_core_mongo_app_name")]
|
||||
pub app_name: String,
|
||||
#[serde(default = "default_core_mongo_db_name")]
|
||||
pub db_name: String,
|
||||
}
|
||||
|
||||
fn default_core_mongo_app_name() -> String {
|
||||
"monitor_core".to_string()
|
||||
}
|
||||
|
||||
fn default_core_mongo_db_name() -> String {
|
||||
"monitor".to_string()
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct AwsCredentials {
|
||||
#[serde(skip_serializing)]
|
||||
pub access_key_id: String,
|
||||
#[serde(skip_serializing)]
|
||||
pub secret_access_key: String,
|
||||
}
|
||||
|
||||
impl CoreConfig {
|
||||
pub fn load(config_path: &str) -> CoreConfig {
|
||||
parse_config_file::<CoreConfig>(config_path)
|
||||
.unwrap_or_else(|e| panic!("failed at parsing config at {config_path} | {e:#?}"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Copy)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum LogLevel {
|
||||
Off,
|
||||
Error,
|
||||
Warn,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
}
|
||||
|
||||
impl From<LogLevel> for log::LevelFilter {
|
||||
fn from(value: LogLevel) -> Self {
|
||||
match value {
|
||||
LogLevel::Off => log::LevelFilter::Off,
|
||||
LogLevel::Error => log::LevelFilter::Error,
|
||||
LogLevel::Warn => log::LevelFilter::Warn,
|
||||
LogLevel::Info => log::LevelFilter::Info,
|
||||
LogLevel::Debug => log::LevelFilter::Debug,
|
||||
LogLevel::Trace => log::LevelFilter::Trace,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,58 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use std::{sync::Arc, time::Instant};
|
||||
|
||||
use axum::{
|
||||
headers::ContentType, http::StatusCode, routing::post, Extension, Json, Router, TypedHeader,
|
||||
};
|
||||
use termination_signal::tokio::immediate_term_handle;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::requests::CoreRequest;
|
||||
|
||||
mod config;
|
||||
mod resolvers;
|
||||
mod requests;
|
||||
mod state;
|
||||
|
||||
async fn app() -> anyhow::Result<()> {
|
||||
let state = state::State::load().await?;
|
||||
|
||||
info!("version: v{}", env!("CARGO_PKG_VERSION"));
|
||||
|
||||
let socket_addr = state.socket_addr()?;
|
||||
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/api",
|
||||
post(
|
||||
|state: Extension<Arc<state::State>>, Json(request): Json<CoreRequest>| async move {
|
||||
let timer = Instant::now();
|
||||
let req_id = Uuid::new_v4();
|
||||
info!("request {req_id} | {request:?}");
|
||||
let res = state
|
||||
.resolve_request(request)
|
||||
.await
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("{e:?}")));
|
||||
if let Err(e) = &res {
|
||||
debug!("request {req_id} ERROR: {e:?}");
|
||||
}
|
||||
let res = res?;
|
||||
let elapsed = timer.elapsed();
|
||||
info!("request {req_id} | resolve time: {elapsed:?}");
|
||||
debug!("request {req_id} RESPONSE: {res}");
|
||||
Result::<_, (StatusCode, String)>::Ok((TypedHeader(ContentType::json()), res))
|
||||
},
|
||||
),
|
||||
)
|
||||
.layer(Extension(state));
|
||||
|
||||
info!("starting server on {}", socket_addr);
|
||||
|
||||
axum::Server::bind(&socket_addr)
|
||||
.serve(app.into_make_service())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -6,4 +6,5 @@ use crate::state::State;
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Resolver)]
|
||||
#[serde(tag = "type", content = "params")]
|
||||
#[resolver_target(State)]
|
||||
#[allow(clippy::enum_variant_names, clippy::large_enum_variant)]
|
||||
pub enum CoreRequest {}
|
||||
@@ -1,11 +1,35 @@
|
||||
use std::sync::Arc;
|
||||
use std::{sync::Arc, net::SocketAddr, str::FromStr};
|
||||
|
||||
pub struct State {}
|
||||
use anyhow::Context;
|
||||
use simple_logger::SimpleLogger;
|
||||
|
||||
use crate::config::{CoreConfig, Env};
|
||||
|
||||
pub struct State {
|
||||
pub env: Env,
|
||||
pub config: CoreConfig,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub async fn load() -> anyhow::Result<Arc<State>> {
|
||||
let state = State {};
|
||||
let env = Env::load()?;
|
||||
let config = CoreConfig::load(&env.config_path);
|
||||
|
||||
SimpleLogger::new()
|
||||
.with_level(config.log_level.into())
|
||||
.env()
|
||||
.with_colors(true)
|
||||
.with_utc_timestamps()
|
||||
.init()
|
||||
.context("failed to configure logger")?;
|
||||
|
||||
let state = State { env, config };
|
||||
|
||||
Ok(state.into())
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> anyhow::Result<SocketAddr> {
|
||||
SocketAddr::from_str(&format!("0.0.0.0:{}", self.config.port))
|
||||
.context("failed to parse socket addr")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
|
||||
Reference in New Issue
Block a user