From f5d68b4d782cbd92241e61ba181152143a925575 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Sun, 18 Jun 2023 17:55:37 +0000 Subject: [PATCH] add api secret create / delete methods --- Cargo.lock | 9 +- Cargo.toml | 2 +- core/src/auth/github/mod.rs | 4 +- core/src/auth/google/client.rs | 11 +-- core/src/auth/jwt.rs | 15 ++-- core/src/auth/local.rs | 2 + core/src/auth/mod.rs | 6 +- core/src/auth/secret.rs | 1 + core/src/helpers.rs | 14 ++++ core/src/main.rs | 9 +- core/src/requests/{api.rs => api/mod.rs} | 5 +- core/src/requests/api/secret.rs | 82 +++++++++++++++++++ core/src/requests/auth.rs | 6 +- lib/rs_client/src/lib.rs | 35 ++++++-- lib/types/src/entities/server/docker_image.rs | 12 +-- lib/types/src/entities/user.rs | 20 +++-- lib/types/src/lib.rs | 2 +- lib/types/src/requests/api.rs | 32 ++++++++ lib/types/src/requests/auth.rs | 2 - lib/types/src/requests/mod.rs | 1 - periphery/src/main.rs | 2 +- periphery/src/requests/build.rs | 4 +- periphery/src/requests/container.rs | 27 +++--- periphery/src/requests/git.rs | 5 +- periphery/src/requests/mod.rs | 9 +- periphery/src/requests/network.rs | 10 ++- periphery/src/requests/stats.rs | 16 ++-- tests/Cargo.toml | 3 +- tests/src/core.rs | 11 +++ tests/src/main.rs | 47 +---------- tests/src/periphery.rs | 49 +++++++++++ 31 files changed, 328 insertions(+), 125 deletions(-) create mode 100644 core/src/helpers.rs rename core/src/requests/{api.rs => api/mod.rs} (76%) create mode 100644 core/src/requests/api/secret.rs create mode 100644 tests/src/core.rs create mode 100644 tests/src/periphery.rs diff --git a/Cargo.lock b/Cargo.lock index 72a373047..39c83140b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1924,9 +1924,9 @@ dependencies = [ [[package]] name = "resolver_api" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ec3e46f747f873a3aac9612d4599cae1d7600df5a5db106b5bca28ab734369" +checksum = "2a4c612fa902830ac9b906bacbe800e0cb34968ff913a1aef29b16b65a8c6781" dependencies = [ "anyhow", "async-trait", @@ -1937,9 +1937,9 @@ dependencies = [ [[package]] name = "resolver_api_derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce9be59c8b5b836bc5d2e87a1bd3309b9fb6b4b4e1c414cf8039a7fb110496df" +checksum = "c9be9792e0b0154c7764feb2ee95dd2427d4db012715bb8320a5f0e53368c558" dependencies = [ "proc-macro2", "quote", @@ -2494,6 +2494,7 @@ name = "tests" version = "0.1.0" dependencies = [ "anyhow", + "dotenv", "make_option", "monitor_client", "monitor_types", diff --git a/Cargo.toml b/Cargo.toml index f2afb7216..d948ef63f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ termination_signal = "0.1.2" async_timing_util = "0.1.14" partial_derive2 = "0.1.4" make_option = "0.1.3" -resolver_api = "0.1.4" +resolver_api = "0.1.5" parse_csl = "0.1.0" mungos = "0.4.2" svi = "0.1.4" diff --git a/core/src/auth/github/mod.rs b/core/src/auth/github/mod.rs index 175b09a4f..affdede55 100644 --- a/core/src/auth/github/mod.rs +++ b/core/src/auth/github/mod.rs @@ -1,11 +1,11 @@ use anyhow::{anyhow, Context}; use async_timing_util::unix_timestamp_ms; -use axum::{extract::Query, response::Redirect, routing::get, Router, http::StatusCode}; +use axum::{extract::Query, http::StatusCode, response::Redirect, routing::get, Router}; use monitor_types::entities::user::User; use mungos::mongodb::bson::doc; use serde::Deserialize; -use crate::{state::StateExtension}; +use crate::state::StateExtension; pub mod client; diff --git a/core/src/auth/google/client.rs b/core/src/auth/google/client.rs index 474efa7be..298da0f8e 100644 --- a/core/src/auth/google/client.rs +++ b/core/src/auth/google/client.rs @@ -18,11 +18,12 @@ pub struct GoogleOauthClient { } impl GoogleOauthClient { - pub fn new(CoreConfig { google_oauth, host, .. }: &CoreConfig) -> Option { - if google_oauth.enabled - && !google_oauth.id.is_empty() - && !google_oauth.secret.is_empty() - { + pub fn new( + CoreConfig { + google_oauth, host, .. + }: &CoreConfig, + ) -> Option { + if google_oauth.enabled && !google_oauth.id.is_empty() && !google_oauth.secret.is_empty() { GoogleOauthClient { http: Default::default(), client_id: google_oauth.id.clone(), diff --git a/core/src/auth/jwt.rs b/core/src/auth/jwt.rs index 88e00c6a5..1e16f372e 100644 --- a/core/src/auth/jwt.rs +++ b/core/src/auth/jwt.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, sync::Arc}; use anyhow::{anyhow, Context}; use async_timing_util::{get_timelength_in_ms, unix_timestamp_ms, Timelength}; -use axum::{body::Body, http::Request}; +use axum::{body::Body, http::Request, Extension}; use hmac::{Hmac, Mac}; use jwt::{SignWithKey, VerifyWithKey}; use serde::{Deserialize, Serialize}; @@ -15,8 +15,11 @@ use super::random_string; type ExchangeTokenMap = Mutex>; +pub type RequestUser = Arc; +pub type RequestUserExtension = Extension; + #[derive(Default)] -pub struct RequestUser { +pub struct InnerRequestUser { pub id: String, pub is_admin: bool, pub create_server_permissions: bool, @@ -92,7 +95,7 @@ impl State { pub async fn authenticate_check_enabled( &self, req: &Request, - ) -> anyhow::Result> { + ) -> anyhow::Result { let jwt = req .headers() .get("authorization") @@ -106,7 +109,7 @@ impl State { .auth_jwt_check_enabled(&jwt) .await .context("failed to authenticate jwt")?; - Ok(Arc::new(user)) + Ok(user.into()) } pub async fn auth_jwt_check_enabled(&self, jwt: &str) -> anyhow::Result { @@ -121,13 +124,13 @@ impl State { .await? .ok_or(anyhow!("did not find user with id {}", claims.id))?; if user.enabled { - let user = RequestUser { + let user = InnerRequestUser { id: claims.id, is_admin: user.admin, create_server_permissions: user.create_server_permissions, create_build_permissions: user.create_build_permissions, }; - Ok(user) + Ok(user.into()) } else { Err(anyhow!("user not enabled")) } diff --git a/core/src/auth/local.rs b/core/src/auth/local.rs index ed52facd2..b25fcf43b 100644 --- a/core/src/auth/local.rs +++ b/core/src/auth/local.rs @@ -19,6 +19,7 @@ impl Resolve for State { async fn resolve( &self, CreateLocalUser { username, password }: CreateLocalUser, + _: (), ) -> anyhow::Result { if !self.config.local_auth { return Err(anyhow!("local auth is not enabled")); @@ -63,6 +64,7 @@ impl Resolve for State { async fn resolve( &self, LoginLocalUser { username, password }: LoginLocalUser, + _: (), ) -> anyhow::Result { if !self.config.local_auth { return Err(anyhow!("local auth is not enabled")); diff --git a/core/src/auth/mod.rs b/core/src/auth/mod.rs index 1602386c8..106d208cc 100644 --- a/core/src/auth/mod.rs +++ b/core/src/auth/mod.rs @@ -20,7 +20,7 @@ use crate::{ state::{State, StateExtension}, }; -pub use self::jwt::JwtClient; +pub use self::jwt::{JwtClient, RequestUser, RequestUserExtension}; pub use github::client::GithubOauthClient; pub use google::client::GoogleOauthClient; @@ -49,7 +49,7 @@ pub fn router(state: &State) -> Router { let req_id = Uuid::new_v4(); info!("/auth request {req_id} | {request:?}"); let res = state - .resolve_request(request) + .resolve_request(request, ()) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("{e:?}"))); if let Err(e) = &res { @@ -75,7 +75,7 @@ pub fn router(state: &State) -> Router { router } -fn random_string(length: usize) -> String { +pub fn random_string(length: usize) -> String { thread_rng() .sample_iter(&Alphanumeric) .take(length) diff --git a/core/src/auth/secret.rs b/core/src/auth/secret.rs index e21c7dd6b..e8b5e2f3f 100644 --- a/core/src/auth/secret.rs +++ b/core/src/auth/secret.rs @@ -15,6 +15,7 @@ impl Resolve for State { async fn resolve( &self, LoginWithSecret { username, secret }: LoginWithSecret, + _: (), ) -> anyhow::Result { let user = self .db diff --git a/core/src/helpers.rs b/core/src/helpers.rs new file mode 100644 index 000000000..be25623da --- /dev/null +++ b/core/src/helpers.rs @@ -0,0 +1,14 @@ +use anyhow::Context; +use monitor_types::entities::user::User; + +use crate::state::State; + +impl State { + pub async fn get_user(&self, user_id: &str) -> anyhow::Result { + self.db + .users + .find_one_by_id(user_id) + .await? + .context(format!("no user exists with id {user_id}")) + } +} diff --git a/core/src/main.rs b/core/src/main.rs index 70a063ec0..d5279fd6d 100644 --- a/core/src/main.rs +++ b/core/src/main.rs @@ -3,7 +3,7 @@ extern crate log; use std::time::Instant; -use auth::auth_request; +use auth::{auth_request, RequestUserExtension}; use axum::{ headers::ContentType, http::StatusCode, middleware, routing::post, Extension, Json, Router, TypedHeader, @@ -18,6 +18,7 @@ use crate::requests::api::ApiRequest; mod auth; mod config; mod db; +mod helpers; mod requests; mod state; @@ -47,12 +48,14 @@ fn api() -> Router { .route( "/", post( - |state: StateExtension, Json(request): Json| async move { + |state: StateExtension, + Extension(user): RequestUserExtension, + Json(request): Json| async move { let timer = Instant::now(); let req_id = Uuid::new_v4(); info!("/auth request {req_id} | {request:?}"); let res = state - .resolve_request(request) + .resolve_request(request, user) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("{e:?}"))); if let Err(e) = &res { diff --git a/core/src/requests/api.rs b/core/src/requests/api/mod.rs similarity index 76% rename from core/src/requests/api.rs rename to core/src/requests/api/mod.rs index 28840eab7..6277ee4ec 100644 --- a/core/src/requests/api.rs +++ b/core/src/requests/api/mod.rs @@ -1,10 +1,13 @@ use resolver_api::derive::Resolver; use serde::{Deserialize, Serialize}; -use crate::state::State; +use crate::{auth::RequestUser, state::State}; + +mod secret; #[derive(Serialize, Deserialize, Debug, Clone, Resolver)] #[resolver_target(State)] +#[resolver_args(RequestUser)] #[serde(tag = "type", content = "params")] #[allow(clippy::enum_variant_names, clippy::large_enum_variant)] pub enum ApiRequest {} diff --git a/core/src/requests/api/secret.rs b/core/src/requests/api/secret.rs new file mode 100644 index 000000000..fe030f7a5 --- /dev/null +++ b/core/src/requests/api/secret.rs @@ -0,0 +1,82 @@ +use anyhow::{anyhow, Context}; +use async_timing_util::unix_timestamp_ms; +use async_trait::async_trait; +use monitor_types::{ + entities::user::ApiSecret, + requests::api::{CreateLoginSecret, CreateLoginSecretResponse, DeleteLoginSecret}, +}; +use mungos::{ + mongodb::bson::{doc, to_bson, Document}, + Update, +}; +use resolver_api::Resolve; + +use crate::{ + auth::{random_string, RequestUser}, + state::State, +}; + +const SECRET_LENGTH: usize = 40; +const BCRYPT_COST: u32 = 10; + +#[async_trait] +impl Resolve for State { + async fn resolve( + &self, + secret: CreateLoginSecret, + user: RequestUser, + ) -> anyhow::Result { + let user = self.get_user(&user.id).await?; + for s in &user.secrets { + if s.name == secret.name { + return Err(anyhow!("secret with name {} already exists", secret.name)); + } + } + let secret_str = random_string(SECRET_LENGTH); + let api_secret = ApiSecret { + name: secret.name, + created_at: unix_timestamp_ms() as i64, + expires: secret.expires, + hash: bcrypt::hash(&secret_str, BCRYPT_COST) + .context("failed at hashing secret string")?, + }; + self.db + .users + .update_one::( + &user.id, + Update::Custom(doc! { + "$push": { + "secrets": to_bson(&api_secret).context("failed at converting secret to bson")? + } + }), + ) + .await + .context("failed at mongo update query")?; + Ok(CreateLoginSecretResponse { secret: secret_str }) + } +} + +#[async_trait] +impl Resolve for State { + async fn resolve( + &self, + DeleteLoginSecret { name }: DeleteLoginSecret, + user: RequestUser, + ) -> anyhow::Result<()> { + self.db + .users + .update_one::( + &user.id, + Update::Custom(doc! { + "$pull": { + "secrets": { + "name": name + } + } + }), + ) + .await + .context("failed at mongo update query")?; + Ok(()) + } +} diff --git a/core/src/requests/auth.rs b/core/src/requests/auth.rs index fe10da891..4ec161394 100644 --- a/core/src/requests/auth.rs +++ b/core/src/requests/auth.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use monitor_types::requests::auth::{ - ExchangeForJwt, ExchangeForJwtResponse, GetLoginOptions, LoginWithSecret, CreateLocalUser, LoginLocalUser, + CreateLocalUser, ExchangeForJwt, ExchangeForJwtResponse, GetLoginOptions, LoginLocalUser, + LoginWithSecret, }; use resolver_api::{derive::Resolver, Resolve, ResolveToString}; use serde::{Deserialize, Serialize}; @@ -22,7 +23,7 @@ pub enum AuthRequest { #[async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetLoginOptions) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetLoginOptions, _: ()) -> anyhow::Result { Ok(self.login_options_response.clone()) } } @@ -32,6 +33,7 @@ impl Resolve for State { async fn resolve( &self, ExchangeForJwt { token }: ExchangeForJwt, + _: (), ) -> anyhow::Result { let jwt = self.jwt.redeem_exchange_token(&token).await?; let res = ExchangeForJwtResponse { jwt }; diff --git a/lib/rs_client/src/lib.rs b/lib/rs_client/src/lib.rs index d11f44eba..50412c6d1 100644 --- a/lib/rs_client/src/lib.rs +++ b/lib/rs_client/src/lib.rs @@ -1,5 +1,7 @@ use anyhow::{anyhow, Context}; -use monitor_types::requests::auth::{self, LoginLocalUserResponse, LoginWithSecretResponse}; +use monitor_types::requests::auth::{ + self, CreateLocalUserResponse, LoginLocalUserResponse, LoginWithSecretResponse, +}; use reqwest::StatusCode; use resolver_api::HasResponse; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -7,7 +9,7 @@ use serde_json::json; #[derive(Deserialize)] struct MonitorEnv { - monitor_url: String, + monitor_address: String, monitor_token: Option, monitor_username: Option, monitor_password: Option, @@ -52,6 +54,29 @@ impl MonitorClient { Ok(client) } + pub async fn new_with_new_account( + address: impl Into, + username: impl Into, + password: impl Into, + ) -> anyhow::Result { + let mut client = MonitorClient { + reqwest: Default::default(), + address: address.into(), + jwt: Default::default(), + }; + + let CreateLocalUserResponse { jwt } = client + .auth(auth::CreateLocalUser { + username: username.into(), + password: password.into(), + }) + .await?; + + client.jwt = jwt; + + Ok(client) + } + pub async fn new_with_secret( address: impl Into, username: impl Into, @@ -79,17 +104,17 @@ impl MonitorClient { let env = envy::from_env::() .context("failed to parse environment for monitor client")?; if let Some(token) = env.monitor_token { - Ok(MonitorClient::new_with_token(&env.monitor_url, token)) + Ok(MonitorClient::new_with_token(&env.monitor_address, token)) } else if let Some(password) = env.monitor_password { let username = env.monitor_username.ok_or(anyhow!( "must provide MONITOR_USERNAME to authenticate with MONITOR_PASSWORD" ))?; - MonitorClient::new_with_password(&env.monitor_url, username, password).await + MonitorClient::new_with_password(&env.monitor_address, username, password).await } else if let Some(secret) = env.monitor_secret { let username = env.monitor_username.ok_or(anyhow!( "must provide MONITOR_USERNAME to authenticate with MONITOR_SECRET" ))?; - MonitorClient::new_with_secret(&env.monitor_url, username, secret).await + MonitorClient::new_with_secret(&env.monitor_address, username, secret).await } else { Err(anyhow!("failed to initialize monitor client from env | must provide one of: (MONITOR_TOKEN), (MONITOR_USERNAME and MONITOR_PASSWORD), (MONITOR_USERNAME and MONITOR_SECRET)")) } diff --git a/lib/types/src/entities/server/docker_image.rs b/lib/types/src/entities/server/docker_image.rs index 719fcb56b..f46d70ee1 100644 --- a/lib/types/src/entities/server/docker_image.rs +++ b/lib/types/src/entities/server/docker_image.rs @@ -3,6 +3,8 @@ use std::collections::HashMap; use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize}; use typeshare::typeshare; +use crate::I64; + #[typeshare] #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct ImageSummary { @@ -26,19 +28,19 @@ pub struct ImageSummary { /// Date and time at which the image was created as a Unix timestamp (number of seconds sinds EPOCH). #[serde(rename = "Created")] - pub created: i64, + pub created: I64, /// Total size of the image including all layers it is composed of. #[serde(rename = "Size")] - pub size: i64, + pub size: I64, /// Total size of image layers that are shared between this image and other images. This size is not calculated by default. `-1` indicates that the value has not been set / calculated. #[serde(rename = "SharedSize")] - pub shared_size: i64, + pub shared_size: I64, /// Total size of the image including all layers it is composed of. In versions of Docker before v1.10, this field was calculated from the image itself and all of its parent images. Docker v1.10 and up store images self-contained, and no longer use a parent-chain, making this field an equivalent of the Size field. This field is kept for backward compatibility, but may be removed in a future version of the API. #[serde(rename = "VirtualSize")] - pub virtual_size: i64, + pub virtual_size: I64, /// User-defined key/value metadata. #[serde(rename = "Labels")] @@ -47,7 +49,7 @@ pub struct ImageSummary { /// Number of containers using this image. Includes both stopped and running containers. This size is not calculated by default, and depends on which API endpoint is used. `-1` indicates that the value has not been set / calculated. #[serde(rename = "Containers")] - pub containers: i64, + pub containers: I64, } fn deserialize_nonoptional_vec<'de, D: Deserializer<'de>, T: DeserializeOwned>( diff --git a/lib/types/src/entities/user.rs b/lib/types/src/entities/user.rs index ce267110d..cd6b0c36a 100644 --- a/lib/types/src/entities/user.rs +++ b/lib/types/src/entities/user.rs @@ -1,8 +1,10 @@ use bson::serde_helpers::hex_string_as_object_id; use mungos::MungosIndexed; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use typeshare::typeshare; +use crate::I64; + #[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Default, MungosIndexed)] pub struct User { @@ -14,11 +16,11 @@ pub struct User { )] pub id: String, - #[unique_index] + #[unique_index] pub username: String, #[serde(default)] - #[index] + #[index] pub enabled: bool, #[serde(default)] @@ -42,10 +44,10 @@ pub struct User { pub google_id: Option, #[serde(default, skip_serializing_if = "i64_is_zero")] - pub created_at: i64, + pub created_at: I64, #[serde(default)] - pub updated_at: i64, + pub updated_at: I64, } #[typeshare] @@ -54,10 +56,10 @@ pub struct ApiSecret { pub name: String, #[serde(default, skip_serializing_if = "String::is_empty")] pub hash: String, - pub created_at: String, - pub expires: Option, + pub created_at: I64, + pub expires: Option, } -fn i64_is_zero(n: &i64) -> bool { +fn i64_is_zero(n: &I64) -> bool { *n == 0 -} \ No newline at end of file +} diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index 484952a99..bdc3b8660 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -1,7 +1,7 @@ use typeshare::typeshare; -pub mod requests; pub mod entities; +pub mod requests; #[typeshare(serialized_as = "number")] pub type I64 = i64; diff --git a/lib/types/src/requests/api.rs b/lib/types/src/requests/api.rs index e69de29bb..883f0474b 100644 --- a/lib/types/src/requests/api.rs +++ b/lib/types/src/requests/api.rs @@ -0,0 +1,32 @@ +use resolver_api::derive::Request; +use serde::{Deserialize, Serialize}; +use typeshare::typeshare; + +use crate::I64; + +// + +#[typeshare] +#[derive(Serialize, Deserialize, Debug, Clone, Request)] +#[response(CreateLoginSecretResponse)] +pub struct CreateLoginSecret { + pub name: String, + pub expires: Option, +} + +#[typeshare] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct CreateLoginSecretResponse { + pub secret: String, +} + +// + +#[typeshare] +#[derive(Serialize, Deserialize, Debug, Clone, Request)] +#[response(())] +pub struct DeleteLoginSecret { + pub name: String, +} + +// diff --git a/lib/types/src/requests/auth.rs b/lib/types/src/requests/auth.rs index 88abfb1ff..7918d66c3 100644 --- a/lib/types/src/requests/auth.rs +++ b/lib/types/src/requests/auth.rs @@ -81,5 +81,3 @@ pub struct LoginWithSecretResponse { } // - - diff --git a/lib/types/src/requests/mod.rs b/lib/types/src/requests/mod.rs index 4665b77cb..1f85274d0 100644 --- a/lib/types/src/requests/mod.rs +++ b/lib/types/src/requests/mod.rs @@ -1,3 +1,2 @@ pub mod api; pub mod auth; - diff --git a/periphery/src/main.rs b/periphery/src/main.rs index f1867f050..84b02d63f 100644 --- a/periphery/src/main.rs +++ b/periphery/src/main.rs @@ -37,7 +37,7 @@ async fn app() -> anyhow::Result<()> { let req_id = Uuid::new_v4(); info!("request {req_id} | {request:?}"); let res = state - .resolve_request(request) + .resolve_request(request, ()) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("{e:?}"))); if let Err(e) = &res { diff --git a/periphery/src/requests/build.rs b/periphery/src/requests/build.rs index 7776eb573..5474eab06 100644 --- a/periphery/src/requests/build.rs +++ b/periphery/src/requests/build.rs @@ -14,7 +14,7 @@ pub struct Build { #[async_trait] impl Resolve for State { - async fn resolve(&self, Build { build }: Build) -> anyhow::Result> { + async fn resolve(&self, Build { build }: Build, _: ()) -> anyhow::Result> { let secrets = self.secrets.clone(); let repo_dir = self.config.repo_dir.clone(); let log = match self.get_docker_token(&optional_string(&build.config.docker_account)) { @@ -38,7 +38,7 @@ pub struct PruneImages {} #[async_trait] impl Resolve for State { - async fn resolve(&self, _: PruneImages) -> anyhow::Result { + async fn resolve(&self, _: PruneImages, _: ()) -> anyhow::Result { Ok(docker::prune_images().await) } } diff --git a/periphery/src/requests/container.rs b/periphery/src/requests/container.rs index 09e2b9a58..31f072c05 100644 --- a/periphery/src/requests/container.rs +++ b/periphery/src/requests/container.rs @@ -18,7 +18,7 @@ pub struct GetContainerList {} #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, _: GetContainerList) -> anyhow::Result> { + async fn resolve(&self, _: GetContainerList, _: ()) -> anyhow::Result> { self.docker.list_containers().await } } @@ -39,7 +39,7 @@ fn default_tail() -> u64 { #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, req: GetContainerLog) -> anyhow::Result { + async fn resolve(&self, req: GetContainerLog, _: ()) -> anyhow::Result { Ok(docker::container_log(&req.name, req.tail).await) } } @@ -54,7 +54,7 @@ pub struct GetContainerStats { #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, req: GetContainerStats) -> anyhow::Result { + async fn resolve(&self, req: GetContainerStats, _: ()) -> anyhow::Result { let error = anyhow!("no stats matching {}", req.name); let mut stats = docker::container_stats(Some(req.name)).await?; let stats = stats.pop().ok_or(error)?; @@ -70,7 +70,11 @@ pub struct GetContainerStatsList {} #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, _: GetContainerStatsList) -> anyhow::Result> { + async fn resolve( + &self, + _: GetContainerStatsList, + _: (), + ) -> anyhow::Result> { docker::container_stats(None).await } } @@ -83,7 +87,7 @@ pub struct GetNetworkList {} #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, _: GetNetworkList) -> anyhow::Result> { + async fn resolve(&self, _: GetNetworkList, _: ()) -> anyhow::Result> { self.docker.list_networks().await } } @@ -96,7 +100,7 @@ pub struct GetImageList {} #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, _: GetImageList) -> anyhow::Result> { + async fn resolve(&self, _: GetImageList, _: ()) -> anyhow::Result> { self.docker.list_images().await } } @@ -111,7 +115,7 @@ pub struct StartContainer { #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, req: StartContainer) -> anyhow::Result { + async fn resolve(&self, req: StartContainer, _: ()) -> anyhow::Result { Ok(docker::start_container(&req.name).await) } } @@ -128,7 +132,7 @@ pub struct StopContainer { #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, req: StopContainer) -> anyhow::Result { + async fn resolve(&self, req: StopContainer, _: ()) -> anyhow::Result { Ok(docker::stop_container(&req.name, req.signal, req.time).await) } } @@ -145,7 +149,7 @@ pub struct RemoveContainer { #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, req: RemoveContainer) -> anyhow::Result { + async fn resolve(&self, req: RemoveContainer, _: ()) -> anyhow::Result { Ok(docker::stop_and_remove_container(&req.name, req.signal, req.time).await) } } @@ -161,7 +165,7 @@ pub struct RenameContainer { #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, req: RenameContainer) -> anyhow::Result { + async fn resolve(&self, req: RenameContainer, _: ()) -> anyhow::Result { Ok(docker::rename_container(&req.curr_name, &req.new_name).await) } } @@ -174,7 +178,7 @@ pub struct PruneContainers {} #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, _: PruneContainers) -> anyhow::Result { + async fn resolve(&self, _: PruneContainers, _: ()) -> anyhow::Result { Ok(docker::prune_containers().await) } } @@ -198,6 +202,7 @@ impl Resolve for State { stop_signal, stop_time, }: Deploy, + _: (), ) -> anyhow::Result { let secrets = self.secrets.clone(); let log = match self.get_docker_token(&optional_string(&deployment.config.docker_account)) { diff --git a/periphery/src/requests/git.rs b/periphery/src/requests/git.rs index 2040c4def..249050f7e 100644 --- a/periphery/src/requests/git.rs +++ b/periphery/src/requests/git.rs @@ -13,7 +13,7 @@ pub struct CloneRepo { #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, CloneRepo { args }: CloneRepo) -> anyhow::Result> { + async fn resolve(&self, CloneRepo { args }: CloneRepo, _: ()) -> anyhow::Result> { let access_token = self.get_github_token(&args.github_account)?; git::clone_repo(args, self.config.repo_dir.clone(), access_token).await } @@ -38,6 +38,7 @@ impl Resolve for State { branch, on_pull, }: PullRepo, + _: (), ) -> anyhow::Result> { let name = to_monitor_name(&name); Ok(git::pull(self.config.repo_dir.join(name), &branch, &on_pull).await) @@ -54,7 +55,7 @@ pub struct DeleteRepo { #[async_trait::async_trait] impl Resolve for State { - async fn resolve(&self, DeleteRepo { name }: DeleteRepo) -> anyhow::Result { + async fn resolve(&self, DeleteRepo { name }: DeleteRepo, _: ()) -> anyhow::Result { let name = to_monitor_name(&name); let deleted = std::fs::remove_dir_all(self.config.repo_dir.join(&name)); let msg = match deleted { diff --git a/periphery/src/requests/mod.rs b/periphery/src/requests/mod.rs index 73f605ff2..232520e2a 100644 --- a/periphery/src/requests/mod.rs +++ b/periphery/src/requests/mod.rs @@ -87,7 +87,7 @@ pub struct GetHealthResponse {} #[async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetHealth) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetHealth, _: ()) -> anyhow::Result { Ok(String::from("{}")) } } @@ -105,7 +105,7 @@ pub struct GetVersionResponse { #[async_trait] impl Resolve for State { - async fn resolve(&self, _: GetVersion) -> anyhow::Result { + async fn resolve(&self, _: GetVersion, _: ()) -> anyhow::Result { Ok(GetVersionResponse { version: env!("CARGO_PKG_VERSION").to_string(), }) @@ -126,7 +126,7 @@ pub struct GetAccountsResponse { #[async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetAccounts) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetAccounts, _: ()) -> anyhow::Result { Ok(self.accounts_response.clone()) } } @@ -139,7 +139,7 @@ pub struct GetSecrets {} #[async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetSecrets) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetSecrets, _: ()) -> anyhow::Result { Ok(self.secrets_response.clone()) } } @@ -157,6 +157,7 @@ impl Resolve for State { RunCommand { command: SystemCommand { path, command }, }: RunCommand, + _: (), ) -> anyhow::Result { tokio::spawn(async move { let command = if path.is_empty() { diff --git a/periphery/src/requests/network.rs b/periphery/src/requests/network.rs index 6db3c32fe..5691fbf9c 100644 --- a/periphery/src/requests/network.rs +++ b/periphery/src/requests/network.rs @@ -16,7 +16,11 @@ pub struct CreateNetwork { #[async_trait] impl Resolve for State { - async fn resolve(&self, CreateNetwork { name, driver }: CreateNetwork) -> anyhow::Result { + async fn resolve( + &self, + CreateNetwork { name, driver }: CreateNetwork, + _: (), + ) -> anyhow::Result { Ok(docker::create_network(&name, driver).await) } } @@ -31,7 +35,7 @@ pub struct DeleteNetwork { #[async_trait] impl Resolve for State { - async fn resolve(&self, DeleteNetwork { name }: DeleteNetwork) -> anyhow::Result { + async fn resolve(&self, DeleteNetwork { name }: DeleteNetwork, _: ()) -> anyhow::Result { Ok(docker::delete_network(&name).await) } } @@ -44,7 +48,7 @@ pub struct PruneNetworks {} #[async_trait] impl Resolve for State { - async fn resolve(&self, _: PruneNetworks) -> anyhow::Result { + async fn resolve(&self, _: PruneNetworks, _: ()) -> anyhow::Result { Ok(docker::prune_networks().await) } } diff --git a/periphery/src/requests/stats.rs b/periphery/src/requests/stats.rs index 6659c606f..88fbd5974 100644 --- a/periphery/src/requests/stats.rs +++ b/periphery/src/requests/stats.rs @@ -14,7 +14,7 @@ pub struct GetSystemInformation {} #[async_trait::async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetSystemInformation) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetSystemInformation, _: ()) -> anyhow::Result { let info = &self.stats.read().await.info; serde_json::to_string(info).context("failed to serialize response to string") } @@ -28,7 +28,7 @@ pub struct GetAllSystemStats {} #[async_trait::async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetAllSystemStats) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetAllSystemStats, _: ()) -> anyhow::Result { let stats = &self.stats.read().await.stats; serde_json::to_string(stats).context("failed to serialize response to string") } @@ -42,7 +42,7 @@ pub struct GetBasicSystemStats {} #[async_trait::async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetBasicSystemStats) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetBasicSystemStats, _: ()) -> anyhow::Result { let stats = &self.stats.read().await.stats.basic; serde_json::to_string(stats).context("failed to serialize response to string") } @@ -56,7 +56,7 @@ pub struct GetCpuUsage {} #[async_trait::async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetCpuUsage) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetCpuUsage, _: ()) -> anyhow::Result { let stats = &self.stats.read().await.stats.cpu; serde_json::to_string(stats).context("failed to serialize response to string") } @@ -70,7 +70,7 @@ pub struct GetDiskUsage {} #[async_trait::async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetDiskUsage) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetDiskUsage, _: ()) -> anyhow::Result { let stats = &self.stats.read().await.stats.disk; serde_json::to_string(stats).context("failed to serialize response to string") } @@ -84,7 +84,7 @@ pub struct GetNetworkUsage {} #[async_trait::async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetNetworkUsage) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetNetworkUsage, _: ()) -> anyhow::Result { let stats = &self.stats.read().await.stats.network; serde_json::to_string(&stats).context("failed to serialize response to string") } @@ -98,7 +98,7 @@ pub struct GetSystemProcesses {} #[async_trait::async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetSystemProcesses) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetSystemProcesses, _: ()) -> anyhow::Result { let stats = &self.stats.read().await.stats.processes; serde_json::to_string(&stats).context("failed to serialize response to string") } @@ -112,7 +112,7 @@ pub struct GetSystemComponents {} #[async_trait::async_trait] impl ResolveToString for State { - async fn resolve_to_string(&self, _: GetSystemComponents) -> anyhow::Result { + async fn resolve_to_string(&self, _: GetSystemComponents, _: ()) -> anyhow::Result { let stats = &self.stats.read().await.stats.componenets; serde_json::to_string(&stats).context("failed to serialize response to string") } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index d9d91c231..4fd571f3f 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -15,4 +15,5 @@ serde.workspace = true serde_json.workspace = true partial_derive2.workspace = true make_option.workspace = true -mungos.workspace = true \ No newline at end of file +mungos.workspace = true +dotenv.workspace = true \ No newline at end of file diff --git a/tests/src/core.rs b/tests/src/core.rs new file mode 100644 index 000000000..a5bf401a2 --- /dev/null +++ b/tests/src/core.rs @@ -0,0 +1,11 @@ +use monitor_client::MonitorClient; + +#[allow(unused)] +pub async fn tests() -> anyhow::Result<()> { + dotenv::dotenv().ok(); + let monitor = + MonitorClient::new_with_new_account("http://localhost:9001", "defi moses", "jah guide") + .await?; + + Ok(()) +} diff --git a/tests/src/main.rs b/tests/src/main.rs index 6492e8eef..75f9149b1 100644 --- a/tests/src/main.rs +++ b/tests/src/main.rs @@ -1,49 +1,10 @@ -use periphery_client::{requests, PeripheryClient}; +mod core; +mod periphery; #[tokio::main] async fn main() -> anyhow::Result<()> { - let periphery = PeripheryClient::new("http://localhost:9001", "monitor_passkey"); - - let version = periphery.request(requests::GetVersion {}).await?; - println!("{version:?}"); - - let system_info = periphery.request(requests::GetSystemInformation {}).await?; - println!("{system_info:#?}"); - - let processes = periphery.request(requests::GetSystemProcesses {}).await?; - // println!("{system_stats:#?}"); - - let periphery_process = processes.into_iter().find(|p| p.name.contains("periphery")); - println!("{periphery_process:#?}"); - - let accounts = periphery.request(requests::GetAccounts {}).await?; - println!("{accounts:#?}"); - - let secrets = periphery.request(requests::GetSecrets {}).await?; - println!("{secrets:#?}"); - - let container_stats = periphery - .request(requests::GetContainerStatsList {}) - .await?; - println!("{container_stats:#?}"); - - let res = periphery.request(requests::GetNetworkList {}).await?; - println!("{res:#?}"); - - let res = periphery - .request(requests::GetContainerStats { - name: "monitor-mongo".into(), - }) - .await?; - println!("{res:#?}"); - - let res = periphery - .request(requests::GetContainerLog { - name: "monitor-mongo".into(), - tail: 50, - }) - .await?; - println!("{res:#?}"); + // periphery::tests().await?; + core::tests().await?; Ok(()) } diff --git a/tests/src/periphery.rs b/tests/src/periphery.rs new file mode 100644 index 000000000..40fbea3b3 --- /dev/null +++ b/tests/src/periphery.rs @@ -0,0 +1,49 @@ +use periphery_client::{requests, PeripheryClient}; + +#[allow(unused)] +pub async fn tests() -> anyhow::Result<()> { + let periphery = PeripheryClient::new("http://localhost:9001", "monitor_passkey"); + + let version = periphery.request(requests::GetVersion {}).await?; + println!("{version:?}"); + + let system_info = periphery.request(requests::GetSystemInformation {}).await?; + println!("{system_info:#?}"); + + let processes = periphery.request(requests::GetSystemProcesses {}).await?; + // println!("{system_stats:#?}"); + + let periphery_process = processes.into_iter().find(|p| p.name.contains("periphery")); + println!("{periphery_process:#?}"); + + let accounts = periphery.request(requests::GetAccounts {}).await?; + println!("{accounts:#?}"); + + let secrets = periphery.request(requests::GetSecrets {}).await?; + println!("{secrets:#?}"); + + let container_stats = periphery + .request(requests::GetContainerStatsList {}) + .await?; + println!("{container_stats:#?}"); + + let res = periphery.request(requests::GetNetworkList {}).await?; + println!("{res:#?}"); + + let res = periphery + .request(requests::GetContainerStats { + name: "monitor-mongo".into(), + }) + .await?; + println!("{res:#?}"); + + let res = periphery + .request(requests::GetContainerLog { + name: "monitor-mongo".into(), + tail: 50, + }) + .await?; + println!("{res:#?}"); + + Ok(()) +}